Have a variable in a struct only in debug builds?

In C/C++ I can do something like this:

class Foo {
#ifndef NDEBUG
    bool initialized;
#endif

    void init() {
        // do stuff

        #ifndef NDEBUG
        initialized = true;
        #endif
    }

    void deinit() {
        // do stuff

        #ifndef NDEBUG
        initialized = false;
        #endif
    }

    void doSomething() {
        #ifndef NDEBUG
        assert(initialized == true && "You forgot to call init()!");
        #endif
    }
};

How do I do this in Zig? The only thing I can come up with is this:

fn Foo() type {

    if (builtin.mode == builtin.Mode.Debug) {
        return struct {
            initialized: bool = false,

            // everything else goes here
        };
    }
    else {

        return struct {
            // duplicate everything AGAIN, except without checks for "initialized"
        };
    }
}

but this means I have to have 2 copies of my struct, and 2 different sets of code to maintain.

1 Like

Would something like this work?

const Foo = struct {

    initialized: if (builtin.mode == builtin.Mode.Debug) bool else void,

    pub fn init(self: *@This()) {
       // do stuff

       if (builtin.mode == builtin.Mode.Debug) {
           self.initialized = true;
       }
    }

    // ...
};

This way at least initialized doesn’t take up any space in the struct or affect its layout in non-debug builds, right?

1 Like

Can you post your full struct code? I have some ideas but they are contextually dependent on the declarations.

Yes, this works.

Examples from the zig standard library:

  • heap.zig
    get_called: if (std.debug.runtime_safety) bool else void
  • array_hash_map.zig
    pub const Hash = if (store_hash) u32 else void;
4 Likes