# Safety Checks

### Safety Checks

Zig inserts safety checks for operations that are valid only under certain conditions. These checks are present in safe build modes. They catch mistakes at the point where the mistake happens.

Array indexing is checked.

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

pub fn main() void {
    const a = [_]u8{ 1, 2, 3 };

    std.debug.print("{d}\n", .{a[3]});
}
```

The array has indexes `0`, `1`, and `2`. Index `3` is outside the array.

In Debug mode, this is a panic.

```text
panic: index out of bounds
```

Arithmetic overflow is checked.

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

pub fn main() void {
    var x: u8 = 255;
    x += 1;

    std.debug.print("{d}\n", .{x});
}
```

The value `256` cannot fit in `u8`.

In a safe build mode, this is a panic.

```text
panic: integer overflow
```

Use wrapping arithmetic when wrapping is the intended operation.

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

pub fn main() void {
    var x: u8 = 255;
    x +%= 1;

    std.debug.print("{d}\n", .{x});
}
```

The result is:

```text
0
```

Unwrapping an optional is checked.

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

pub fn main() void {
    const x: ?u32 = null;

    std.debug.print("{d}\n", .{x.?});
}
```

The expression:

```zig
x.?
```

means: take the value inside the optional.

If the optional is `null`, there is no value to take. In a safe build mode, this is a panic.

Use `if` to handle the null case.

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

pub fn main() void {
    const x: ?u32 = null;

    if (x) |value| {
        std.debug.print("{d}\n", .{value});
    } else {
        std.debug.print("no value\n", .{});
    }
}
```

Error unions are also checked when forced.

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

fn fail() !u32 {
    return error.Failed;
}

pub fn main() void {
    const value = fail() catch unreachable;

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

The word `unreachable` tells the compiler that control cannot reach this point.

If it is reached in a safe mode, Zig panics.

```text
panic: reached unreachable code
```

Use `try`, `catch`, or an explicit branch to handle the error.

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

fn fail() !u32 {
    return error.Failed;
}

pub fn main() void {
    const value = fail() catch |err| {
        std.debug.print("error: {}\n", .{err});
        return;
    };

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

Alignment is checked when asserted.

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

pub fn main() void {
    var bytes = [_]u8{ 1, 2, 3, 4, 5 };

    const p: *u32 = @ptrCast(@alignCast(&bytes[1]));

    std.debug.print("{d}\n", .{p.*});
}
```

The address of `bytes[1]` may not be aligned for `u32`.

`@alignCast` asserts that the pointer has the required alignment. If the assertion is false in a safe build mode, the program panics.

Safety checks are not a substitute for correct code. They are a way to make wrong code fail close to the source of the error.

The programmer still chooses the operation.

Checked addition:

```zig
x += 1;
```

Wrapping addition:

```zig
x +%= 1;
```

Checked optional unwrap:

```zig
const y = x.?;
```

Handled optional:

```zig
if (x) |y| {
    // use y
}
```

Unchecked assumption:

```zig
unreachable
```

Handled error:

```zig
const y = f() catch |err| {
    // handle err
};
```

A useful habit is to write the program first in Debug mode. Let the checks find bad indexes, bad unwraps, overflow, wrong alignment, and false assumptions.

Then decide which checks must remain in the released program.

The build mode controls this.

| Mode | Safety checks | Main use |
|---|---|---|
| Debug | On | Development |
| ReleaseSafe | On | Safer optimized builds |
| ReleaseFast | Mostly off | Speed |
| ReleaseSmall | Mostly off | Size |

The exact cost of a check depends on the operation and the target. Some checks compile away when the compiler can prove they are unnecessary.

For example:

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

pub fn main() void {
    const a = [_]u8{ 10, 20, 30 };

    for (a) |x| {
        std.debug.print("{d}\n", .{x});
    }
}
```

The loop ranges over the array itself. There is no separate index that can go out of bounds.

This form gives the compiler more information and gives the programmer fewer ways to make an indexing mistake.

Safety in Zig is mostly explicit. The language checks the sharp edges, but it does not remove them.

Exercise 19-5. Write a program that unwraps a null optional with `.?`, then rewrite it with `if`.

Exercise 19-6. Write a program that reaches `unreachable`, then rewrite it to handle the case normally.

Exercise 19-7. Compare `+` and `+%` on `u8` values near `255`.

Exercise 19-8. Rewrite an index-based loop as a direct `for` loop over the array.

