Packed union comparison

Why is a packed union not comparable with == like for example a packed struct? Is that because some bits could be uninitialized if we have two different sized fields inside it?

partly yes. What would it even mean to compare two unions with different active fields?

Well !=, would be an intuitive result, but otherwise you’re comparing values of different types, which is also generally not allowed. It quickly gets complex to decide what the correct interpretation is, so likely Zig punts to the user to more explicitly code the intent by comparing the fields of the union instead of the union itself, which of course entails casting to a compatible types.

I assume because comparing equality of unions is ambiguous.

const MyUnion = packed union {
    a: u32,
    b: u32,
};

const x = MyUnion{ .a = 10 };
const y = MyUnion{ .b = 10 };

Reasonable minds could disagree one whether x and y are equal in this example, and realistically it seldom make sense to compare them without being explicit as to what “equal” would mean without more context. It is not obviously clear what the intention, or the expectation, would be here.

I thought I read somewhere that packed unions do not have “active fields” but can be explicitely there to just memory re-interprete the stuff inside.

This just works. So I was a bit surprised that == did not work.
Of course this one is very specific 2 bits.

const Uni = packed union 
{
    const Enum = enum(u2) 
    {
        A, B, C, D
    };
    e: Enum,
    u: u2,
};
const a: Uni = .{ .e = .A };
const b: Uni = .{ .u = 3 };
std.debug.print("const a: {s} {}\n", .{ @tagName(a.e), a.u});
std.debug.print("const b: {s} {}\n", .{ @tagName(b.e), b.u});

This seems like a duplicate of this topic:

Yes it is.
Unfortunately for me different sized fields inside will be disallowed, i see there.
Understandable because of missing bits when you initialize the smallest only, but it can be quite convenient in some cases (no typecasting needed).

Packed structs have the equality operator because:

  1. they have the ABI of their backing integer
  2. they only have one, well-defined representation in memory

This makes the equality operator roughly translate to a single cpu instruction for small bit-size packed structs. There is nothing hidden about what is happening. The author can understand that the code generated is likely to be a simple comparison of the backing integer.

Packed unions:

  1. can represent multiple types
  2. the active field is not detectable / stored

This means the equality operator is ambiguous. Would you want u8: 0 to compare equal to i8: 0? “Equality” in this case would mean same bits, but not same type. If you want to compare bits, bitCast to the backing integer of the packed union before comparison, or select identically typed fields.

2 Likes

Yes that is what I more or less suspected. Thx.