# `while` Loops

### `while` Loops

Programs often need to repeat work.

A program may need to:

read lines from a file

walk through items in a buffer

retry an operation

count from one number to another

keep running until the user quits

In Zig, one basic way to repeat work is with `while`.

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

pub fn main() void {
    var i: u8 = 0;

    while (i < 5) {
        std.debug.print("i = {}\n", .{i});
        i += 1;
    }
}
```

This prints:

```text
i = 0
i = 1
i = 2
i = 3
i = 4
```

The loop starts with `i = 0`.

Before each round, Zig checks:

```zig
i < 5
```

If the condition is true, the loop body runs.

After the body runs, `i += 1` increases `i`.

When `i` becomes `5`, the condition becomes false, and the loop stops.

#### The Basic Shape

The basic shape of `while` is:

```zig
while (condition) {
    // repeated code
}
```

The condition must be a boolean.

This is valid:

```zig
while (i < 10) {
    i += 1;
}
```

This is invalid:

```zig
while (i) {
    // invalid
}
```

Zig does not treat integers as booleans. Write the condition explicitly:

```zig
while (i != 0) {
    i -= 1;
}
```

This strictness is useful. It prevents unclear code.

#### A Loop Needs Progress

A `while` loop must eventually make progress, unless you intentionally want an infinite loop.

This loop stops:

```zig
var i: u8 = 0;

while (i < 3) {
    std.debug.print("{}\n", .{i});
    i += 1;
}
```

This loop never stops:

```zig
var i: u8 = 0;

while (i < 3) {
    std.debug.print("{}\n", .{i});
}
```

The value of `i` never changes, so `i < 3` is always true.

This is one of the most common beginner mistakes with loops: forgetting to update the variable that controls the loop.

#### The Continue Expression

Zig has a useful form of `while` with a continue expression.

```zig
var i: u8 = 0;

while (i < 5) : (i += 1) {
    std.debug.print("i = {}\n", .{i});
}
```

This prints:

```text
i = 0
i = 1
i = 2
i = 3
i = 4
```

The part after the colon is:

```zig
: (i += 1)
```

This runs after each loop body.

So this:

```zig
while (i < 5) : (i += 1) {
    std.debug.print("i = {}\n", .{i});
}
```

means:

check `i < 5`

run the body

run `i += 1`

repeat

This keeps the loop update close to the loop condition.

#### `continue`

The `continue` statement skips the rest of the current loop body and moves to the next round.

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

pub fn main() void {
    var i: u8 = 0;

    while (i < 6) : (i += 1) {
        if (i == 3) {
            continue;
        }

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

This prints:

```text
0
1
2
4
5
```

When `i` is `3`, the loop reaches:

```zig
continue;
```

That skips the print statement.

Because this loop has a continue expression, `i += 1` still runs before the next condition check.

#### `break`

The `break` statement exits the loop immediately.

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

pub fn main() void {
    var i: u8 = 0;

    while (i < 10) : (i += 1) {
        if (i == 4) {
            break;
        }

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

This prints:

```text
0
1
2
3
```

When `i` becomes `4`, the loop stops.

`break` is useful when the loop condition alone does not describe every reason to stop.

#### Infinite Loops

Sometimes a program should run until something inside the loop stops it.

Use `while (true)` for this.

```zig
var count: u8 = 0;

while (true) {
    if (count == 3) {
        break;
    }

    std.debug.print("count = {}\n", .{count});
    count += 1;
}
```

This prints:

```text
count = 0
count = 1
count = 2
```

The condition `true` never becomes false. The loop stops only because of `break`.

This pattern is common in servers, command loops, interpreters, and programs that read input until the input ends.

#### `while` Can Return a Value

Like `if` and `switch`, `while` can be an expression.

A `while` expression may have an `else` branch.

The `else` branch runs when the loop condition becomes false naturally.

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

pub fn main() void {
    var i: u8 = 0;

    const result = while (i < 3) : (i += 1) {
        std.debug.print("i = {}\n", .{i});
    } else "finished";

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

This prints:

```text
i = 0
i = 1
i = 2
finished
```

Here, the loop ends because `i < 3` becomes false. Then the `else` branch produces `"finished"`.

For beginners, this form is less common than a normal loop. But it shows an important Zig idea: control flow constructs can be expressions.

#### `while` with `break` Value

A loop can produce a value through `break`.

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

pub fn main() void {
    var i: u8 = 0;

    const found = while (i < 10) : (i += 1) {
        if (i == 4) {
            break true;
        }
    } else false;

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

This prints:

```text
found = true
```

Read it this way:

search while `i < 10`

if `i == 4`, stop the loop and return `true`

if the loop finishes normally, return `false`

This is useful for search logic.

#### `while` with Optionals

Zig can use `while` to unwrap optional values.

An optional value either contains a value or is `null`.

```zig
const maybe_number: ?u32 = 10;
```

The type `?u32` means: either a `u32`, or `null`.

Here is a simple optional loop:

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

fn nextNumber(i: *u8) ?u8 {
    if (i.* >= 3) return null;

    const value = i.*;
    i.* += 1;
    return value;
}

pub fn main() void {
    var i: u8 = 0;

    while (nextNumber(&i)) |n| {
        std.debug.print("n = {}\n", .{n});
    }
}
```

This prints:

```text
n = 0
n = 1
n = 2
```

The line:

```zig
while (nextNumber(&i)) |n| {
```

means:

call `nextNumber(&i)`

if it returns a value, name that value `n`

run the loop body

if it returns `null`, stop the loop

This pattern is useful when reading items one at a time until there are no more items.

#### `while` with Error Unions

`while` can also work with error unions.

Suppose a function returns either a value or an error:

```zig
fn readByte() !u8 {
    // may return a byte or an error
}
```

You can handle successful values and errors separately.

A simple example:

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

const ReadError = error{
    End,
};

fn next(i: *u8) ReadError!u8 {
    if (i.* >= 3) return error.End;

    const value = i.*;
    i.* += 1;
    return value;
}

pub fn main() void {
    var i: u8 = 0;

    while (next(&i)) |value| {
        std.debug.print("value = {}\n", .{value});
    } else |err| {
        std.debug.print("stopped with error: {}\n", .{err});
    }
}
```

This prints:

```text
value = 0
value = 1
value = 2
stopped with error: error.End
```

The loop continues while `next(&i)` returns a successful value.

When `next(&i)` returns an error, the loop stops and the `else` branch receives the error.

#### `while` vs `for`

Use `while` when the loop depends on a condition.

```zig
while (bytes_read < total) {
    // keep reading
}
```

Use `while` when you do not know exactly how many times the loop will run.

```zig
while (try readLine()) |line| {
    // process line
}
```

Use `for` when you already have a collection and want to visit each item.

```zig
for (items) |item| {
    // use item
}
```

We will cover `for` in the next section.

#### The Main Idea

`while` repeats code while a condition is true.

The condition must be a boolean. The loop should make progress. Use `continue` to skip to the next round. Use `break` to leave the loop early.

Zig also lets `while` work with optionals, error unions, and returned values. For now, focus on the simple form:

```zig
while (condition) {
    // repeat this
}
```

That one form is enough to write many useful programs.

