Setting a field that may not exist based on comptime condition

I have a parameter struct with this definition:

        const VmRuntimeParams = struct {
            /// Base allocator for all vm allocations.
            allocator: std.mem.Allocator,

            /// Logs runtime errors.
            errorWriter: *std.Io.Writer,

            /// Used only for debugging purposes. Logs all executed opcodes and (call)stack.
            traceWriter: if (compParams.hasTraces()) *std.Io.Writer else void,

            /// Used for debugging. Logs all allocations calls and GC cycles.
            gcWriter: if (compParams.hasMemory()) *std.Io.Writer else void,
        };

And I would like to set the last two fields conditionaly:

    var vm = try Vm.init(.{
        .errorWriter = stderr,
        .allocator = genericAllocator,
        .gcWriter = if (Vm.params.hasMemory()) memoryWriterInterface else {},
        .traceWriter = if (Vm.params.hasTraces()) traceWriterInterface else {},
    });

Zig 0.15.1 will error at me telling me the two if branches don’t have the same type. How can I solve this ? Maybe there’s a simpler way ?

‘returning’ different types on a branch requires the branch condition be comptime, which it isnt because functions are not eagerly called at comptime unless explicitly asked to with the comptime keyword, or are in a context where they have to be comptime, like in the type expression of a field.

if those functions cant be called at comptime, and you cant use compParams then you can do:

if (@FieldType(Vm, "trace/gcWriter") == *std.io.Writer) \\...
1 Like

Put comptime before the function call in the initialization:

const std = @import("std");

fn extraPresent() bool {
    return false;
}

const S = struct {
    i: i32,
    extra: if (extraPresent()) u32 else void,
};

pub fn main() void {
    const s: S = .{
        .i = -10,
        .extra = if (comptime extraPresent()) 16 else {},
    };
    std.debug.print("{any}\n", .{s});
}

As @vulpesx says, Zig will only eagerly call functions at compile time if the callsite’s context requires it. In the struct declaration, that is a given, but inside of a function it’s not, so you need to force it.

1 Like