[swift-evolution] Pitch: Automatically deriving Equatable/Hashable for more value types

Tony Allevato tony.allevato at gmail.com
Fri May 5 14:20:31 CDT 2017


On Fri, May 5, 2017 at 12:18 PM Xiaodi Wu <xiaodi.wu at gmail.com> wrote:

> Hmm, with these complications, I regret suggesting that this could be
> extended to classes so easily. Definitely some interesting solutions, but
> my inclination as well would be to leave classes out entirely for the
> moment and let it percolate for Swift 4.1+. After all, it's an additive
> convenience.
>
> Any thought as to including tuples though?
>

Can non-nominal types conform to protocols? I thought that was the main
limitation for supporting these conformances on tuples.

I would love to support them if possible to get rid of the arbitrary ==
implementations in the standard library and make multi-component dictionary
keys easier to work with, but my understanding was that the above issue was
the bigger factor preventing it.




> On Fri, May 5, 2017 at 13:51 Matthew Johnson via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>> On May 5, 2017, at 1:33 PM, Tony Allevato <tony.allevato at gmail.com>
>> wrote:
>>
>>
>>
>> On Fri, May 5, 2017 at 11:07 AM Matthew Johnson <matthew at anandabits.com>
>> wrote:
>>
>>> On May 5, 2017, at 10:45 AM, Tony Allevato via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>> Thanks for your feedback, everybody!
>>>
>>>
>>> Thanks for continuing to drive this forward!
>>>
>>>
>>> I've updated the gist
>>> <https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad> to
>>> reflect what seems to be a consensus here:
>>>
>>> * Derived conformances are now opt-in (this makes the recursive case
>>> *much* cleaner, and the complexity involved in that section has been
>>> completely removed)
>>>
>>>
>>> Can the opt-in conformance be declared in an extension?  If so, can the
>>> extension be in a different module than the original declaration?  If so,
>>> do you intend any restrictions, such as requiring all members of the type
>>> declared in a different module to be public?  My initial thought is that
>>> this should be possible as long as all members are visible.
>>>
>>
>> Declaring the conformance in an extension in the same module should
>> definitely be allowed; I believe this would currently be the only way to
>> support conditional conformances (such as the `Optional: Hashable where
>> Wrapped: Hashable` example in the updated draft), without requiring deeper
>> syntactic changes.
>>
>> I'm less sure about conformances being added in other modules, but I'm
>> inclined to agree with your assessment. I could see two ways of
>> interpreting it:
>>
>> * E/H can only be derived in an extension in an external module if all
>> the members are accessible (and the other conditions are met).
>> * E/H can be derived in an extension in an external module using only the
>> subset of accessible members (if the other conditions are met).
>>
>> These are subtly different. The argument for the first would be "if you
>> want to add E/H to a type in a different module, you must *consciously*
>> decide which members you want to use in those computations". The argument
>> for the second would be "you can already make a type in a different module
>> conform to E/H and you'd be restricted to the accessible members there, so
>> let's make that path easier for users too."
>>
>> The first case is probably the safer choice. I'm not sure about the
>> implementation difficulty of each.
>>
>>
>>> * Classes are supported now as well
>>>
>>> Please take a look at the updated version and let me know if there are
>>> any concerns! If folks like it, I'll prepare a pull request.
>>>
>>>
>>> Will the synthesis for classes dispatch through a non-final method which
>>> is expected to be overridden by subclasses?  You don’t explicitly state
>>> this but it seems implied.  If so, what if  the subclass requires a custom
>>> implementation?  This would require the signature of the non-final method
>>> to be part of the synthesis contract.
>>>
>>
>>> Supporting non-final classes introduces enough complexity (especially
>>> when multiple modules are involved).  I would hate to see it get
>>> sidetracked in discussions regarding non-final classes and miss the Swift 4
>>> window because of that.  Given the limited time left for Swift 4 it might
>>> be better to keep the initial proposal simpler and consider a followup in
>>> the Swift 5 timeframe to build on the initial proposal.
>>>
>>
>> For ==, the operator must already be "class final" or "static" regardless
>> of this proposal, and it can't be "overridden" as such in subclasses
>> because the arguments would be different (lhs and rhs would be the
>> subclass, not the superclass). So the compiler should be able to generate
>> the correct implementation for subclasses in all cases, right?
>>
>>
>> This won’t work because Equatable has a `Self` requirement so the `==`
>> defined by the initial conforming class would be called.  In order to
>> support non-final classes you would need to have that dispatch through
>> something like an `isEqual` method which *can* be overridden.
>>
>>
>> For hashValue, I think the possibilities are:
>>
>> * Sub is a subclass of Super. Super conforms to Hashable and implements
>> non-final hashValue. The compiler can derive it for Sub and call
>> super.hashValue in its implementation.
>>
>>
>> Yes, this makes sense.  The primary difficulty with Hashable is that it
>> refines Equatable.  Refining a non-final implementation of `hashValue` is
>> relatively straightforward.
>>
>> * Sub is a subclass of Super. Super conforms to Hashable and implements a
>> final hashValue. The compiler cannot derive one for Super and would
>> silently not do so.
>>
>>
>> Do you mean “the compiler cannot derive one for Sub”?
>>
>> * Sub is a subclass of Super. Super does not conform to Hashable, but Sub
>> asks to derive it. This can either (1) not be allowed, telling the user
>> that they need to write it manually in this case, or (2) be allowed and use
>> all accessible members to compute the hashValue (including those from the
>> superclass).
>>
>> What do Encodable/Decodable do in these situations? It seems similar
>> solutions there would apply here.
>>
>>
>> That’s a good question.  I don’t recall whether this was addressed
>> explicitly or not.
>>
>>
>> But after writing this all out, I'm inclined to agree that I'd rather see
>> structs/enums make it into Swift 4 even if it meant pushing classes to
>> Swift 4+x.
>>
>>
>> That is reasonable.
>>
>> On the other hand, I think you could come up with straightforward
>> semantics for synthesizing conformance for final classes as well.  Final
>> classes with no superclass should be straightforward.  Final classes that
>> do have a superclass would be similarly straightforward if we decide to
>> allow this as described in option (2) above regarding hashValue.
>>
>> I’m on the fence on this - if we can include final classes using option
>> (2) without jeopardizing getting this in for Swift 4 I would support that.
>> If it’s going to put support for value types in Swift 4 at risk then I
>> would not.
>>
>>
>>
>>
>>>
>>>
>>>
>>> On Fri, May 5, 2017 at 8:16 AM Nevin Brackett-Rozinsky via
>>> swift-evolution <swift-evolution at swift.org> wrote:
>>>
>>>> On Fri, May 5, 2017 at 1:47 AM, Xiaodi Wu via swift-evolution <
>>>> swift-evolution at swift.org> wrote:
>>>>
>>>>> On Fri, May 5, 2017 at 12:41 AM, Brent Royal-Gordon <
>>>>> brent at architechies.com> wrote:
>>>>>
>>>>>> I would think only final classes could participate in this, since a
>>>>>> subclassable class would need to allow subclasses to override equality, and
>>>>>> you can't override a static `==` operator method.
>>>>>>
>>>>>
>>>>> I work so rarely with classes that I'm embarrassed to have to ask this
>>>>> question: can classes not satisfy Equatable with a `public class func ==`?
>>>>>
>>>>
>>>> Currently:
>>>>
>>>> class C: Equatable {
>>>>     class func == (lhs: C, rhs: C) -> Bool {
>>>>         return lhs === rhs
>>>>     }
>>>> }
>>>>
>>>> Yields an error, “Operator '==' declared in non-final class 'C' must be
>>>> 'final'”.
>>>>
>>>> Nevin
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170505/16a5eaa8/attachment.html>


More information about the swift-evolution mailing list