Also… (hopefully the last follow up)
Even though I’ve read docs with examples on switch
several times, which says (best parts):
switch
can be used to capture the field values of a Tagged union.
Switch prongs can be marked as inline to generate the prong’s body for each possible value it could have.
The else branch catches everything not already captured.
inline else
prongs can be used as a type safe alternative to inline for
loops
I still have hard time getting the overall picture of (1) how exactly this switch with inline else and capture work, and (2) whether there is any reason to use @as
in switch(@as(tag_type, node))
rather than being explicit as the solution works successfully without. Here what I tried to do:
const std = @import("std");
pub fn main() !void {
const Node = union(enum) { f1: u8, f2: u8 };
const node = Node{ .f1 = 255 };
prettyPrint(node);
}
fn prettyPrint(node: anytype) void {
const node_T_info = @typeInfo(@TypeOf(node));
if (node_T_info == .Union) {
const op_tag_type = node_T_info.Union.tag_type;
if (op_tag_type) |tag_type| {
// inlined else
switch (node) {
inline else => |tag| {
std.log.debug("{any}", .{tag}); // 255
},
}
// inlined else + as
switch (@as(tag_type, node)) {
inline else => |tag| {
std.log.debug("{any}", .{tag}); // @typeInfo(filename.main.Node).Union.tag_type.?.f1
},
}
// normal else
switch (node) {
else => |tag| {
std.log.debug("{any}", .{tag}); // filename.main.Node{ .f1 = 255 }
},
}
// normal else + as
switch (@as(tag_type, node)) {
else => |tag| {
std.log.debug("{any}", .{tag}); // @typeInfo(filename.main.Node).Union.tag_type.?.f1
},
}
}
}
}
And here is what I get:
debug: 255
debug: @typeInfo(filename.main.Node).Union.tag_type.?.f1
debug: filename.main.Node{ .f1 = 255 }
debug: @typeInfo(filename.main.Node).Union.tag_type.?.f1
As you can see sometimes the capture returns “unwrapped” value of the union field, sometimes it returns a kind of “struct”, sometimes it prints… not sure how to even describe it. After seeing all that, I’m completely lost behind the s-witch magic.