# What Is `comptime`

### What Is `comptime`

`comptime` means “compile time.”

In Zig, some code runs while your program is being compiled. That code does not run later when the final program starts. It runs earlier, inside the compiler, while Zig is checking and building your program.

This is one of Zig’s most important features.

Most languages have a sharp split:

You write source code.

The compiler turns it into a program.

The program runs later.

Zig keeps that basic model, but it also lets you execute normal Zig code during compilation. That means you can compute values, check rules, choose types, generate code patterns, and build generic functions before runtime.

#### Runtime vs Compile Time

Runtime means the time when the program is running.

Compile time means the time when the compiler is building the program.

Here is a runtime value:

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

pub fn main() void {
    const x = 10 + 20;
    std.debug.print("{}\n", .{x});
}
```

The expression `10 + 20` is simple, so the compiler may optimize it. But conceptually, this value belongs to the program.

Now compare this:

```zig
const x = comptime 10 + 20;
```

This says: calculate this value during compilation.

The result is still `30`, but Zig knows that `x` is a compile-time value.

#### A First Example

Suppose we want a function that returns the length of an array.

```zig
fn length(comptime n: usize) usize {
    return n;
}
```

The parameter `n` is marked `comptime`.

That means the caller must pass a value known during compilation:

```zig
const size = length(8);
```

Here, `8` is known immediately. The compiler can run `length(8)` while compiling the program.

This is useful because some parts of Zig require compile-time values. Array lengths, types, and many code-shaping decisions must be known before the program runs.

#### Types Are Compile-Time Values

In Zig, types are values too.

That may feel strange at first. In many languages, types are only part of the compiler’s internal system. In Zig, you can pass a type to a function at compile time.

Example:

```zig
fn zero(comptime T: type) T {
    return 0;
}
```

This function takes a type called `T`, then returns a zero value of that type.

```zig
const a = zero(i32);
const b = zero(u64);
```

For `a`, `T` is `i32`.

For `b`, `T` is `u64`.

The compiler creates the right version of the function based on the type you passed.

This is the foundation of Zig generics.

#### Generic Functions

A generic function is a function that works with more than one type.

Here is a simple example:

```zig
fn add(comptime T: type, a: T, b: T) T {
    return a + b;
}
```

This function accepts a type `T`, then accepts two values of that type.

```zig
const x = add(i32, 10, 20);
const y = add(f64, 1.5, 2.5);
```

The first call works with `i32`.

The second call works with `f64`.

There is no separate template language. There is no macro syntax. Zig uses ordinary Zig code, with compile-time parameters.

#### `comptime` Makes Code Explicit

Zig does not want hidden magic.

If something must be known at compile time, Zig usually makes that visible.

This function says clearly that `T` is a compile-time argument:

```zig
fn makeDefault(comptime T: type) T {
    return switch (T) {
        bool => false,
        i32 => 0,
        u8 => 0,
        else => @compileError("unsupported type"),
    };
}
```

Now the compiler can check the type and choose the correct branch while building the program.

```zig
const a = makeDefault(bool);
const b = makeDefault(i32);
```

But this will fail:

```zig
const c = makeDefault([]u8);
```

The compiler reaches this branch:

```zig
else => @compileError("unsupported type"),
```

So the program does not compile.

This is powerful. You can reject bad code before it becomes a running program.

#### Compile-Time Errors

`@compileError` stops compilation with a custom error message.

Example:

```zig
fn onlySmall(comptime n: usize) void {
    if (n > 10) {
        @compileError("n must be 10 or smaller");
    }
}
```

This call is allowed:

```zig
onlySmall(5);
```

This call fails during compilation:

```zig
onlySmall(20);
```

The program never runs. The compiler rejects it first.

This is useful when you are writing libraries. You can make illegal use impossible, or at least make it fail with a clear message.

#### Compile-Time Branching

A normal `if` runs at runtime when its condition depends on runtime data.

But if the condition is known at compile time, Zig can choose the branch while compiling.

```zig
fn printTypeName(comptime T: type) void {
    if (T == i32) {
        @compileLog("i32");
    } else if (T == bool) {
        @compileLog("bool");
    } else {
        @compileLog("other");
    }
}
```

Here, `T` is known at compile time. So the compiler can decide which branch applies.

This is not like runtime polymorphism. There is no object, no virtual table, and no dynamic lookup. The compiler knows the answer early.

#### Compile-Time Loops

Zig can also run loops at compile time.

```zig
fn sum(comptime values: []const u32) u32 {
    var total: u32 = 0;

    for (values) |value| {
        total += value;
    }

    return total;
}
```

If `values` is known at compile time, the compiler can evaluate the loop while compiling.

```zig
const result = sum(&.{ 1, 2, 3, 4 });
```

The result is `10`, and it is known before the program runs.

#### `inline for`

Zig also has `inline for`, which expands loop iterations at compile time.

Example:

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

pub fn main() void {
    inline for (.{ i32, u8, bool }) |T| {
        std.debug.print("{s}\n", .{@typeName(T)});
    }
}
```

The loop is unrolled by the compiler. Each iteration gets its own compile-time type value.

This is useful when writing generic code that needs to inspect several types.

#### Why Zig Uses `comptime`

Zig uses `comptime` instead of adding many separate language features.

In other languages, you may find:

macros

templates

generics

reflection

conditional compilation

build-time code generation

Zig handles many of these jobs with one idea: run normal Zig code at compile time.

That gives the language a smaller core. You do not need to learn a separate macro language. You use Zig itself.

#### What `comptime` Is Good For

`comptime` is useful when you need to work with information known before runtime.

Common uses include:

| Use | Example |
|---|---|
| Generic functions | A function that works with `i32`, `u64`, or `f64` |
| Type selection | Choose a result type based on input types |
| Static checks | Reject unsupported types during compilation |
| Lookup tables | Build a table once at compile time |
| Code specialization | Generate fast code for a known case |
| Reflection | Inspect fields of a struct or tags of an enum |
| Configuration | Enable or disable code based on build options |

#### What `comptime` Is Not

`comptime` is not a way to make runtime data magically known early.

This does not work:

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

pub fn main() void {
    var x: usize = 10;
    const y = comptime x + 1;
    std.debug.print("{}\n", .{y});
}
```

The variable `x` is a runtime variable. Its value belongs to the running program. Zig cannot use it as a compile-time value.

To use `comptime`, the value must be known while compiling.

#### A Simple Rule

Ask this question:

Can the compiler know this value before the program runs?

If yes, it may be usable at compile time.

If no, it is runtime data.

For example:

```zig
const a = 10;
```

This can be known at compile time.

```zig
var b: usize = 10;
```

This is runtime storage, because `var` means the value can change.

```zig
const T = i32;
```

This is a compile-time type value.

```zig
const name = userInput();
```

This depends on the running program, so it cannot be compile-time data.

#### The Mental Model

`comptime` lets the compiler execute part of your program before the final program exists.

That sounds advanced, but the basic idea is simple:

use runtime for work that depends on real input

use compile time for work that is already known

use compile-time checks to catch mistakes early

use compile-time types to write generic code

Zig’s `comptime` is not an extra layer added on top of the language. It is part of the language’s normal way of thinking.

When you understand `comptime`, Zig starts to make much more sense.

