<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><br><br><div id="AppleMailSignature"><span style="background-color: rgba(255, 255, 255, 0);">I like this. </span></div><div id="AppleMailSignature"><span style="background-color: rgba(255, 255, 255, 0);"><br></span></div><div id="AppleMailSignature"><span style="background-color: rgba(255, 255, 255, 0);">I don't see why not make this the default. </span></div><div id="AppleMailSignature"><span style="background-color: rgba(255, 255, 255, 0);"><br></span></div><div id="AppleMailSignature"><span style="background-color: rgba(255, 255, 255, 0);">If someone thinks it is not needed for their application then they simply don't use it. Having it there would not cause any harm. Unless someone had a requirement to have strict control on the size of the application and had to cut down on the amount of code. </span></div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">If we establish that value types get this by default then there is no need to make it explicit. It would become a known fact for value types in the Swift language. </div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">I don't see a reason to make this opt-in. I think there is more beneficial to make the behavior automatic and allow a way to override/ customize. </div><div id="AppleMailSignature"><br></div></div><div><br>On May 25, 2016, at 2:28 PM, Tony Allevato via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br><br></div><blockquote type="cite"><div><div dir="ltr">I was inspired to put together a draft proposal based on an older discussion in the Universal Equality, Hashability, and Comparability thread <<a href="http://thread.gmane.org/gmane.comp.lang.swift.evolution/8919/">http://thread.gmane.org/gmane.comp.lang.swift.evolution/8919/</a>> that recently got necromanced (thanks Mark Sands!).<div><br></div><div>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.</div><div><br></div><div><h1 style="font-size:2.25em;margin:0px 0px 16px;line-height:1.2;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol'">Automatically deriving<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:inherit;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Equatable</code><span class="inbox-inbox-Apple-converted-space"> </span>and<code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:inherit;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Hashable</code><span class="inbox-inbox-Apple-converted-space"> </span>for value types</h1><ul style="padding-left:2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px"><li style="box-sizing: border-box;">Proposal:<span class="inbox-inbox-Apple-converted-space"> </span><a href="https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-name.md" style="color:rgb(64,120,192);text-decoration:none;background-color:transparent">SE-0000</a></li><li style="box-sizing: border-box;">Author(s):<span class="inbox-inbox-Apple-converted-space"> </span><a href="https://github.com/allevato" style="color:rgb(64,120,192);text-decoration:none;background-color:transparent">Tony Allevato</a></li><li style="box-sizing: border-box;">Status:<span class="inbox-inbox-Apple-converted-space"> </span><span style="font-weight:bolder"><a href="https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad#rationale" style="color:rgb(64,120,192);text-decoration:none;background-color:transparent">Awaiting review</a></span></li><li style="box-sizing: border-box;">Review manager: TBD</li></ul><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol'"><a id="inbox-inbox-user-content-introduction" class="inbox-inbox-anchor" href="https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad#introduction" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent"></a>Introduction</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">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 to<code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Equatable</code><span class="inbox-inbox-Apple-converted-space"> </span>and<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Hashable</code><span class="inbox-inbox-Apple-converted-space"> </span>to reduce this boilerplate, in a subset of scenarios where generating the correct implementation is likely to be possible.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">Swift-evolution thread:<span class="inbox-inbox-Apple-converted-space"> </span><a href="http://thread.gmane.org/gmane.comp.lang.swift.evolution/8919" style="color:rgb(64,120,192);text-decoration:none;background-color:transparent">Universal Equatability, Hashability, and Comparability</a></p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol'"><a id="inbox-inbox-user-content-motivation" class="inbox-inbox-anchor" href="https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad#motivation" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent"></a>Motivation</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">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<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">==</code><span class="inbox-inbox-Apple-converted-space"> </span>operator such that it performs a fairly rote memberwise equality test. As an example, an equality test for a struct looks fairly uninteresting:</p><div class="inbox-inbox-highlight inbox-inbox-highlight-source-swift" style="margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px"><pre style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;border-radius:3px;word-break:normal;background-color:rgb(247,247,247)"><span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">func</span> <span class="inbox-inbox-pl-en" style="color:rgb(121,93,163)">==</span>(lhs: Foo, rhs: Foo) <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">-></span> <span class="inbox-inbox-pl-c1" style="color:rgb(0,134,179)">Bool</span> {
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">return</span> lhs<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>property1 <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rhs<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>property1 <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">&&</span>
lhs<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>property2 <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rhs<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>property2 <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">&&</span>
lhs<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>property3 <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rhs<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>property3 <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">&&</span>
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">...</span>
}</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">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.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">Likewise, hashability is necessary when one wishes to store a value type in a<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Set</code><span class="inbox-inbox-Apple-converted-space"> </span>or use one as a multi-valued<code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Dictionary</code><span class="inbox-inbox-Apple-converted-space"> </span>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.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">In particular, the code that must be written to implement equality for enums is quite verbose. One such real-world example (<a href="https://github.com/exercism/xswift/blob/master/exercises/poker/PokerExample.swift#L151-L189" style="color:rgb(64,120,192);text-decoration:none;background-color:transparent">source</a>):</p><div class="inbox-inbox-highlight inbox-inbox-highlight-source-swift" style="margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px"><pre style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;border-radius:3px;word-break:normal;background-color:rgb(247,247,247)"><span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">func</span> <span class="inbox-inbox-pl-en" style="color:rgb(121,93,163)">==</span>(lhs: HandRank, rhs: HandRank) <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">-></span> <span class="inbox-inbox-pl-c1" style="color:rgb(0,134,179)">Bool</span> {
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">switch</span> (lhs, rhs) {
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">case</span> (<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>straightFlush(<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lRank, <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lSuit), <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>straightFlush(<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rRank , <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rSuit)):
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">return</span> lRank <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rRank <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">&&</span> lSuit <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rSuit
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">case</span> (<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>fourOfAKind(four: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lFour), <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>fourOfAKind(four: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rFour)):
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">return</span> lFour <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rFour
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">case</span> (<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>fullHouse(three: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lThree), <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>fullHouse(three: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rThree)):
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">return</span> lThree <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rThree
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">case</span> (<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>flush(<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lRank, <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lSuit), <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>flush(<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rRank, <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rSuit)):
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">return</span> lSuit <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rSuit <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">&&</span> lRank <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rRank
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">case</span> (<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>straight(high: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lRank), <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>straight(high: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rRank)):
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">return</span> lRank <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rRank
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">case</span> (<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>threeOfAKind(three: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lRank), <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>threeOfAKind(three: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rRank)):
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">return</span> lRank <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rRank
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">case</span> (<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>twoPair(high: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lHigh, low: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lLow, highCard: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lCard),
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>twoPair(high: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rHigh, low: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rLow, highCard: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rCard)):
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">return</span> lHigh <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rHigh <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">&&</span> lLow <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rLow <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">&&</span> lCard <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rCard
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">case</span> (<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>onePair(<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lPairRank, card1: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lCard1, card2: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lCard2, card3: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lCard3),
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>onePair(<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rPairRank, card1: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rCard1, card2: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rCard2, card3: <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rCard3)):
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">return</span> lPairRank <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rPairRank <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">&&</span> lCard1 <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rCard1 <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">&&</span> lCard2 <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rCard2 <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">&&</span> lCard3 <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rCard3
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">case</span> (<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>highCard(<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> lCard), <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>highCard(<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> rCard)):
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">return</span> lCard <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> rCard
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">default</span>:
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">return</span> <span class="inbox-inbox-pl-c1" style="color:rgb(0,134,179)">false</span>
}
}</pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">Crafting a high-quality hash function for this enum would be similarly inconvenient to write, involving another large<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">switch</code>statement.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">Swift already provides implicit protocol conformance in some cases; notably, enums with raw values conform to<code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">RawRepresentable</code>,<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Equatable</code>, and<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Hashable</code><span class="inbox-inbox-Apple-converted-space"> </span>without the user explicitly declaring them:</p><div class="inbox-inbox-highlight inbox-inbox-highlight-source-swift" style="margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px"><pre style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;border-radius:3px;word-break:normal;background-color:rgb(247,247,247)"><span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">enum</span> Foo: <span class="inbox-inbox-pl-c1" style="color:rgb(0,134,179)">Int</span> {
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">case</span> one <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">=</span> <span class="inbox-inbox-pl-c1" style="color:rgb(0,134,179)">1</span>
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">case</span> two <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">=</span> <span class="inbox-inbox-pl-c1" style="color:rgb(0,134,179)">2</span>
}
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> x <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">=</span> (Foo<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>one <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">==</span> Foo<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>two) <span class="inbox-inbox-pl-c" style="color:rgb(150,152,150)">// works</span>
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> y <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">=</span> Foo<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>one<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span><span class="inbox-inbox-pl-c1" style="color:rgb(0,134,179)">hashValue</span> <span class="inbox-inbox-pl-c" style="color:rgb(150,152,150)">// also works</span>
<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">let</span> z <span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">=</span> Foo<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span>one<span class="inbox-inbox-pl-k" style="color:rgb(167,29,93)">.</span><span class="inbox-inbox-pl-c1" style="color:rgb(0,134,179)">rawValue</span> <span class="inbox-inbox-pl-c" style="color:rgb(150,152,150)">// also also works</span></pre></div><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">Since there is precedent for this in Swift, we propose extending this support to more value types.</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol'"><a id="inbox-inbox-user-content-proposed-solution" class="inbox-inbox-anchor" href="https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad#proposed-solution" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent"></a>Proposed solution</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">We propose that a value type be<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Equatable</code>/<code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Hashable</code><span class="inbox-inbox-Apple-converted-space"> </span>if all of its members are<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Equatable</code>/<code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Hashable</code>, with the result for the outer type being composed from its members.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">Specifically, we propose the following rules for deriving<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Equatable</code>:</p><ul style="padding-left:2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px"><li style="box-sizing: border-box;"><p style="margin-top:16px;margin-bottom:16px">A<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">struct</code><span class="inbox-inbox-Apple-converted-space"> </span>implicitly conforms to<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Equatable</code><span class="inbox-inbox-Apple-converted-space"> </span>if all of its fields are of types that conform to<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Equatable</code><span class="inbox-inbox-Apple-converted-space"> </span>– either explicitly, or implicitly by the application of these rules. The compiler will generate an implementation of<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">==(lhs: T, rhs: T)</code>that returns true if and only if<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">lhs.x == rhs.x</code><span class="inbox-inbox-Apple-converted-space"> </span>for all fields<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">x</code><span class="inbox-inbox-Apple-converted-space"> </span>in<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">T</code>.</p></li><li style="box-sizing: border-box;"><p style="margin-top:16px;margin-bottom:16px">An<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">enum</code><span class="inbox-inbox-Apple-converted-space"> </span>implicitly conforms to<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Equatable</code><span class="inbox-inbox-Apple-converted-space"> </span>if all of its associated values across all of its cases are of types that conform to<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Equatable</code><span class="inbox-inbox-Apple-converted-space"> </span>– either explicitly, or implicitly by the application of these rules. The compiler will generate an implementation of<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">==(lhs: T, rhs: T)</code><span class="inbox-inbox-Apple-converted-space"> </span>that returns true if and only if<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">lhs</code><span class="inbox-inbox-Apple-converted-space"> </span>and<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">rhs</code><span class="inbox-inbox-Apple-converted-space"> </span>are the same case and have payloads that are memberwise-equal.</p></li></ul><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">Likewise, we propose the following rules for deriving<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Hashable</code>:</p><ul style="padding-left:2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px"><li style="box-sizing: border-box;"><p style="margin-top:16px;margin-bottom:16px">A<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">struct</code><span class="inbox-inbox-Apple-converted-space"> </span>implicitly conforms to<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Hashable</code><span class="inbox-inbox-Apple-converted-space"> </span>if all of its fields are of types that conform to<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Hashable</code><span class="inbox-inbox-Apple-converted-space"> </span>– either explicitly, or implicitly by the application of these rules. The compiler will generate an implementation of<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">hashValue</code><span class="inbox-inbox-Apple-converted-space"> </span>that uses a pre-defined hash function<span style="font-size:12px;line-height:0;vertical-align:baseline">†</span><span class="inbox-inbox-Apple-converted-space"> </span>to compute the hash value of the struct from the hash values of its members.</p><p style="margin-top:16px;margin-bottom:16px">Since order of the terms affects the hash value computation, we recommend ordering the terms in member definition order.</p></li><li style="box-sizing: border-box;"><p style="margin-top:16px;margin-bottom:16px">An<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">enum</code><span class="inbox-inbox-Apple-converted-space"> </span>implicitly conforms to<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Hashable</code><span class="inbox-inbox-Apple-converted-space"> </span>if all of its associated values across all of its cases are of types that conform to<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Hashable</code><span class="inbox-inbox-Apple-converted-space"> </span>– either explicitly, or implicitly by the application of these rules. The compiler will generate an implementation of<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">hashValue</code><span class="inbox-inbox-Apple-converted-space"> </span>that uses a pre-defined hash function<span style="font-size:12px;line-height:0;vertical-align:baseline">†</span><span class="inbox-inbox-Apple-converted-space"> </span>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.</p></li></ul><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px"><span style="font-size:12px;line-height:0;vertical-align:baseline">†</span><span class="inbox-inbox-Apple-converted-space"> </span>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.</p><h3 style="margin-top:1em;margin-bottom:16px;line-height:1.43;font-size:1.5em;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol'"><a id="inbox-inbox-user-content-overriding-defaults" class="inbox-inbox-anchor" href="https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad#overriding-defaults" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2;background-color:transparent"></a>Overriding defaults</h3><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">Any user-provided implementations of<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">==</code><span class="inbox-inbox-Apple-converted-space"> </span>or<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">hashValue</code><span class="inbox-inbox-Apple-converted-space"> </span>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.</p><h3 style="margin-top:1em;margin-bottom:16px;line-height:1.43;font-size:1.5em;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol'"><a id="inbox-inbox-user-content-open-questions" class="inbox-inbox-anchor" href="https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad#open-questions" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2;background-color:transparent"></a>Open questions</h3><h4 style="margin-top:1em;margin-bottom:16px;line-height:1.4;font-size:1.25em;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol'"><a id="inbox-inbox-user-content-omission-of-fields-from-generated-computations" class="inbox-inbox-anchor" href="https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad#omission-of-fields-from-generated-computations" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2;background-color:transparent"></a>Omission of fields from generated computations</h4><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">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<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">==</code><span class="inbox-inbox-Apple-converted-space"> </span>and<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">hashValue</code><span class="inbox-inbox-Apple-converted-space"> </span>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<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">@transient</code>, that would omit the property from the generated computations.</p><h4 style="margin-top:1em;margin-bottom:16px;line-height:1.4;font-size:1.25em;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol'"><a id="inbox-inbox-user-content-explicit-or-implicit-derivation" class="inbox-inbox-anchor" href="https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad#explicit-or-implicit-derivation" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2;background-color:transparent"></a>Explicit or implicit derivation</h4><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">As with raw-value enums today, should the derived conformance be completely explicit, or should users have to explicitly list conformance with<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Equatable</code><span class="inbox-inbox-Apple-converted-space"> </span>and<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Hashable</code><span class="inbox-inbox-Apple-converted-space"> </span>in order for the compiler to generate the derived implementation?</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol'"><a id="inbox-inbox-user-content-impact-on-existing-code" class="inbox-inbox-anchor" href="https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad#impact-on-existing-code" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent"></a>Impact on existing code</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">This change will have no impact on existing code because it is purely additive. Value types that already provide custom implementations of<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">==</code><span class="inbox-inbox-Apple-converted-space"> </span>or<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">hashValue</code><span class="inbox-inbox-Apple-converted-space"> </span>but satisfy the rules above would keep the custom implementation because it would override the compiler-provided default.</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol'"><a id="inbox-inbox-user-content-alternatives-considered" class="inbox-inbox-anchor" href="https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad#alternatives-considered" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent"></a>Alternatives considered</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">The original discussion thread also included<span class="inbox-inbox-Apple-converted-space"> </span><code style="font-family:consolas,'liberation mono',menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)">Comparable</code><span class="inbox-inbox-Apple-converted-space"> </span>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<span class="inbox-inbox-Apple-converted-space"> </span><em style="box-sizing: border-box;">behavioral</em><span class="inbox-inbox-Apple-converted-space"> </span>change.)</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol'"><a id="inbox-inbox-user-content-acknowledgments" class="inbox-inbox-anchor" href="https://gist.github.com/allevato/2fd10290bfa84accfbe977d8ac07daad#acknowledgments" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent"></a>Acknowledgments</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'helvetica neue',helvetica,'segoe ui',arial,freesans,sans-serif,'apple color emoji','segoe ui emoji','segoe ui symbol';font-size:16px;line-height:25.6px">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.</p></div></div>
</div></blockquote><blockquote type="cite"><div><span>_______________________________________________</span><br><span>swift-evolution mailing list</span><br><span><a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a></span><br><span><a href="https://lists.swift.org/mailman/listinfo/swift-evolution">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span><br></div></blockquote></body></html>