Is there usingnamespace analogue for fields?

It is possible to use usingnamespace hack to conditionally include declarations into a struct based on some comptime parameters, like here:

Is there something analogues for fields?

I know that I can use

if (comptime_condition) {
    return struct { foo: i32 };
} else {
    return struct { bar: bool };
}

but that requires duplicating everything else that’s common.

I also can do something like

var fields: []StructField = []
if (comptime_condition) {
    fields = fields ++ ... ;
} else {
    fields = fields ++ ... ;
}

return @Type(.Struct = { .fields = fields });

This gets rid of duplication, at the cost of constructing the whole thing through reflection.

What I’d ideally want is something along the lines of

return struct {
    if (comptime_condition) {
        foo: i32,
    } else {
        bar: bool,
    }
}

Is this possible in today’s Zig somehow?

3 Likes

Something I’ve seen the standard library do pretty often for this type of thing would be:

const Foo = struct {
    foo: if (comptime_condition) i32 else void,
    bar: if (!comptime_condition) bool else void,
}

Here’s an example from the GPA:

(note also the @TypeOf usage in total_requested_bytes/requested_memory_limit/mutex to make the pattern slightly nicer)

5 Likes

You can do something similar with reflection and tuple concatenation:

return createStruct (
    .{"first", bool}
    ++ if (comptime_condition) {
        .{"foo", i32}
    } else {
        .{"bar", bool}
    }
    ++ .{"baz", f32}
    ++ ...
)

Where createStruct parses the tuple and creates the struct fields:

fn createStruct(comptime tuple: anytype) type {
    var fields: []StructField = []
    var i: usize = 0;
    while(i < tuple.len): (i += 2) {
        fields = fields ++ .{.name = tuple[i], .type = tuple[i+1], ...};
    }
    return @Type(.Struct = { .fields = fields });
}
3 Likes