Recursion, loops, and tables
The compiler executes a complete subset of the language: arithmetic, control flow, and method calls on arrays and strings. This means that recursion and loops work normally inside comptime contexts.
Recursion
A @comptime fn can call itself. The compiler evaluates the recursion down to
the base case and bakes the result as a literal. The runtime never sees the
call stack — only the final number.
Comptime Fibonacci: fib(10) and fib(15) baked directly into the binary.
// Feature: comptime recursion — a `@comptime fn` calling itself
// Syntax: same as above; recursion is fine, but you must terminate.
// When to use: classic precomputed sequences (Fibonacci, factorials,
// CRC tables) — the runtime sees only the final number.
@comptime
fn fib(n: int) -> int {
if n <= 1 { return n }
return fib(n - 1) + fib(n - 2)
}
let f10 = comptime fib(10)
print(f10)
// expected: 55
let f15 = comptime fib(15)
print(f15)
// expected: 610
Loops
A for inside comptime { ... } runs entirely in the compiler. Gauss's sum
from 1 to 100 is a classic example: the answer is always 5050 and there is no
reason to compute it at runtime.
Comptime loop: sums 1..=100 in the compiler, the program receives the literal 5050.
// Feature: comptime loops — a `for` inside a comptime block
// Syntax: any control flow is fair game; the block runs in the
// compiler. The tail expression is the value baked in.
// When to use: precomputed sums, lookup tables, anything where the
// answer is known at build time and you want the binary to ship a
// literal instead of a loop.
// Gauss sum 1..=100, computed at build time.
let total = comptime {
var s = 0
for i in 1..=100 {
s = s + i
}
s
}
print(total)
// expected: 5050
Lookup tables
The same pattern serves to generate literal arrays — tables of squares,
primes, CRC values, palettes. Build the array inside the block, end it as a
tail expression, and the compiler emits [1, 4, 9, 16, 25, ...] directly into
the binary.
Array of squares from 1 to 5 generated at compile time.
// Feature: comptime arrays — emit a literal `[v1, v2, ...]`
// Syntax: build the array inside `comptime { ... }`, end with the
// array as the tail expression. The runtime sees a baked literal.
// When to use: lookup tables (squares, primes, lookup-by-index
// for hot paths), CRC tables, palette tables.
let squares = comptime {
var out = []
for n in 1..=5 {
out = out.push(n * n)
}
out
}
print(squares[0]) // expected: 1
print(squares[1]) // expected: 4
print(squares[2]) // expected: 9
print(squares[3]) // expected: 16
print(squares[4]) // expected: 25
Challenge
Adapt the table example to generate the first 10 multiples of 7 and access
squares[9] to confirm the result.