Compile flag controlled optional struct member

Hi all,
I have a feature that I want to put behind a build Option. I’ve got it set up to have the Option working, but I want to have some fields in a struct only show up when the option is enabled.
In an imaginary zig language:

const config = @import("config");

pub const SomeOpts = struct {
    enable_foo: bool =  false,
    feature_bar_values: AnotherStruct = .{},
    if (config.enable_baz) {
        feature_baz_values: BazStruct = .{},
    }
};

This doesn’t work, but is there some equivalent that I am missing. I know you can do

const SomeStruct = if (config.enable_baz) struct {
    enable_foo: bool = false,
    feature_bar_values: AnotherStruct = .{},
    feature_baz_values: BazStruct = .{},
} else struct {
    enable_foo: bool = false,
    feature_bar_values: AnotherStruct = .{},
};

However, this is redundant and not the cleanest. Are there any other methods?

Another option is to set BazStruct to void, so it doesn’t take any space.

The standard library does this for example in the GeneralPurposeAllocator:

const LargeAlloc = struct {
  bytes: []u8,
  requested_size: if (config.enable_memory_limit) usize else void,
  stack_addresses: [trace_n][stack_n]usize,
  freed: if (config.retain_metadata) bool else void,
  log2_ptr_align: if (config.never_unmap and config.retain_metadata) u8 else void,
...

Ah, that makes sense. So if it is set to void it doesn’t take any space, but it would still show up in dev tooling, correct? (i.e. autocomplete, docs). If you want to set a default value, I would assume you would have to have some thing like this:

   enable_feature_baz: if (config.enable_baz) bool else void = if (config.enable_baz) false else .{};

Almost, void is {} without the . in the front.
But you could have something like this somewhere:

const Config = if (config.enabled) struct {
    const feature:u32 = 3;
    ...
} else struct {
    const feature:void = {};
    ...
};

const example = struct {
   enable_feature_baz: @TypeOf(config.feature) = config.feature;
};

Basically putting the switching logic somewhere else and using your first version again. But I think it may be a good way to combine the two in some situations.

I think so, at least I have noticed that zls tends to pick one of the values and not always the one that is actually the right one. But I don’t really know what is going on with that in detail.

1 Like

Ah, nice one with the @TypeOf on the feature. That solves it for me. Thanks!

2 Likes