-
Notifications
You must be signed in to change notification settings - Fork 86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add type equality is_equal_to
member
#2368
Conversation
Codecov Report
Additional details and impacted files
|
and any( | ||
all( | ||
this._is_equal_to(that, all_parameters) | ||
for this, that in zip(self._contents, contents) | ||
) | ||
for contents in permutations(other._contents) | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like the correct thing to do, but it's really not ideal to be invoking the permutations in order to do so. AFAICR, we have not suggested that the order of a union's contents matters, so we must check equality like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although records and unions have a canonical contents
order that they preserve, it would be correct to say that two records or two unions are equal if they have the same set of contents
, regardless of order (zip(fields, contents)
in the case of records, which puts an ordering back in for tuples).
I was trying some examples with our new canonicalization rules to see if we'd have to distinguish between types like
A = union[option[X], Y]
and
B = union[X, option[Y]]
I found that an attempt to create
C = option[union[X, Y]]
forces you to go through simplified
and makes
D = union[option[X], option[Y]]
but it's still possible to create an asymmetric case (A
or B
). How about if we squash that avenue as well? That is, an attempt to construct
UnionArray(tags, index, [option_type_array, non_option_type_array])
would (with a future rule) fail and force you to use UnionArray.simplified
(already required wherever the codebase makes UnionArray
, and then UnionArray.simplified
would wrap all the non-option type arrays in an UnmaskedArray
if any one of the provided contents
is option-type.
How about it? Then you'd have fewer cases to consider when checking equality of types: you wouldn't have to worry about whether A
and B
should be considered equivalent because they can't exist (they always be D
).
This comment can become a new issue, if you like that idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this is an interesting thought. I had not thought about the fact that ?union[X, Y]
, union[?X, Y]
and union[X, ?Y]
are degenerate. We don't permit ?union
, so perhaps we do want this rule, too. Especially as UnmaskedArray
is very low overhead.
For posterity, @jpivarski's point is partially distinct from the need to perform permutations; rather, even with permutations there are currently-valid representations that would not evaluate as equivalent despite the functional equivalence.
I'm in favour, and I'll create an issue from this comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So types wouldn't even have an __eq__
? Users are forced to use is_equal_to
?
What about providing is_equal_to
for more control, as you've implemented it here, and have __eq__
be an alias to it with sensible defaults? (is_equal_to
already has all of its options as opt-in.)
Also, I have a comment below about ambiguity of union[option[X], Y]
and union[X, option[Y]]
which could be followed up in a new issue/PR.
No, I agree that we need This PR sets |
I see: __eq__ = is_equal_to I missed that, searching for " This is good to go! |
@jpivarski when I made #1773, I was leaning towards records having a definable order (as they do for tuples). However, it sounds like we're not interested in pushing that idea, so #1773 really just guarantees order under serialisation only. Iff. this is the case, do you agree that I need to mirror the permutation logic (in union type equality comparison) for the record comparison case? Nicely, the initial permutation is always the trivial one (c1, c2, ..., cn), which should often be the right one. |
Yes, the permutation will always be needed. (That's what I meant in my first paragraph, before going on a tangent about The order is preserved through serialization and lots of operations—it's important for us to not lose it—but it is not essential to the meaning of the record or union. Not losing the order is so that a user-supplied The way I think about it formally, a record type (instance) is a mapping from names to field types (field instances), and a domain of "names" is not usually ordered. We implement an ordering to not wantonly change it as a kindness to users, but formally, it isn't part of the definition. |
In general, we have more ways of comparing types than the argument-less
__eq__
protocol permits. This PR adds support for comparison of just the nominal parameters, or all parameters.If we're happy with this idea, I'd want to gradually rework the
Content.is_equal_to
and add a form equivalent too, probably.In future, we can extend this signature to e.g. allow same-kind numeric comparisons.