Comment by tialaramex

2 days ago

C's union (and the one in Rust or C++) is a kind of user defined type that's literally just either A or B. It does not know whether it's an A or a B, ensuring you achieve type safety (not using it as an A when it was actually a B or vice versa) is your job as programmer. It's size is thus MAX(size_of(A), size_of(B))

[This is a big part of why writing to Rust's union is safe, storing either an A or a B is fine, there's no safety problem, only reading the union has potential issues and thus needs an unsafe super power]

But your quote was about a tagged union, which is a common idea found in more modern languages and which you could implement by hand in C easily enough (though it is tedious to work with). The tagged union also has a field (we can think of it as an enumeration and I believe in Zig that's always exactly what it is) which says either A or B, so we can check that field and know if it's an A or a B. This type is slightly bigger, to make space for that enumeration field‡

So in your quote the problem is that from a type safety POV it was crucial to set that field to B, not just write a B where the A was and hope.

‡ One of the important ideas in Rust is that we can avoid having this extra field in some cases yet deliver the same behaviour as if it existed - and that makes an important size / efficiency difference to our program, this is called "Niche optimization" and to some extent a C++ program could do it "by hand" using specialization and indeed a C programmer could write lots of horrible macros to enforce this style in their C, I would not recommend that.