I wanted to share a little snippet of code to show zig compile time to merge two structs.
pub fn merge(comptime S: type, map1: anytype, map2: S) void {
const T = std.meta.Child(@TypeOf(map1));
const fields = comptime std.meta.fieldNames(S);
inline for (fields) |field| {
if (@hasField(T, field) and @FieldType(T, field) == @FieldType(S, field)) {
@field(map1.*, field) = @field(map2, field);
}
}
}
I came from clojure where hash-maps are heavily used to store and pass data. One issue in low level languages is that of having two types share some fields and having to manually match between fields. For example in std.build.addTest options
are almost assigned verbatim to root_module
. So I wanted to try zig compile time and it works great, Do you guys have any thoughts on how to write it better?
4 Likes
dimdin
January 15, 2025, 10:22pm
2
Runtime performance is perfect, because only the field assignments remain.
Some ideas for improvement:
It is not clear, without looking at the implementation, which argument is the source and which is the destination/target.
From the names map1
and map2
someone might expect an actual map instead of a struct.
The function actually copies the common fields, why is it called merge
?
The function can have only two arguments, instead of three that are intermixed (source type, destination, source).
pub fn copyFields(dst: anytype, src: anytype) void {
const S = @TypeOf(src);
...
Some assertions can be used to enforce correct usage:
dst
must be a not const pointer to one item.
src
must not be a pointer.
both src
and dst
must have fields
std.debug.assert(fields.len > 0);
Welcome to ziggit
3 Likes
thank you. yeah I knew the interface is bad but I was happy that something worked that it didn’t matter.