<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On 25 May 2016, at 12:21, Brent Royal-Gordon <<a href="mailto:brent@architechies.com" class="">brent@architechies.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class=""><blockquote type="cite" class="">Brent, I think it's even slightly more complicated than that. Think e.g. how two subclass instances of NSArray should compare equal even if they've got different types. (I really dislike class inheritance for these reasons, but below is my take on how we could better live with the issue in Swift.)<br class=""></blockquote><br class="">If you're referring to this:<br class=""><br class=""><blockquote type="cite" class=""><blockquote type="cite" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>guard let other = other as? Self else {<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span><span class="Apple-tab-span" style="white-space:pre">        </span>return super == other<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}<br class=""></blockquote></blockquote><br class="">I probably should have said `#Self`, meaning e.g. `NSArray` if you're implementing `NSArray.==`. What you really want to test for there is the *static* type of `self`, not the dynamic type.<br class=""><br class="">If you're referring to the multiple dispatch thing, I actually think that will handle subclassing perfectly well. If you have a class hierarchy like this, with each class implementing its own `(Self, Self)` equality operation:<br class=""><br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>NSObject<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span><span class="Apple-tab-span" style="white-space:pre">        </span>NSArray<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span><span class="Apple-tab-span" style="white-space:pre">        </span><span class="Apple-tab-span" style="white-space:pre">        </span>MyArray<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span><span class="Apple-tab-span" style="white-space:pre">        </span><span class="Apple-tab-span" style="white-space:pre">        </span>MyOtherArray<br class=""><br class="">Then using `==` on `MyArray` and `MyOtherArray` should use `(NSArray, NSArray).==()`, which presumably would compare the length and elements to test for equality.<br class=""></div></div></blockquote><div><br class=""></div><div>It's kind of hard to explain without working code so here's a sample to play with: <a href="http://swiftlang.ng.bluemix.net/#/repl/c1ddd24113169ab82df118660c8e0de6ea24e48d32997c327638a88dc686e91f" class="">http://swiftlang.ng.bluemix.net/#/repl/c1ddd24113169ab82df118660c8e0de6ea24e48d32997c327638a88dc686e91f</a>. Use the `#if true` line to toggle between the implementations. The core of the issue—which I think will also happen if we ever gain the ability to "open" existentials—is at the point where we cast the right-hand side to Self:</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">struct</span><span style="font-variant-ligatures: no-common-ligatures" class=""> AnyEquatable : </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">Equatable</span><span style="font-variant-ligatures: no-common-ligatures" class=""> {</span></div></div></div></div><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> value: </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Any</span></div></div></div></div><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> isEqual: (</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">AnyEquatable</span><span style="font-variant-ligatures: no-common-ligatures" class="">) -> </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Bool</span></div></div></div></div><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">init</span><span style="font-variant-ligatures: no-common-ligatures" class=""><T : </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">Equatable</span><span style="font-variant-ligatures: no-common-ligatures" class="">>(</span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">_</span><span style="font-variant-ligatures: no-common-ligatures" class=""> value: </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">T</span><span style="font-variant-ligatures: no-common-ligatures" class="">) {</span></div></div></div></div><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">self</span><span style="font-variant-ligatures: no-common-ligatures" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">value</span><span style="font-variant-ligatures: no-common-ligatures" class=""> = value</span></div></div></div></div><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">self</span><span style="font-variant-ligatures: no-common-ligatures" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">isEqual</span><span style="font-variant-ligatures: no-common-ligatures" class=""> = {r </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">in</span></div></div></div></div><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">guard</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> other = r.</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">value</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">as</span><span style="font-variant-ligatures: no-common-ligatures" class="">? </span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">T</span><span style="font-variant-ligatures: no-common-ligatures" class="">.EqualSelf </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">else</span><span style="font-variant-ligatures: no-common-ligatures" class=""> { </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">return</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">false</span><span style="font-variant-ligatures: no-common-ligatures" class=""> }</span></div></div></div></div><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">return</span><span style="font-variant-ligatures: no-common-ligatures" class=""> value </span><span style="font-variant-ligatures: no-common-ligatures; color: #31595d" class="">==</span><span style="font-variant-ligatures: no-common-ligatures" class=""> other</span></div></div></div></div><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> }</span></div></div></div></div><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> }</span></div></div></div></div><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div></div></div></div><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal; min-height: 13px;" class=""><br class=""></div></div></div></div><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal; color: rgb(79, 129, 135);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">func</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> == (l: </span><span style="font-variant-ligatures: no-common-ligatures" class="">AnyEquatable</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class="">, r: </span><span style="font-variant-ligatures: no-common-ligatures" class="">AnyEquatable</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class="">) -> </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Bool</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> {</span></div></div></div></div><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">return</span><span style="font-variant-ligatures: no-common-ligatures" class=""> l.</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">isEqual</span><span style="font-variant-ligatures: no-common-ligatures" class="">(r)</span></div></div></div></div><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div></div></div></div></blockquote><div><div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><div style="margin: 0px; line-height: normal; min-height: 13px;" class=""><br class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span></div></div></div></div><div><div>See the cast `<span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class="">r.</span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);" class="">value</span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class=""> </span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);" class="">as</span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class="">? </span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);" class="">T</span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class="">.EqualSelf</span>`, or `<span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class="">r.</span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);" class="">value</span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class=""> </span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);" class="">as</span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class="">? </span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures; color: rgb(79, 129, 135);" class="">T</span>` like it would go for the stdlib Equatable. When `T` is MyArray or MyOtherArray and the erased type of `r.value` is not, the cast will fail.</div><br class=""><blockquote type="cite" class=""><div class=""><div class=""><blockquote type="cite" class="">For the very example of Equatable and Foundation classes, we would get the right behaviour for NSObject's `isEqual` by changing the definition of Equatable into:<br class=""><br class=""> protocol Equatable {<br class=""> associatedtype EqualSelf = Self // the default is ok pretty much always<br class=""> func == (lhs: Self, rhs: EqualSelf) -> Bool<br class=""> func != (lhs: Self, rhs: EqualSelf) -> Bool<br class=""> }<br class=""><br class="">This way, the compiler would always be looking for the `(Self, NSObject) -> Bool` shape of operation, which actually picks up statically the correct overload for `lhs.isEqual(rhs)`.<br class=""></blockquote><br class="">But you would need to do this for all operators. A protocol that requires `<` or `+` would need to de-privilege the right-hand side in exactly the same way.<br class=""></div></div></blockquote></div><div class=""><br class=""></div>That's true. Maybe if we want to take this issue into account we should name `EqualSelf` more generally. Or then we can just shrug away the problem and document it. It's not something I tend to face in real work, partly because I try to avoid inheritance as much as possible, but I know it's there.<br class=""><div class=""><br class=""></div><div class="">— Pyry</div><div class=""><br class=""></div></body></html>