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