Confundir comptime vs runtime — Como Resolver em Zig

Confundir comptime vs runtime — Como Resolver em Zig

O Que Este Erro Significa

Um dos conceitos mais poderosos e ao mesmo tempo confusos de Zig para iniciantes é a distinção entre comptime (tempo de compilação) e runtime (tempo de execução). Muitos erros ocorrem quando o programador tenta usar valores de runtime em contextos que exigem comptime, ou vice-versa. O compilador reporta esses erros com mensagens como:

error: unable to evaluate comptime expression
error: expected comptime-known value
error: runtime value used in comptime context

Em Zig, comptime permite executar código durante a compilação, gerar tipos, otimizar caminhos de código e fazer metaprogramação — mas exige que os valores sejam conhecidos antes do programa rodar.

Causas Comuns

1. Usar Variável Runtime como Tipo

const std = @import("std");

pub fn main() void {
    var tamanho: usize = 10;
    _ = &tamanho;
    // ERRO: tamanho não é comptime — não pode ser usado como tamanho de tipo
    var array: [tamanho]u8 = undefined;
    _ = array;
}

2. Valor Runtime em switch com comptime

const std = @import("std");

pub fn main() !void {
    const stdin = std.io.getStdIn().reader();
    var buf: [100]u8 = undefined;
    const input = try stdin.readUntilDelimiterOrEof(&buf, '\n');
    _ = input;

    // input é runtime — não pode ser usado em padrões comptime
    // const tipo = @TypeOf(input); // Isso funciona, mas...
}

3. Tentar Criar Tipo com Dados de Runtime

fn criarArray(tamanho: usize) void {
    // ERRO: tamanho é runtime, mas [N]T requer N comptime
    var arr: [tamanho]u8 = undefined;
    _ = arr;
}

4. @compileLog em Código Runtime

const std = @import("std");

pub fn main() void {
    var x: u32 = 42;
    _ = &x;
    @compileLog(x); // ERRO: x é runtime, @compileLog precisa de comptime
}

5. Usar inline for com Valores Runtime

pub fn main() void {
    var n: usize = 5;
    _ = &n;
    // ERRO: inline for precisa de range comptime
    inline for (0..n) |i| {
        _ = i;
    }
}

6. Retornar Tipo Diferente Baseado em Condição Runtime

fn processar(modo: bool) if (modo) u32 else i32 {
    // ERRO: modo é runtime, mas o tipo de retorno precisa ser comptime
    if (modo) return 42 else return -1;
}

Como Corrigir

Solucao 1: Marcar Parâmetro como comptime

fn criarArray(comptime tamanho: usize) [tamanho]u8 {
    return [_]u8{0} ** tamanho; // OK: tamanho é comptime
}

pub fn main() void {
    var arr = criarArray(10); // 10 é comptime — OK
    arr[0] = 42;
}

Solucao 2: Usar Alocação Dinâmica para Tamanhos Runtime

const std = @import("std");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    var tamanho: usize = 10;
    _ = &tamanho;

    // Para tamanhos runtime, use alocação dinâmica
    const buffer = try allocator.alloc(u8, tamanho);
    defer allocator.free(buffer);

    buffer[0] = 42;
}

Solucao 3: Usar comptime para Geração de Tipos

fn VetorDe(comptime T: type, comptime N: usize) type {
    return struct {
        dados: [N]T,

        const Self = @This();

        fn init() Self {
            return .{ .dados = [_]T{0} ** N };
        }

        fn get(self: *const Self, i: usize) T {
            return self.dados[i];
        }
    };
}

pub fn main() void {
    const Vec3 = VetorDe(f32, 3);
    var v = Vec3.init();
    v.dados[0] = 1.0;
    v.dados[1] = 2.0;
    v.dados[2] = 3.0;
    _ = v;
}

Solucao 4: Separar Lógica Comptime e Runtime

const std = @import("std");

// Função comptime — gera código em tempo de compilação
fn calcularFibComptime(comptime n: u32) u32 {
    if (n <= 1) return n;
    return calcularFibComptime(n - 1) + calcularFibComptime(n - 2);
}

// Função runtime — executa em tempo de execução
fn calcularFibRuntime(n: u32) u32 {
    if (n <= 1) return n;
    var a: u32 = 0;
    var b: u32 = 1;
    var i: u32 = 2;
    while (i <= n) : (i += 1) {
        const temp = a + b;
        a = b;
        b = temp;
    }
    return b;
}

pub fn main() void {
    // Comptime — resultado calculado durante compilação
    const fib_10 = comptime calcularFibComptime(10);
    std.debug.print("Fib(10) comptime: {}\n", .{fib_10});

    // Runtime — resultado calculado durante execução
    var n: u32 = 10;
    _ = &n;
    const fib_n = calcularFibRuntime(n);
    std.debug.print("Fib({}) runtime: {}\n", .{ n, fib_n });
}

Solucao 5: Usar @as para Forçar Tipo Comptime

const std = @import("std");

pub fn main() void {
    // Literal numérico é comptime
    const tamanho = 100; // comptime_int

    // @as converte para tipo concreto em comptime
    const buffer_size = @as(usize, tamanho);

    var buf: [buffer_size]u8 = undefined;
    buf[0] = 42;
    _ = buf;
}

Solucao 6: Bloco comptime para Computação em Compilação

const std = @import("std");

const tabela_lookup = comptime blk: {
    var result: [256]u8 = undefined;
    for (0..256) |i| {
        result[i] = @intCast((i * 7 + 3) % 256);
    }
    break :blk result;
};

pub fn main() void {
    // tabela_lookup é computada em tempo de compilação
    // Nenhum custo de inicialização em runtime
    std.debug.print("tabela[42] = {}\n", .{tabela_lookup[42]});
}

Comptime vs Runtime: Guia Rápido

ContextoComptimeRuntime
Tamanhos de array[N]T requer N comptimeUse alloc para runtime
TiposTipos são SEMPRE comptimeNão existe tipo runtime
Parâmetroscomptime param: Tparam: T
Condiçõesif (comptime ...) avaliado na compilaçãoif (...) avaliado na execução
Loopsinline for requer range comptimefor aceita runtime
Valoresconst x = 42 (literal) é comptimevar x: u32 = 42 é runtime

Quando Usar comptime

  1. Geração de tipos: fn MeuTipo(comptime T: type) type
  2. Tabelas de lookup: const tabela = comptime { ... }
  3. Otimização: unrolling de loops com inline for
  4. Validação: @compileError para verificar condições em compilação
  5. Metaprogramação: gerar código baseado em tipos

Quando Usar Runtime

  1. Dados do usuário: input, argumentos de CLI, variáveis de ambiente
  2. I/O: leitura de arquivos, rede
  3. Alocação dinâmica: tamanhos variáveis em runtime
  4. Estado mutável: variáveis que mudam durante execução

Erros Relacionados

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.