i want to be able to create to different structs like above, but without having to assign { } to the “unused” fields. if i give the optional field a defualt value, i have to give it to all the cases.
so basically, i want to be able to decide at comptime, if a struct has a field or not. If it has a field, i want it to require me to assign it at struct creation. If it has no field, i dont want to have to assign { } to the empty field.
This would be easy if Zig lazily evaluated default values:
// NOTE: not a working solution
fn A(comptime has_field: bool) type {
return struct {
field: if (has_field) i32 else void = if (has_field)
@compileError("must provide default") else void{},
};
}
pub fn main() void {
const a = A(false){};
std.debug.print("a: {any}\n", .{a});
// Compile error: "must provide default", despite providing value.
// This would compile if Zig didn't evaluate the default value unless it had to.
const b = A(true){ .field = 21 };
std.debug.print("b: {any}\n", .{b});
}
I don’t know if this is something that Zig could/should do.
Anyway you may want to consider biting the bullet and just initializing the field to void, but here’s a hacky solution just for fun:
// Create two different `new` functions to wrap the initialization,
// and use `usingnamespace` to decide which definition to declare.
// (I don't really recommend doing this).
fn B(comptime has_field: bool) type {
return struct {
const Self = @This();
foo: if (has_field) i32 else void,
bar: u8,
usingnamespace if (has_field) struct {
fn new(foo: i32, bar: u8) Self {
return .{ .foo = foo, .bar = bar };
}
} else struct {
fn new(bar: u8) Self {
return .{ .foo = {}, .bar = bar };
}
};
};
}
pub fn main() void {
const a = B(false).new(255);
std.debug.print("a: {any}\n", .{a});
const b = B(true).new(-10, 0);
std.debug.print("b: {any}\n", .{b});
}
thanks for all the suggestions, i think @chung-leong solution looks most ideal.
but, what if i wanted to have struct funtions aswell, where would i put them?
Then you’re kinda screwed, since @Type() can’t add decls to a struct. There is no solution I can think of.
In my opinion, a void field should have an implicit default value of {}. That’s the only possible value so why make end-users specify it? The language already treats void differently (we don’t need to capture it when it’s returned by a function).