# Union Equality

**URL:** <https://ziggit.dev/t/union-equality/4060>\
**Category:** Help\
**Tags:** language\
**Created:** [April 23, 2024, 4:03pm UTC](https://ziggit.dev/t/union-equality/4060 "2024-04-23T16:03:59Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![n0s4](https://ziggit.dev/user_avatar/ziggit.dev/n0s4/32/2227_2.png) [@n0s4](https://ziggit.dev/u/n0s4)\
**Post date:** [April 23, 2024, 4:03pm UTC](https://ziggit.dev/t/union-equality/4060/1 "2024-04-23T16:03:59Z")

</div>

I’m trying to represent a dynamically typed value in Zig, and need to be able to check if two of such values are equal, both in type and in value. I have a function that seems to work but want to know if there is any more efficient way to do this, rather than having a potentially long switch statement for every variant. Thanks.

```zig
pub const Value = union(enum) {
    pub const Type = std.meta.Tag(Value);

    nil,
    boolean: bool,
    number: f32,
    // ...

    pub fn equals(self: Value, other: Value) bool {
        if (@as(Type, self) != @as(Type, other)) return false;
        return switch (self) {
            .nil => true,
            .number => self.number == other.number,
            .boolean => self.boolean == other.boolean,
            // ...
        };
    }
}

```

---

<div class="post-metadata">

**Author:** ![matklad](https://ziggit.dev/user_avatar/ziggit.dev/matklad/32/2462_2.png) [@matklad](https://ziggit.dev/u/matklad)\
**Post date:** [April 23, 2024, 4:10pm UTC](https://ziggit.dev/t/union-equality/4060/2 "2024-04-23T16:10:26Z")

</div>

You can use `std.meta.eql`, or look how that is implemented:

```zig
        .Union => |info| {
            if (info.tag_type) |UnionTag| {
                const tag_a = activeTag(a);
                const tag_b = activeTag(b);
                if (tag_a != tag_b) return false;

                inline for (info.fields) |field_info| {
                    if (@field(UnionTag, field_info.name) == tag_a) {
                        return eql(@field(a, field_info.name), @field(b, field_info.name));
                    }
                }
                return false;
            }

            @compileError("cannot compare untagged union type " ++ @typeName(T));
        },

```

---

<div class="post-metadata">

**Author:** ![matklad](https://ziggit.dev/user_avatar/ziggit.dev/matklad/32/2462_2.png) [@matklad](https://ziggit.dev/u/matklad)\
**Post date:** [April 23, 2024, 4:12pm UTC](https://ziggit.dev/t/union-equality/4060/3 "2024-04-23T16:12:20Z")

</div>

Hm, isn’t that a bit of dead code? that `return false` should be `unreachable`, no?

---

<div class="post-metadata">

**Author:** ![Validark](https://ziggit.dev/user_avatar/ziggit.dev/validark/32/646_2.png) [@Validark](https://ziggit.dev/u/Validark)\
**Post date:** [April 23, 2024, 4:51pm UTC](https://ziggit.dev/t/union-equality/4060/4 "2024-04-23T16:51:30Z")

</div>

Aside from using a library function, yes, you probably want multiple prongs of a switch statement. At least for numeric comparisons, since comparing floats is not a straightforward check on whether the bits are equal, there is also the fact that -0 and +0 are equal, NaN’s always being unequal to everything, even themselves, and maybe there’s more. So when you do `a == b` on float types it is going to give you a completely different instruction that couldn’t be used for any other type.

You could try an `inline else` though to have Zig fill in the details.

---

<div class="post-metadata">

**Author:** ![n0s4](https://ziggit.dev/user_avatar/ziggit.dev/n0s4/32/2227_2.png) [@n0s4](https://ziggit.dev/u/n0s4)\
**Post date:** [April 23, 2024, 5:16pm UTC](https://ziggit.dev/t/union-equality/4060/5 "2024-04-23T17:16:53Z")

</div>

Thank you, I think I’ll use this.

---

<div class="post-metadata">

**Author:** ![dude\_the\_builder](https://ziggit.dev/user_avatar/ziggit.dev/dude_the_builder/32/557_2.png) [@dude\_the\_builder](https://ziggit.dev/u/dude_the_builder)\
**Post date:** [April 23, 2024, 9:13pm UTC](https://ziggit.dev/t/union-equality/4060/6 "2024-04-23T21:13:58Z")

</div>

I think this is simpler?

```zig
    pub fn equals(self: Value, other: Value) bool {
        return switch (other) {
            .nil => self == .nil,
            .number => |n| self == .number and self.number == n,
            .boolean => |b| self == .boolean and self.boolean == b,
            // ...
        };
    }

```

If you don’t mind panicking when the tags are different, you can remove the first part of the tests:

```zig
.number => |n| self.number == n, // will panic if self isn't .number

```

---

<div class="post-metadata">

**Author:** ![Sze](https://ziggit.dev/user_avatar/ziggit.dev/sze/32/496_2.png) [@Sze](https://ziggit.dev/u/Sze)\
**Post date:** [April 23, 2024, 9:43pm UTC](https://ziggit.dev/t/union-equality/4060/7 "2024-04-23T21:43:18Z")

</div>

I think this is kind of neat:

```zig
    pub fn equals(self: Value, other: Value) bool {
        return switch (self) {
            inline else => |value, tag| tag == std.meta.activeTag(other) and value == @field(other, @tagName(tag)),
        };
    }

```

This works because for nil it just compares that `{}` is equal to `{}` which is true.

* * *

If any case should compare values differently like for example float, you can add it as an explicit case like this:

```zig
    pub fn equals(self: Value, other: Value) bool {
        return switch (self) {
            .float => |f| .float == std.meta.activeTag(other) and floatEqualImpl(f, other.float),
            inline else => |value, tag| tag == std.meta.activeTag(other) and value == @field(other, @tagName(tag)),
        };
    }

```

---

<div class="post-metadata">

**Author:** ![dude\_the\_builder](https://ziggit.dev/user_avatar/ziggit.dev/dude_the_builder/32/557_2.png) [@dude\_the\_builder](https://ziggit.dev/u/dude_the_builder)\
**Post date:** [April 24, 2024, 12:16am UTC](https://ziggit.dev/t/union-equality/4060/8 "2024-04-24T00:16:58Z")

</div>

@Sze wins. Flawless victory. 😸
