# Labels and Block Expressions

### Labels and Block Expressions

Zig has blocks.

A block is a group of statements surrounded by braces:

```zig
{
    const x = 10;
    const y = 20;
    _ = x + y;
}
```

You have already seen blocks in `if`, `switch`, `while`, and `for`.

```zig
if (age >= 18) {
    std.debug.print("adult\n", .{});
}
```

The part inside `{}` is a block.

Most beginner code uses blocks only to group statements. Zig can do more than that. In Zig, a block can also produce a value.

#### A Block Creates a Scope

A block creates a new scope.

A scope is a region where names exist.

```zig
const std = @import("std");

pub fn main() void {
    {
        const x = 10;
        std.debug.print("x = {}\n", .{x});
    }

    // x cannot be used here
}
```

The name `x` exists only inside the inner block.

This is invalid:

```zig
pub fn main() void {
    {
        const x = 10;
    }

    std.debug.print("x = {}\n", .{x}); // error
}
```

The variable `x` is gone after the block ends.

This is useful because it lets you keep temporary names local. Small scopes make code easier to read.

#### Why Blocks Matter

A block lets you group several steps.

```zig
const area = blk: {
    const width = 10;
    const height = 20;
    break :blk width * height;
};
```

This computes an area and stores it in `area`.

The block contains temporary variables:

```zig
const width = 10;
const height = 20;
```

Then it returns a value:

```zig
break :blk width * height;
```

The final value of the block is:

```zig
200
```

So this:

```zig
const area = blk: {
    const width = 10;
    const height = 20;
    break :blk width * height;
};
```

means roughly:

```zig
const area = 200;
```

But the block allowed us to use multiple statements to compute the value.

#### Labels

A label gives a name to a block.

```zig
blk: {
    // block body
}
```

Here, the label is:

```zig
blk
```

The full shape is:

```zig
label_name: {
    // statements
}
```

A label is useful because `break` can refer to it.

```zig
const value = blk: {
    break :blk 123;
};
```

This means:

leave the block named `blk`, and make its value `123`.

#### `break` from a Block

In Zig, `break` is not only for loops. It can also leave a labeled block.

```zig
const std = @import("std");

pub fn main() void {
    const value = blk: {
        break :blk 42;
    };

    std.debug.print("value = {}\n", .{value});
}
```

This prints:

```text
value = 42
```

The important line is:

```zig
break :blk 42;
```

Read it as:

break out of the block named `blk` with the value `42`.

The type of `value` is inferred from the value returned by the block.

#### Blocks Without Values

A block does not always need to produce a value.

```zig
{
    std.debug.print("hello\n", .{});
}
```

This block is only used for grouping.

Its type is `void`.

`void` means “no useful value.”

This is also `void`:

```zig
const result = {};
```

But in normal code, you rarely write that. Most `void` blocks are used for control flow or grouping.

#### Block Expressions in `if`

Blocks become more useful when combined with `if`.

```zig
const std = @import("std");

pub fn main() void {
    const score = 82;

    const message = if (score >= 60) blk: {
        const extra = score - 60;
        break :blk if (extra >= 20) "strong pass" else "pass";
    } else blk: {
        break :blk "fail";
    };

    std.debug.print("{s}\n", .{message});
}
```

This prints:

```text
strong pass
```

Each branch uses a block to compute a value.

The first branch:

```zig
blk: {
    const extra = score - 60;
    break :blk if (extra >= 20) "strong pass" else "pass";
}
```

has a temporary variable `extra`.

The block returns either `"strong pass"` or `"pass"`.

#### Each Branch Must Return a Compatible Type

When blocks are used as values, their returned values must fit the expected type.

This is valid:

```zig
const value = blk: {
    break :blk 10;
};
```

This is also valid:

```zig
const message = if (ok) blk: {
    break :blk "yes";
} else blk: {
    break :blk "no";
};
```

Both branches return strings.

This is invalid:

```zig
const value = if (ok) blk: {
    break :blk 10;
} else blk: {
    break :blk "no";
};
```

One branch returns an integer. The other returns a string. Zig rejects this because `value` cannot have two unrelated types.

#### Labels on Loops

Labels can also be used with loops.

This matters when you have nested loops.

```zig
const std = @import("std");

pub fn main() void {
    outer: for (0..3) |i| {
        for (0..3) |j| {
            if (i == 1 and j == 1) {
                break :outer;
            }

            std.debug.print("i={}, j={}\n", .{ i, j });
        }
    }
}
```

This prints:

```text
i=0, j=0
i=0, j=1
i=0, j=2
i=1, j=0
```

The label is:

```zig
outer:
```

The line:

```zig
break :outer;
```

means:

stop the loop named `outer`.

Without the label, `break` would stop only the inner loop.

#### `continue` with Labels

Labels also work with `continue`.

```zig
const std = @import("std");

pub fn main() void {
    outer: for (0..3) |i| {
        for (0..3) |j| {
            if (j == 1) {
                continue :outer;
            }

            std.debug.print("i={}, j={}\n", .{ i, j });
        }
    }
}
```

This prints:

```text
i=0, j=0
i=1, j=0
i=2, j=0
```

When `j == 1`, this line runs:

```zig
continue :outer;
```

That skips the rest of the inner loop and moves to the next iteration of the outer loop.

This is useful, but use it carefully. Labeled `continue` can make code harder to follow if overused.

#### Choosing Label Names

For small block expressions, many Zig examples use `blk`.

```zig
const value = blk: {
    break :blk 123;
};
```

For loops, use names that explain the purpose.

```zig
search: for (items) |item| {
    // ...
}
```

```zig
rows: for (grid) |row| {
    // ...
}
```

```zig
commands: while (true) {
    // ...
}
```

A label should help the reader understand what is being exited or continued.

#### When Block Expressions Are Useful

Block expressions are useful when a value needs several steps to compute.

Instead of writing:

```zig
var result: u32 = undefined;

if (x > 10) {
    result = x * 2;
} else {
    result = x + 1;
}
```

You can write:

```zig
const result = if (x > 10) x * 2 else x + 1;
```

If the computation needs multiple statements, use blocks:

```zig
const result = if (x > 10) blk: {
    const doubled = x * 2;
    break :blk doubled;
} else blk: {
    const incremented = x + 1;
    break :blk incremented;
};
```

This keeps `result` as a `const`. That is often cleaner than creating a mutable variable and assigning it later.

#### A Practical Example

Suppose we want to classify a file size.

```zig
const std = @import("std");

pub fn main() void {
    const bytes: u64 = 2_500_000;

    const label = blk: {
        if (bytes < 1_000) {
            break :blk "small";
        }

        if (bytes < 1_000_000) {
            break :blk "medium";
        }

        break :blk "large";
    };

    std.debug.print("file is {s}\n", .{label});
}
```

This prints:

```text
file is large
```

The block allows several checks, but the final result is still a single constant:

```zig
const label = ...
```

That is a clean Zig pattern.

#### The Main Idea

A block groups statements and creates a scope.

A labeled block can also produce a value:

```zig
const value = name: {
    break :name 123;
};
```

Labels can also name loops, which lets `break` and `continue` target an outer loop.

For beginners, the most important uses are:

```zig
const result = blk: {
    const x = 10;
    const y = 20;
    break :blk x + y;
};
```

and:

```zig
outer: for (items) |item| {
    for (subitems) |subitem| {
        break :outer;
    }
}
```

Blocks and labels give Zig precise control flow without hidden behavior.

