Precomputed Data

One use of comptime is precomputing data for constants.

Let’s say we want to precompute a multiplication table:

const std = @import("std");
const print = std.debug.print;

pub fn main() void {
    print("{} * {} = {}\n", .{ 3, 7, table[3][7] });
}

// If we initialize a global variable from a function,
// that function will run at compile time.
const table = multiplicationTable();

fn multiplicationTable() [10][10]u64 {
    var result: [10][10]u64 = undefined;
    for (0..10) |row| {
        for (0..10) |col| {
            result[row][col] = row * col;
        }
    }
    return result;
}
$ zig run precomputed.zig 
3 * 7 = 21

The size of the table is hard-coded in the version above. Because multiplicationTable is only called at compile time, we can make it an argument instead:

const std = @import("std");
const print = std.debug.print;

pub fn main() void {
    print("{} * {} = {}\n", .{ 3, 7, table[3][7] });
}

// The type of 'table' is still [10][10]u64.
const table = multiplicationTable(10);

// 'n' has to be known at compile time because it’s used
// to determine the function’s return type.
fn multiplicationTable(comptime n: u64) [n][n]u64 {
    var result: [n][n]u64 = undefined;
    for (0..n) |row| {
        for (0..n) |col| {
            result[row][col] = row * col;
        }
    }
    return result;
}
$ zig run precomputed-2.zig 
3 * 7 = 21

Next example: Generic Functions.