# Inline Loops

> Unrolled loops where each iteration can differ in type.

```zig
const std = @import("std");
const expect = std.testing.expect;

test "inline for over a tuple" {
    // A tuple's elements have different types, so the loop body must be
    // compiled separately for each. That is what `inline` provides.
    const tuple = .{ @as(u8, 1), @as(f32, 2.5), true };
    var count: usize = 0;
    inline for (tuple) |value| {
        if (@TypeOf(value) == bool) count += 10 else count += 1;
    }
    try expect(count == 12);
}

test "inline for over types" {
    const types = [_]type{ u8, u16, u32 };
    var total: usize = 0;
    inline for (types) |T| {
        total += @sizeOf(T);
    }
    try expect(total == 7);
}

test "the loop variable becomes comptime-known" {
    var sum: usize = 0;
    inline for (0..4) |i| {
        // `i` is comptime here, so it can be used where a comptime value
        // is required, such as an array type's length.
        const arr: [i]u8 = undefined;
        sum += arr.len;
    }
    try expect(sum == 6); // 0 + 1 + 2 + 3
}
```

*Runnable: compiled to WebAssembly and executed by CI against Zig master. (`02-language.inline-loops`)*

`inline for` unrolls at compile time. That is occasionally about performance,
but the real reason it exists is **types**.

## Iterating heterogeneous things

A tuple's elements have different types. A normal loop body is compiled once,
so it cannot handle that. An `inline for` body is compiled separately per
iteration, so `@TypeOf(value)` can differ each time:

```zig
inline for (tuple) |value| {
    if (@TypeOf(value) == bool) { ... }
}
```

This is how `std.debug.print` walks its arguments, and how serialisation code
walks a struct's fields.

## The loop variable becomes comptime-known

Inside `inline for (0..4) |i|`, `i` is a comptime value, so it can be used
where the compiler demands one (array lengths, type construction, field
names):

```zig
const arr: [i]u8 = undefined;   // only valid because i is comptime
```

## Use it deliberately

Unrolling multiplies generated code by the iteration count. For a 3-element
tuple that is free; for `inline for (0..10000)` it is a compile-time and
binary-size disaster. Reach for `inline` when you need comptime-ness, not as a
performance reflex.
