Merge structs

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

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 :slight_smile:

3 Likes

thank you. yeah I knew the interface is bad but I was happy that something worked that it didn’t matter.