I'm trying a thing that iterates over the fields of a struct
and does a different action according to the type of the field:
const std = @import("std");
const S = struct {
letter: u8,
number: u64,
};
pub fn main() void {
var result: i64 = 0;
var s = S{ .letter = 'a', .number = 77 };
inline for ([_][]const u8{ "letter", "number" }) |fname| {
var v = @field(s, fname);
switch (@TypeOf(v)) {
u8 => result += 1,
u64 => result += 2,
else => unreachable,
}
}
std.debug.print("result={}\n", .{result});
}
My question is: will the field differentiation logic (the switch
) happen at comptime
?, i.e. will the actual compile program be similar to
result += 1;
result += 2;
-- or will it be more like
const type1 = u8;
switch (type1) {
u8 => result += 1,
u64 => result += 2,
else => unreachable,
}
const type2 = u64;
switch (type2) {
u8 => result += 1,
u64 => result += 2,
else => unreachable,
}
I was assuming these switches were unnecessary since everything required to compute these things are known at compile time, but apparently the switch
is being evaluated, because if I declare S.number
to be u32
, for example, the execution panics at the unreachable
.
If that is the case, how can I rewrite this to make it more performant?
Yes, but not because of the
inline for
, it's because the thing you're switching on iscomptime
only, atype
. That means the entire switch will be replaced by whichever branch was hit at comptime, theinline for
just lets you do this more than once.So if we deconstruct it step by step (as the compiler would do) it might look something like this:
Step 1:
Step 2:
Step 3:
You can see this when you inspect the assembly code generated, even in debug mode it's just equivalent to:
Also, recommendation for iterating over a type's fields is to use either
@typeInfo(T).Struct.fields
, orstd.meta.fields
like this: