Skip to content

Synthesize ==/hashValue for tuple fields/payloads #12598

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

Closed
wants to merge 3 commits into from

Conversation

allevato
Copy link
Member

@allevato allevato commented Oct 24, 2017

The original PR (#9619) implementing Equatable/Hashable only covered types that directly conformed to those protocols. This is a bit restrictive for real-world usage—for example, a struct with an Int? field won't be able to synthesize, so this PR fills in some gaps for the sake of usability: synthesis for fields/associated values that are Optional<T> where T: Equatable/Hashable and for tuples where all fields are Equatable/Hashable.

~In each case, ~future language improvements will eventually allow the special cases to go away. For Optional, we need conditional conformances. For tuples, we need the ability to conform non-nominal types to protocols (and variadic generics).

Update: As discussed below, the support for Optional has been removed because it will be covered better by conditional conformances. Exciting!

@allevato
Copy link
Member Author

Open question: Attempting to do this recursively (to allow synthesis in the presence of fields, say, of types Int??, (Int?, Int?), or (Int, Int)?) gets quite a bit more complicated, so those have been left out.

But, there may be some value in extending this to handle Array and Dictionary—the == operator already exists for [T] and [T: U] where T and U are Equatable, and we could add helper functions in Hashing.swift for computing their hash values.

Thoughts?

@airspeedswift
Copy link
Member

Once we have conditional conformance this can just be driven by Equatable conformance (except for tuples). And that should be pretty close based on @huonw’s recent commits. So probably better to hold off for now.

@allevato
Copy link
Member Author

@airspeedswift That's great—I didn't realize they were that close. Making ==/hashValue work with conditional conformances will require the ability to synthesize in a same-file extension, which we don't support today, but I can work on that in a different PR.

It sounds like I should remove the Optional support from this one and focus solely on tuples. WDYT?

@DougGregor
Copy link
Member

Yeah, I'd prefer to remove Optional support from this pull request and focus solely on tuples, for which we won't be able to use conditional conformances.

@allevato allevato changed the title Synthesize ==/hashValue for Optional and tuple fields Synthesize ==/hashValue for tuple fields/payloads Oct 25, 2017
@allevato
Copy link
Member Author

Sounds good to me! I've updated the PR to cover tuples only.

@xwu
Copy link
Collaborator

xwu commented Oct 25, 2017

Question: tuples have == implemented only up to arity 6, and that's an acknowledged hack. Instead of synthesizing Equatable for types that have a tuple field, can we fix the hack and actually synthesize Equatable for the tuples themselves?

@allevato
Copy link
Member Author

@xwu I looked into it a little bit, but it seems that having non-nominal types conform to protocols is a much deeper change. Unfortunately I'm less familiar with where to go about getting started on that.

Since I don't know how much work it is, I'm not sure if it would make it by the Swift 4.1 deadline. If that change isn't possible in that timeframe, I'd like to not have the existing synthesis crippled because of that missing feature. The tuple-specific changes in this PR can be easily removed in the future once tuples have that capability.

@huonw
Copy link
Contributor

huonw commented Oct 25, 2017

can we fix the hack and actually synthesize Equatable for the tuples themselves?

Even aside from the non-nominal types issue, this also requires conditional conformances. It requires synthesizing something like extension<T, U> (T, U): Equatable where T: Equatable, U: Equatable (pseudo-Swift syntax), which is almost, but not quite, supported.

@allevato
Copy link
Member Author

allevato commented Oct 25, 2017

It's also less clear how tuples and Hashable conformance would interact. Equatable is "cleaner" because the requirement can be satisfied by synthesizing a global function.

What does it mean to attach a property to a tuple? What if my tuple is (foo: Int, hashValue: Int) and I want it to conform to Hashable? How is that collision handled? (Edit: In retrospect, I suppose that's no different than if I have a struct with an existing property named hashValue—it would just shadow it, whether that was your intention or not.)

@xwu
Copy link
Collaborator

xwu commented Oct 25, 2017

This is one reason (I think) why the design of the derived == operator was changed so that the actual method is named __derived_struct_equals with an attribute @_implements(Equatable, ==(_:_:)).

If it isn't already, the synthesized hashValue should be named __derived_struct_hashValue with a corresponding attribute so that no funny shadowing occurs.

@CodaFi
Copy link
Contributor

CodaFi commented Nov 17, 2019

@allevato It's been a few years. If you want to pursue this further, could you please pitch this to evolution so we can get the community's updated thoughts on the idea?

Sorry we weren't able to resolve this at the time.

@CodaFi CodaFi closed this Nov 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants