u/zeronetdev

is there a way to force eager evaluation of a unused const on a type?
▲ 13 r/Zig

is there a way to force eager evaluation of a unused const on a type?

Hi there, sorry if this is not the correct place to ask, but with Stack Overflow kinda dead I really don't know where else to put this question.

A bit of context: I'm currently working on a library to simplify Zig-Lua interop. For that I created a marker strategy to represent the metadata of Zig structs, unions and enums that defines metatables and encoding/decoding strategies.

The problem is that it is fragile in the sense that forgetting pub on ZUA_META, or misspelling it, causes the encode/decode paths to fall back to the default strategy. That is intentional since the core idea is to allow interop with as little ceremony as possible, so small DTOs should not need any annotation. But the silent fallback causes two kinds of errors: types with non-table strategies get encoded and decoded as plain tables (the minor problem), and methods never get attached to the metatable (the major one, since Lua ends up calling nil and the error message gives no hint about what went wrong on the Zig side).

To catch this I added a comptime guard inside the metadata type constructor so that a misspelled or private ZUA_META would produce a @ compileError. It does not fire. After debugging with @ compileLog I confirmed the cause is that Zig lazily evaluates generic type instantiations, so the check never runs if the result is never actually used. I can confirm this by forcing evaluation manually:

const Vector2 = struct {
    const ZUA_META = zua.Meta.Table(Vector2, .{ .length = length });

    x: f64,
    y: f64,

    pub fn length(self: Vector2) f64 {
        _ = ZUA_META; // force evaluation
        return std.math.sqrt(self.x * self.x + self.y * self.y);
    }
};

_ = (Vector2{ .x = 0, .y = 0 }).length(); // only now the compileError fires

Is there any mechanism in Zig to force eager evaluation of a comptime block, or to guarantee a generic type instantiation is always evaluated even when its result is not directly used? I cannot require explicit registration calls because that would break the zero-ceremony DTO use case. I also cannot use a struct field with a default value because the marker needs to work for enums and unions too, not just structs.

btw here is the commit where I implemented the check that is not working: https://github.com/SolracHQ/zua/commit/ea6f4f083e795874c98d4a1ae55ca4236715fa8e

btw 2, it is a bit ironic that Zig is extremely strict about unused variables everywhere else but silently skips evaluation of unused type declarations with no warning at all. Even a warning would have saved me a lot of debugging time.

Thanks for any help.

u/zeronetdev — 5 days ago