# Optional Unwrapping

### Optional Unwrapping

Optional unwrapping means taking the value out of an optional.

An optional value has this shape:

```zig
const maybe_number: ?i32 = 42;
```

The type is `?i32`, not `i32`.

That means you cannot use it directly as a normal integer:

```zig
const doubled = maybe_number * 2; // error
```

The compiler rejects this because `maybe_number` might be `null`.

Before you can use the inner value, you must unwrap it.

#### Unwrapping with `if`

The most common way to unwrap an optional is with `if`.

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

pub fn main() void {
    const maybe_number: ?i32 = 42;

    if (maybe_number) |number| {
        std.debug.print("number: {}\n", .{number});
    }
}
```

This line is the key:

```zig
if (maybe_number) |number| {
```

Read it as:

```text
If maybe_number contains a value, call that value number and run this block.
```

Inside the block, `number` is a plain `i32`.

```zig
const doubled = number * 2;
```

Outside the block, `maybe_number` is still optional.

```zig
if (maybe_number) |number| {
    // number is i32 here
}

// maybe_number is still ?i32 here
```

The unwrapped name only exists inside the block.

#### Handling the `null` Case with `else`

Most real code needs to handle both cases: value and no value.

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

pub fn main() void {
    const maybe_name: ?[]const u8 = null;

    if (maybe_name) |name| {
        std.debug.print("hello, {s}\n", .{name});
    } else {
        std.debug.print("hello, guest\n", .{});
    }
}
```

If `maybe_name` contains a string, the first block runs.

If it is `null`, the `else` block runs.

This is the safest basic pattern:

```zig
if (optional_value) |value| {
    // use value
} else {
    // handle null
}
```

#### Unwrapping with `orelse`

Use `orelse` when you want a default value.

```zig
const maybe_port: ?u16 = null;
const port = maybe_port orelse 8080;
```

Now `port` is a normal `u16`.

If `maybe_port` has a value, that value is used.

If `maybe_port` is `null`, `8080` is used.

Another example:

```zig
const maybe_name: ?[]const u8 = null;
const name = maybe_name orelse "guest";
```

This is often cleaner than writing a full `if` when the missing case has a simple default.

#### `orelse` Can Return

The right side of `orelse` does not need to be a plain value. It can also return from the current function.

```zig
fn printName(maybe_name: ?[]const u8) void {
    const name = maybe_name orelse return;

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

This means:

```text
If maybe_name has a value, store it in name.
If maybe_name is null, return from the function.
```

After this line, `name` is no longer optional.

```zig
const name = maybe_name orelse return;
// name is []const u8 here
```

This pattern is useful when a function cannot do anything useful without the value.

#### Unwrapping with `.?`

Zig also has a shorter unwrap operator:

```zig
const value = maybe_number.?;
```

This means:

```text
Take the value out of the optional.
If it is null, panic.
```

Example:

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

pub fn main() void {
    const maybe_number: ?i32 = 42;
    const number = maybe_number.?;

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

This works because `maybe_number` contains `42`.

But this will crash:

```zig
const maybe_number: ?i32 = null;
const number = maybe_number.?; // panic
```

Use `.?` only when null would be a bug, not a normal possibility.

Good use:

```zig
const value = cache.get("known_key").?;
```

This is reasonable only if the program has already guaranteed that `"known_key"` exists.

Poor use:

```zig
const user = findUser(id).?;
```

If the user may be missing in normal use, this is not good. Handle the `null` case instead.

#### Capturing a Pointer with `if`

Sometimes you want to modify the value inside an optional variable.

For that, use pointer capture.

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

pub fn main() void {
    var maybe_count: ?i32 = 10;

    if (maybe_count) |*count| {
        count.* += 1;
    }

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

This part matters:

```zig
if (maybe_count) |*count| {
```

The `*count` means “capture a pointer to the inner value.”

Inside the block, `count` is a pointer. To read or write the value, use `count.*`.

```zig
count.* += 1;
```

After the block, `maybe_count` contains `11`.

Use pointer capture when you want to mutate the value inside the optional.

#### Optional Unwrapping in `while`

You can unwrap optionals in a `while` loop too.

This is useful when a function repeatedly returns either a value or `null`.

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

fn nextNumber(index: *usize, numbers: []const i32) ?i32 {
    if (index.* >= numbers.len) {
        return null;
    }

    const value = numbers[index.*];
    index.* += 1;
    return value;
}

pub fn main() void {
    const numbers = [_]i32{ 10, 20, 30 };
    var index: usize = 0;

    while (nextNumber(&index, numbers[0..])) |number| {
        std.debug.print("{}\n", .{number});
    }
}
```

The loop runs as long as `nextNumber` returns a value.

When `nextNumber` returns `null`, the loop stops.

This pattern appears in iterators and parsers.

#### Optional Pointers

Optional pointers are common.

```zig
const maybe_ptr: ?*i32 = null;
```

Before using the pointer, unwrap it:

```zig
if (maybe_ptr) |ptr| {
    ptr.* = 123;
}
```

Inside the block, `ptr` is a normal `*i32`.

This is safer than allowing every pointer to be null. In Zig, a plain pointer like `*i32` is expected to be non-null. If null is possible, the type must say so.

```zig
*i32   // pointer to i32
?*i32  // maybe pointer to i32
```

That small `?` matters.

#### Choosing the Right Unwrapping Style

Use `if` when you need to handle both cases clearly.

```zig
if (maybe_value) |value| {
    // value case
} else {
    // null case
}
```

Use `orelse` when you want a default.

```zig
const value = maybe_value orelse default_value;
```

Use `orelse return` when the function should stop if the value is missing.

```zig
const value = maybe_value orelse return;
```

Use `.?` only when null would mean a programming mistake.

```zig
const value = maybe_value.?;
```

Do not use `.?` just to avoid writing proper handling code.

#### The Main Idea

Optional unwrapping is Zig’s way of making missing values explicit.

A value of type `?T` cannot be silently treated as `T`.

You must decide what to do:

Use the value.

Use a default.

Return early.

Handle the missing case.

Or assert that missing is impossible.

That decision is part of the program. Zig makes you write it down.

