If you have to specify Equatable / Hashable, then you can get an error if the 
automatic implementation failed, due to a member also not being 
Equatable/Hashable. If it’s automatic, then it will just quietly fail, making 
problems harder to know about and track. It will also always add to the compile 
size, even if you didn’t want the functionality.


> On 27 May 2016, at 10:46 PM, Ricardo Parada <rpar...@mac.com> wrote:
> 
> I agree, I think there is no need for deriving/synthesizes, but also, no need 
> to specify Equatable, Hashable. They should get the functionality by default 
> but allow for override and customization. 
> 
> 
> On May 26, 2016, at 11:02 PM, Patrick Smith <pgwsm...@gmail.com 
> <mailto:pgwsm...@gmail.com>> wrote:
> 
>> I don’t understand why you couldn’t conform to Equatable, and if it fulfils 
>> the requirements (all members are also Equatable), then its implementation 
>> is automatically created for you. That way you don’t need a new keyword. 
>> It’s like Objective-C’s property automatic synthesising that get used unless 
>> you implement ones yourself.
>> 
>> 
>>> On 27 May 2016, at 12:57 PM, Ricardo Parada via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> 
>>> 
>>> 
>>> I wonder if synthesizes would be a better choice than deriving. 
>>> 
>>> 
>>> 
>>> On May 26, 2016, at 5:58 AM, Michael Peternell via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> 
>>>> Can we just copy&paste the solution from Haskell instead of creating our 
>>>> own? It's just better in every aspect. Deriving `Equatable` and `Hashable` 
>>>> would become
>>>> 
>>>> struct Polygon deriving Equatable, Hashable {
>>>>    ...
>>>> }
>>>> 
>>>> This has several advantages:
>>>> - you don't have to guess wether `Equatable` or `Hashable` should be 
>>>> automatically derived or not.
>>>> - Deriving becomes an explicit choice.
>>>> - If you need a custom `Equatable` implementation (for whatever reason), 
>>>> you can still do it.
>>>> - It doesn't break any code that is unaware of the change
>>>> - It can be extended in future versions of Swift, without introducing any 
>>>> new incompatibilities. For example, `CustomStringConvertible` could be 
>>>> derived just as easily.
>>>> - It is compatible with generics. E.g. `struct Shape<T> deriving 
>>>> Equatable` will make every `Shape<X>` equatable if `X` is equatable. But 
>>>> if `X` is not equatable, `Shape<X>` can be used as well. (Unless `X` is 
>>>> not used, in which case every `Shape<T>` would be equatable. Unless 
>>>> something in the definition of `Shape` makes deriving `Equatable` 
>>>> impossible => this produces an error.)
>>>> - It is proven to work in production.
>>>> 
>>>> -Michael
>>>> 
>>>>> Am 26.05.2016 um 03:48 schrieb Mark Sands via swift-evolution 
>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:
>>>>> 
>>>>> Thanks so much for putting this together, Tony! Glad I was able to be 
>>>>> some inspiration. :^)
>>>>> 
>>>>> 
>>>>> On Wed, May 25, 2016 at 1:28 PM, Tony Allevato via swift-evolution 
>>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>>> I was inspired to put together a draft proposal based on an older 
>>>>> discussion in the Universal Equality, Hashability, and Comparability 
>>>>> thread <http://thread.gmane.org/gmane.comp.lang.swift.evolution/8919/ 
>>>>> <http://thread.gmane.org/gmane.comp.lang.swift.evolution/8919/>> that 
>>>>> recently got necromanced (thanks Mark Sands!).
>>>>> 
>>>>> I'm guessing that this would be a significant enough change that it's not 
>>>>> possible for the Swift 3 timeline, but it's something that would benefit 
>>>>> enough people that I want to make sure the discussion stays alive. If 
>>>>> there are enough good feelings about it, I'll move it from my gist into 
>>>>> an actual proposal PR.
>>>>> 
>>>>> Automatically deriving Equatable andHashable for value types
>>>>> 
>>>>>    • Proposal: SE-0000
>>>>>    • Author(s): Tony Allevato
>>>>>    • Status: Awaiting review
>>>>>    • Review manager: TBD
>>>>> Introduction
>>>>> 
>>>>> Value types are prevalent throughout the Swift language, and we encourage 
>>>>> developers to think in those terms when writing their own types. 
>>>>> Frequently, developers find themselves writing large amounts of 
>>>>> boilerplate code to support equatability and hashability of value types. 
>>>>> This proposal offers a way for the compiler to automatically derive 
>>>>> conformance toEquatable and Hashable to reduce this boilerplate, in a 
>>>>> subset of scenarios where generating the correct implementation is likely 
>>>>> to be possible.
>>>>> 
>>>>> Swift-evolution thread: Universal Equatability, Hashability, and 
>>>>> Comparability
>>>>> 
>>>>> Motivation
>>>>> 
>>>>> Building robust value types in Swift can involve writing significant 
>>>>> boilerplate code to support concepts of hashability and equatability. 
>>>>> Equality is pervasive across many value types, and for each one users 
>>>>> must implement the == operator such that it performs a fairly rote 
>>>>> memberwise equality test. As an example, an equality test for a struct 
>>>>> looks fairly uninteresting:
>>>>> 
>>>>> func ==(lhs: Foo, rhs: Foo) -> Bool
>>>>> {
>>>>> 
>>>>> return lhs.property1 == rhs.property1 &&
>>>>> 
>>>>>         lhs
>>>>> .property2 == rhs.property2 &&
>>>>> 
>>>>>         lhs
>>>>> .property3 == rhs.property3 &&
>>>>> 
>>>>> 
>>>>> ...
>>>>> 
>>>>> }
>>>>> 
>>>>> What's worse is that this operator must be updated if any properties are 
>>>>> added, removed, or changed, and since it must be manually written, it's 
>>>>> possible to get it wrong, either by omission or typographical error.
>>>>> 
>>>>> Likewise, hashability is necessary when one wishes to store a value type 
>>>>> in a Set or use one as a multi-valuedDictionary key. Writing 
>>>>> high-quality, well-distributed hash functions is not trivial so 
>>>>> developers may not put a great deal of thought into them – especially as 
>>>>> the number of properties increases – not realizing that their performance 
>>>>> could potentially suffer as a result. And as with equality, writing it 
>>>>> manually means there is the potential to get it wrong.
>>>>> 
>>>>> In particular, the code that must be written to implement equality for 
>>>>> enums is quite verbose. One such real-world example (source):
>>>>> 
>>>>> func ==(lhs: HandRank, rhs: HandRank) -> Bool
>>>>> {
>>>>> 
>>>>> switch
>>>>> (lhs, rhs) {
>>>>> 
>>>>> case (.straightFlush(let lRank, let lSuit), .straightFlush(let rRank , let
>>>>> rSuit)):
>>>>> 
>>>>> return lRank == rRank && lSuit ==
>>>>> rSuit
>>>>> 
>>>>> case (.fourOfAKind(four: let lFour), .fourOfAKind(four: let
>>>>> rFour)):
>>>>> 
>>>>> return lFour ==
>>>>> rFour
>>>>> 
>>>>> case (.fullHouse(three: let lThree), .fullHouse(three: let
>>>>> rThree)):
>>>>> 
>>>>> return lThree ==
>>>>> rThree
>>>>> 
>>>>> case (.flush(let lRank, let lSuit), .flush(let rRank, let
>>>>> rSuit)):
>>>>> 
>>>>> return lSuit == rSuit && lRank ==
>>>>> rRank
>>>>> 
>>>>> case (.straight(high: let lRank), .straight(high: let
>>>>> rRank)):
>>>>> 
>>>>> return lRank ==
>>>>> rRank
>>>>> 
>>>>> case (.threeOfAKind(three: let lRank), .threeOfAKind(three: let
>>>>> rRank)):
>>>>> 
>>>>> return lRank ==
>>>>> rRank
>>>>> 
>>>>> case (.twoPair(high: let lHigh, low: let lLow, highCard: let
>>>>> lCard),
>>>>> 
>>>>> .twoPair(high: let rHigh, low: let rLow, highCard: let
>>>>> rCard)):
>>>>> 
>>>>> return lHigh == rHigh && lLow == rLow && lCard ==
>>>>> rCard
>>>>> 
>>>>> case (.onePair(let lPairRank, card1: let lCard1, card2: let lCard2, 
>>>>> card3: let
>>>>> lCard3),
>>>>> 
>>>>> .onePair(let rPairRank, card1: let rCard1, card2: let rCard2, card3: let
>>>>> rCard3)):
>>>>> 
>>>>> return lPairRank == rPairRank && lCard1 == rCard1 && lCard2 == rCard2 && 
>>>>> lCard3 ==
>>>>> rCard3
>>>>> 
>>>>> case (.highCard(let lCard), .highCard(let
>>>>> rCard)):
>>>>> 
>>>>> return lCard ==
>>>>> rCard
>>>>> 
>>>>> default
>>>>> :
>>>>> 
>>>>> return false
>>>>> 
>>>>>  }
>>>>> }
>>>>> 
>>>>> Crafting a high-quality hash function for this enum would be similarly 
>>>>> inconvenient to write, involving another large switchstatement.
>>>>> 
>>>>> Swift already provides implicit protocol conformance in some cases; 
>>>>> notably, enums with raw values conform toRawRepresentable, Equatable, and 
>>>>> Hashable without the user explicitly declaring them:
>>>>> 
>>>>> enum Foo: Int
>>>>> {
>>>>> 
>>>>> case one = 1
>>>>> 
>>>>> 
>>>>> case two = 2
>>>>> 
>>>>> }
>>>>> 
>>>>> 
>>>>> let x = (Foo.one == Foo.two)  // works
>>>>> let y = Foo.one.hashValue     // also works
>>>>> let z = Foo.one.rawValue      // also also works
>>>>> Since there is precedent for this in Swift, we propose extending this 
>>>>> support to more value types.
>>>>> 
>>>>> Proposed solution
>>>>> 
>>>>> We propose that a value type be Equatable/Hashable if all of its members 
>>>>> are Equatable/Hashable, with the result for the outer type being composed 
>>>>> from its members.
>>>>> 
>>>>> Specifically, we propose the following rules for deriving Equatable:
>>>>> 
>>>>>    • A struct implicitly conforms to Equatable if all of its fields are 
>>>>> of types that conform to Equatable – either explicitly, or implicitly by 
>>>>> the application of these rules. The compiler will generate an 
>>>>> implementation of ==(lhs: T, rhs: T)that returns true if and only if 
>>>>> lhs.x == rhs.x for all fields x in T.
>>>>> 
>>>>>    • An enum implicitly conforms to Equatable if all of its associated 
>>>>> values across all of its cases are of types that conform to Equatable – 
>>>>> either explicitly, or implicitly by the application of these rules. The 
>>>>> compiler will generate an implementation of ==(lhs: T, rhs: T) that 
>>>>> returns true if and only if lhs and rhs are the same case and have 
>>>>> payloads that are memberwise-equal.
>>>>> 
>>>>> Likewise, we propose the following rules for deriving Hashable:
>>>>> 
>>>>>    • A struct implicitly conforms to Hashable if all of its fields are of 
>>>>> types that conform to Hashable – either explicitly, or implicitly by the 
>>>>> application of these rules. The compiler will generate an implementation 
>>>>> of hashValue that uses a pre-defined hash function† to compute the hash 
>>>>> value of the struct from the hash values of its members.
>>>>> 
>>>>> Since order of the terms affects the hash value computation, we recommend 
>>>>> ordering the terms in member definition order.
>>>>> 
>>>>>    • An enum implicitly conforms to Hashable if all of its associated 
>>>>> values across all of its cases are of types that conform to Hashable – 
>>>>> either explicitly, or implicitly by the application of these rules. The 
>>>>> compiler will generate an implementation of hashValue that uses a 
>>>>> pre-defined hash function† to compute the hash value of an enum value by 
>>>>> using the case's ordinal (i.e., definition order) followed by the hash 
>>>>> values of its associated values as its terms, also in definition order.
>>>>> 
>>>>> † We leave the exact definition of the hash function unspecified here; a 
>>>>> multiplicative hash function such as Kernighan and Ritchie or Bernstein 
>>>>> is easy to implement, but we do not rule out other possibilities.
>>>>> 
>>>>> Overriding defaults
>>>>> 
>>>>> Any user-provided implementations of == or hashValue should override the 
>>>>> default implementations that would be provided by the compiler. This is 
>>>>> already possible today with raw-value enums so the same behavior should 
>>>>> be extended to other value types that are made to implicitly conform to 
>>>>> these protocols.
>>>>> 
>>>>> Open questions
>>>>> 
>>>>> Omission of fields from generated computations
>>>>> 
>>>>> Should it be possible to easily omit certain properties from 
>>>>> automatically generated equality tests or hash value computation? This 
>>>>> could be valuable, for example, if a property is merely used as an 
>>>>> internal cache and does not actually contribute to the "value" of the 
>>>>> instance. Under the rules above, if this cached value was equatable, a 
>>>>> user would have to override == and hashValue and provide their own 
>>>>> implementations to ignore it. If there is significant evidence that this 
>>>>> pattern is common and useful, we could consider adding a custom 
>>>>> attribute, such as @transient, that would omit the property from the 
>>>>> generated computations.
>>>>> 
>>>>> Explicit or implicit derivation
>>>>> 
>>>>> As with raw-value enums today, should the derived conformance be 
>>>>> completely explicit, or should users have to explicitly list conformance 
>>>>> with Equatable and Hashable in order for the compiler to generate the 
>>>>> derived implementation?
>>>>> 
>>>>> Impact on existing code
>>>>> 
>>>>> This change will have no impact on existing code because it is purely 
>>>>> additive. Value types that already provide custom implementations of == 
>>>>> or hashValue but satisfy the rules above would keep the custom 
>>>>> implementation because it would override the compiler-provided default.
>>>>> 
>>>>> Alternatives considered
>>>>> 
>>>>> The original discussion thread also included Comparable as a candidate 
>>>>> for automatic generation. Unlike equatability and hashability, however, 
>>>>> comparability requires an ordering among the members being compared. 
>>>>> Automatically using the definition order here might be too surprising for 
>>>>> users, but worse, it also means that reordering properties in the source 
>>>>> code changes the code's behavior at runtime. (This is true for 
>>>>> hashability as well if a multiplicative hash function is used, but hash 
>>>>> values are not intended to be persistent and reordering the terms does 
>>>>> not produce a significant behavioral change.)
>>>>> 
>>>>> Acknowledgments
>>>>> 
>>>>> Thanks to Joe Groff for spinning off the original discussion thread, Jose 
>>>>> Cheyo Jimenez for providing great real-world examples of boilerplate 
>>>>> needed to support equatability for some value types, and to Mark Sands 
>>>>> for necromancing the swift-evolution thread that convinced me to write 
>>>>> this up.
>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>> 
>>>>> 
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>> 
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> 

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to