Reflection

Reflection is the ability of a program to inspect and modify its own structure. Comptime lets us do compile-time reflection.

Let’s try to write a function that prints a struct in a more readable format than the standard print function. It’ll reflect on the type it’s given to get the struct fields.

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

const Color = struct {
    red: u8,
    green: u8,
    blue: u8,
};

pub fn main() void {
    const c: Color = .{
        .red = 255,
        .green = 0,
        .blue = 255,
    };
    printStruct("color", c);
    printStruct("my tuple", .{ 123, 4.56 });
}

// 'anytype' means the function will be specialized for
// different types.
fn printStruct(name: []const u8, v: anytype) void {
    const T = @TypeOf(v);
    print("{s}:\n", .{name});

    const type_info = @typeInfo(T);
    switch (type_info) {
        // We have to write @"struct" here because
        // 'struct' is a keyword.
        .@"struct" => |s| {
            const fields = s.fields;
            // We need 'inline for' because 'fields' is
            // only available at compile time.
            inline for (fields) |f|
                print("    {s}: {}\n", .{
                    f.name,
                    // @field gets a field by name.
                    @field(v, f.name),
                });
        },
        // @compileError raises an error during
        // compilation.
        else => @compileError("expected struct"),
    }
}
$ zig run reflection.zig 
color:
    red: 255
    green: 0
    blue: 255
my tuple:
    0: 123
    1: 4.56

Next example: Build System.