Unexpected size of union

Hey!

The following code prints 2. I don’t understand why that happens.
I expected it to print 1, because the payloads are just 6 bits, meaning the discriminant / tag could be stored in the remaining 2 bits of the 8 bits in 1 byte.

const Node = union(enum) {
    Next,
    BranchYes: u6,
    BranchYes: u6,
    Terminal: u6,
};

print("{}",.{@sizeOf(Node)})

Can someone explain to me why this Zig does not make this optimization?

1 Like

There is a proposal to make this for ?enum{}, maybe they will add it at some point in the future, for now if you absolutely need the optimization you can do this:

const NodeTag = enum(u2) {
    Next,
    BranchYes,
    Terminal,
}

const Node = packed struct(u8) {
    tag: NodeTag,
    payload: packed union(u6) {
        BranchYes: u6,
        Terminal: u6,
    }
};

You will have to do some stuff manually, but it is what it is.

2 Likes

Since the language and libraries are changing a lot, many optimizations mostly remain in the future. This optimization is a space optimization that will likely have code size and runtime performance implications, so it’s not a 100% win, depending on circumstances and your goals.

There are issues open for this and the similar case for optionals – so-called “niche optimization”, so this area is on the radar.

I expect this and other optimization will naturally become more of a focus after we have more native backends.

2 Likes

Is there a link to this proposal somewhere?

I don’t remember the exact name, it’s an old proposal on github if you want to find it, not in codeberg.

1 Like