# Comptime

> Ordinary Zig, executed by the compiler.

`comptime` is Zig's answer to templates, macros, generics, reflection, and
constant folding, all with one mechanism: **run normal Zig at compile time,
where types are values.**

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

fn fibonacci(n: u32) u32 {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

// A generic function is just one that takes a `type` parameter.
fn List(comptime T: type) type {
    return struct {
        items: []T,

        pub fn first(self: @This()) ?T {
            return if (self.items.len == 0) null else self.items[0];
        }
    };
}

fn max(comptime T: type, a: T, b: T) T {
    return if (a > b) a else b;
}

test "evaluate at compile time" {
    // `comptime` forces evaluation during compilation; the binary contains
    // the answer, not the recursion.
    const small = comptime fibonacci(10);
    try expect(small == 55);
    try expect(@TypeOf(small) == u32);
}

test "the branch quota is a real limit" {
    // Comptime evaluation is capped at 1000 backwards branches so a runaway
    // computation fails the build instead of hanging the compiler.
    // fibonacci(20) blows past that; raise the ceiling deliberately.
    @setEvalBranchQuota(100_000);
    const result = comptime fibonacci(20);
    try expect(result == 6765);
}

test "types are comptime values" {
    const T = u16;
    const value: T = 300;
    try expect(@TypeOf(value) == u16);
}

test "generic data structure" {
    var backing = [_]i32{ 10, 20 };
    const list = List(i32){ .items = &backing };
    try expect(list.first().? == 10);

    // A different T produces a genuinely different type.
    try expect(List(i32) != List(u8));
}

test "generic function" {
    try expect(max(u8, 1, 2) == 2);
    try expect(max(f32, 1.5, 0.5) == 1.5);
}

test "comptime blocks can assert" {
    comptime {
        // A failed comptime assert is a compile error, not a test failure.
        std.debug.assert(@sizeOf(u32) == 4);
    }
}
```

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

## Types are values

A `type` is an ordinary comptime value. That single fact removes the need for a
separate generics language:

```zig
fn max(comptime T: type, a: T, b: T) T {
    return if (a > b) a else b;
}
```

`comptime T: type` says this parameter must be known at compile time. Each
distinct `T` produces a separately compiled function: monomorphisation, with
no special syntax.

## Generic types are functions returning types

```zig
fn List(comptime T: type) type {
    return struct { items: []T, ... };
}
```

`List(i32)` and `List(u8)` are genuinely different types. `std.ArrayList` and
`std.HashMap` are ordinary functions like this one. Nothing in the standard
library gets privileged syntax you cannot use yourself.

## The branch quota

Comptime evaluation is capped at **1000 backwards branches**, so an accidental
infinite loop fails the build instead of hanging the compiler. Real work often
exceeds it:

```zig
@setEvalBranchQuota(100_000);
const result = comptime fibonacci(20);
```

Raising it is normal; needing to raise it to something absurd is a hint that
the work belongs at runtime.

## Where it pays off

Anything computed at comptime is not in the binary as code, only as its
result. Format strings are checked against their arguments, lookup tables are
generated, and dead configuration branches disappear entirely.
