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> 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>: >> >> 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> 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/> 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 >> https://lists.swift.org/mailman/listinfo/swift-evolution >> >> >> _______________________________________________ >> swift-evolution mailing list >> swift-evolution@swift.org >> https://lists.swift.org/mailman/listinfo/swift-evolution > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution