Stream: beginners

Topic: Compare different Tags


view this post on Zulip Oskar Hahn (Sep 30 2024 at 15:13):

If I have a function, that returns a tag like [A,B,C], and I want to compare it with a tag like this [A, B], is that possible?

For example:

func : {} -> [A, B, C]
func = \_ -> C

otherFunc : [A, B] -> Bool
otherFunc = \ab ->
  func {} == ab

If I run this, I get an error like

This ab value is a:

    […]

But == needs its 2nd argument to be:

    [C, …]

view this post on Zulip Oskar Hahn (Sep 30 2024 at 15:17):

Ah. I found a solution. I can use [A, B]_ instead of [A, B].

otherFunc : [A, B]_ -> Bool
otherFunc = \ab ->
  func {} == ab

But is this really necessary? If the argument to otherFunc should only be A or B, then the _ seems wrong. Would it be possible to compare any tags and just return Bool.false, if they do not intersect?

view this post on Zulip Sam Mohr (Sep 30 2024 at 16:35):

My understanding is that equality checks via == are derived for specific types, and return true for things that are "structurally" the same

view this post on Zulip Sam Mohr (Sep 30 2024 at 16:36):

So as much as the code makes the types [A, B] and [A, B, C] look the same because two of the variants have the same name, the overall types are actually different

view this post on Zulip Sam Mohr (Sep 30 2024 at 16:39):

The _ is actually just a type hole, not a generic parameter, so it'll resolve to a specific type here, meaning that [A, B]_ is resolving to [A, B] only, and not [A, B, C] as well.

view this post on Zulip Sam Mohr (Sep 30 2024 at 16:43):

For us to implement equality checks between different types is a bit of a rabbit hole... Do we only allow it for tag unions where one is a subset of the other? What if each union has variants missing from the other?

view this post on Zulip Sam Mohr (Sep 30 2024 at 16:44):

So for now, we'd probably expect you to do one of two things:

view this post on Zulip Sam Mohr (Sep 30 2024 at 16:45):

Write a match expression:

when (ab, abc) is
    (A, A) -> Bool.true
    (B, B) -> Bool.true
    _ -> Bool.false

view this post on Zulip Sam Mohr (Sep 30 2024 at 16:46):

Or keep the [A, B] variant in a parent to make the [A, B] type equal:

MyType : [AB [A, B], C]

when myType is
    AB myAb -> myAb == ab
    C -> Bool.false

view this post on Zulip Oskar Hahn (Sep 30 2024 at 16:55):

It's both not so nice. I think I will stay with [A, B]_ for the moment, even when it's not correct

view this post on Zulip Brendan Hansknecht (Sep 30 2024 at 19:07):

So for now, we'd probably expect you to do one of two things:

This is a contrived example, so it is hard to say for sure, but I think the recommendation today would be to not try and compare two different types. Instead architect the code differently.

view this post on Zulip Brendan Hansknecht (Sep 30 2024 at 19:08):

This is kinda like trying to compare two different c++ enums that happen to have some tags with the same names.

view this post on Zulip Oskar Hahn (Sep 30 2024 at 19:42):

When I think about it, I get it. If I had this types: [A, B, C] and [B, C]. In memory, the Bfrom the first type is represented as 1 and the one from the second tag as 0. If you write B == B it would look like 1 == 0 in memory. If roc should be able to compare them, roc would need to convert the types.

I get, that this is something, that should be avoided. But when I just look at the roc code, it is strange at first, that B == B is a type error.

view this post on Zulip Brendan Hansknecht (Sep 30 2024 at 23:04):

Yeah, totally agree with that being strange. The issue with not namespacing or qualifying our tags in some way

view this post on Zulip Brendan Hansknecht (Sep 30 2024 at 23:04):

Cause it really should be: Union1::B == Union2::B

view this post on Zulip Sam Mohr (Sep 30 2024 at 23:46):

Brendan Hansknecht said:

Yeah, totally agree with that being strange. The issue with not namespacing or qualifying our tags in some way

A cost that is totally worth opting into, but is definitely a cost


Last updated: Jul 06 2025 at 12:14 UTC