# Blocks are Expressions

### Blocks are Expressions

A block is a sequence of statements inside braces.

```zig
{
    const x = 1;
    const y = 2;
    _ = x + y;
}
```

Blocks are used for function bodies, `if` bodies, loop bodies, and local scopes. A name declared inside a block exists only inside that block.

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

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

    // x is not visible here
}
```

This is ordinary scoping. The inner block gives `x` a place to live. When the block ends, the name is gone.

A block can also produce a value. This is one of the important rules in Zig. A block is not only a place to put statements. It can be used as an expression.

```zig
const value = blk: {
    const a = 20;
    const b = 22;
    break :blk a + b;
};
```

The value of `value` is `42`.

The label `blk` names the block. The statement

```zig
break :blk a + b;
```

leaves the block and gives it a value.

The label can have any valid name.

```zig
const result = answer: {
    break :answer 100;
};
```

Here `result` is `100`.

This form is useful when a value needs more than one step to compute.

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

pub fn main() void {
    const n = 7;

    const kind = classify: {
        if (n == 0) break :classify "zero";
        if (n < 0) break :classify "negative";
        break :classify "positive";
    };

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

The output is:

```text
positive
```

A block expression has a type, just as every expression has a type. All exits that give a value must agree on the type.

```zig
const x = blk: {
    if (true) break :blk 1;
    break :blk 2;
};
```

Both `1` and `2` are integer values, so this is fine.

This is wrong:

```zig
const x = blk: {
    if (true) break :blk 1;
    break :blk "one";
};
```

One branch gives an integer. The other gives a string. Zig will reject it.

A block that does not give a value has type `void`.

```zig
const x = {};
```

This is legal, but `x` has type `void`, which is rarely useful as a stored value.

A block can be used to limit the lifetime of temporary names.

```zig
const area = compute: {
    const width = 8;
    const height = 5;
    break :compute width * height;
};
```

After this block, `width` and `height` are no longer visible. Only `area` remains.

This keeps programs small and local. Names should live only where they are needed.

Blocks also work well with `defer`.

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

pub fn main() void {
    {
        defer std.debug.print("leaving block\n", .{});
        std.debug.print("inside block\n", .{});
    }

    std.debug.print("after block\n", .{});
}
```

The output is:

```text
inside block
leaving block
after block
```

A `defer` statement runs when control leaves the block. It does not wait until the whole function ends unless it is declared in the outer function block.

Blocks are simple, but they are used everywhere in Zig. They give scope. They group statements. They can compute values. They also decide when deferred work runs.

Exercise 3-1. Write a block expression that sets `x` to `10 + 20`.

Exercise 3-2. Write a block expression that classifies an integer as `"small"` or `"large"`.

Exercise 3-3. Put a `defer` inside an inner block and observe when it runs.

Exercise 3-4. Try to return two different value types from one block expression and read the compiler error.

