pub fn tar(tree: anytype) void {
inline for (std.meta.fields(@TypeOf(tree))) |element| {
if (@typeInfo(@TypeOf(@field(tree, element.name))) == .@"struct") {
std.debug.print("{s} is a nested anon struct\n", .{element.name});
}
else { // granted, this could be much more discerning, but, for the example, let it be
std.debug.print("{s} is a value: {s}\n", .{element.name, @field(tree, element.name)});
}
}
}
test "tar" {
tar(.{
.a = "ay",
.b = "bee",
.c = .{
.d = "dee",
},
});
}
This “works” (output below), but is it “right”? “Ugly”?
a is a value: ay
b is a value: bee
c is a nested anon struct
There is @FieldType(T, "name") which would be slightly more optimal, if you got the @TypeOf(tree) before the loop, as it would do the field access and get the type in one go. But I’m not sure if it would actually be faster, you probably wouldn’t be able to tell unless you had a lot of fields.
It mostly exists for when you have a type, but not an instance that is required by @field, the equivalent would be @TypeOf(@field(@as(T, undefined), "name")), that is not only verbose, but it is 3 operations, where @FieldType is one.
But, ofc, you have an instance already, but not a type, so there isn’t much difference.
Not clear if it’s important to your use case, but I want to point out that this just finds struct fields, not “anonymous” ones.
Zig used to have anonymous struct types, and it no longer does. Never mind what they were, the point is that there’s no formal distinction between defining a struct type inline, and defining it with a name and referencing that name.
So it isn’t a quality you can detect. If you’re exclusively parsing a literal dot-syntax Zon-like value, this doesn’t matter, if not, it might.
Oh!? This surprises me, and I’d like to discover more. 0.16 is my reference here. So, in the above example, my .{ .a = “ay”… does qualify as anonymous, doesn’t it, as it refers to no explicit type definition for the struct? If, on the other hand, you’re referring to tuples, a little testing I did suggested that, indeed (and a little surprising), element.name DID give the name “0” (and then “1”, and so on)… I can’t remember if @field(tree, “0”) subsequently gave the field value, but I think it did. I’ll be doing more testing on this later….
If a struct type is defined in such a manner that it isn’t explicitly given a name, Zig generates one. There is no formal distinction between that struct type and any other.
Technically you could get the type name and heuristically search for evidence that this has happened. Please don’t.
Thank you, yes, that’s the kind of insight/extension I’m after. I made an update that const-assigns to eliminate duplicate calls and make everything cleaner; I just left all that in the first iteration to over-visualize all the @calling.
Gotcha, so… I may have missed your original point then, about this not working for “anonymous ones”.
Right, I should’ve been more careful. I just wasn’t sure if, by “I want to point out that this just finds struct fields, not “anonymous” ones,” you meant “anonymous structs” or “anonymous fields”; the latter I would have assumed to mean: in reference to a tuple. But, I wonder if the standard doc should be modified a little; it introduces tuples as:
Anonymous structs can be created without specifying field names, and are referred to as “tuples”.
And yet, reflecting on earlier threads, including your seminal one on tuples and structs, I agree, and appreciate the distinction between structs and tuples.
My working code is more than the trim I posted to start this thread - it actually recurses into embedded structs. BUT I actually have some tuples embedded in my test tree, right along with the named-field structs. A little to my surprise, everything “just worked”. So I looked and noticed that std/builtin.zig’s Type union does NOT have a field for tuple. Indeed, the tuples that were encountered in my tree were “just structs” as far as this branching cared, and recursion worked just fine with them. I guess a question that might emerge would be: should I expect this to fail, once tuples are cleanly distinguished from structs? I’d be fine with that, actually (as long as there was a tuple field in the builtin.zig Type union), but I’m curious to know something about the likelihood. I guess, “aren’t we all?!” is one acceptable answer.