<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="">This is very interesting and all Swift developers will need to be aware of it, if it isn’t a bug.<div class=""><br class=""></div><div class="">One thing that I think is a little worrying is that if, rather than the == operator, you had a CustomEquatable protocol which defined the equal(to:) function, that function would be dynamically dispatched. You would think that operator witnesses should be resolved in the same way.<div class=""><br class=""></div><div class="">I believe that should even work for the dynamic Self; we have already verified at compile-time that an overload exists (even though it may not be the most appropriate one to execute). So you would get:</div><div class=""><br class=""></div><div class="">let a = Sub()</div><div class="">let b = Sub()</div><div class="">let c = Super()</div><div class=""><br class=""></div><div class="">(a as Super) == b // Both values have (dynamic) type Sub, calls ==(Sub,Sub)</div><div class="">a == c &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // One type is not a Sub, must compare using ==(Super, Super)</div><div class=""><br class=""></div><div class=""><div class="">- Krl</div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On 20 Jan 2017, at 20:24, Pierre Monod-Broca via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="content-type" content="text/html; charset=utf-8" class=""><div dir="auto" class=""><div class="">The way I understand it, it's a bad idea to override == and != (or any infix operator) for Sub if Super has them and that's why the default implementation from Equatable only generates !=(Super, Super) and not !=(Sub, Sub) (and there is no ==(Sub, Sub) generated either).</div><div class=""><br class=""></div><div class="">And it's a bad idea because (without dynamic dispatch on both operands) it leads to unexpected behavior.</div><div class=""><br class=""></div><div class="">Considering :</div><div class="">```</div><div class="">func ==(lhs: Super, rhs: Super) -&gt; Bool {</div><div class="">&nbsp; &nbsp; print("Super")</div><div class="">&nbsp; &nbsp; return true</div><div class="">}</div><div class=""><br class=""></div><div class="">func ==(lhs: Sub, rhs: Sub) -&gt; Bool {</div><div class="">&nbsp; &nbsp; print("Sub")</div><div class="">&nbsp; &nbsp; return false</div><div class="">}</div><div class=""><br class=""></div><div class="">let a = Sub()</div><div class="">let b = Sub()</div><div class="">a == b // Sub</div><div class="">a as Super == b // Super</div><div class="">a == b as Super // Super</div><div class="">à as Super == b as Super // Super</div><div class="">```</div><div class=""><br class=""></div><div class="">One would compare the same objects and don't get the same result.</div><div class=""><br class=""></div><div class=""><div class=""><span style="background-color: rgba(255, 255, 255, 0);" class="">Instead you have to check the dynamic type yourself.</span></div></div><div class=""><br class=""></div><div class=""><br class=""><div class="">Pierre</div></div><div class=""><br class="">Le 20 janv. 2017 à 10:45, Francisco Javier Fernández Toro via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; a écrit&nbsp;:<br class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><br class=""><div class="gmail_extra"><br class=""><div class="gmail_quote">On Wed, Jan 18, 2017 at 6:58 PM, Tony Allevato <span dir="ltr" class="">&lt;<a href="mailto:tony.allevato@gmail.com" target="_blank" class="">tony.allevato@gmail.com</a>&gt;</span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="">Ok, this actually does feel a bit strange. The behavior you're seeing seems to be a consequence of [SE-0091](<a href="https://github.com/apple/swift-evolution/blob/master/proposals/0091-improving-operators-in-protocols.md" target="_blank" class="">https://github.com/<wbr class="">apple/swift-evolution/blob/<wbr class="">master/proposals/0091-<wbr class="">improving-operators-in-<wbr class="">protocols.md</a>), but it looks like you're seeing different behavior than what I described in the "Class types and inheritance" section of that proposal.<div class=""><br class=""></div><div class="">If Sub has `==(Sub, Sub)` implemented as a *static* function, I just tried it and it's *ignored* (`==(Super, Super)` gets called instead), even when the two actual arguments are known to be statically of type Sub. I think this is because of the way that proposal was implemented: when it sees that `Sub` extends `Super`, which conforms to `Equatable`, it appears that it's only looking for static overloads of `==` that are satisfied at the *point of conformance*, which would be `==(Super, Super)` (because `Super` conforms to `Equatable where Self == Super`). The wording of the proposal makes this case: "Then, we say that we do not consider an operator function if it implements a protocol requirement, because the requirement is a generalization of all of the operator functions that satisfy that requirement."</div><div class=""><br class=""></div><div class="">Contrarily, if you provide `==(Sub, Sub)` as a global function instead of a static one, it *does* get called. I think in this case, the type checker gets the whole set of candidate operators (which, unlike above, includes the global `==(Sub, Sub)`), and it gets used because it's a more specific match?</div><div class=""><br class=""></div></div></blockquote><div class=""><br class=""></div><div class="">FWIW, I've just changed both `==` functions to make them global, the the outcome is still the same, its using `==(Super,Super)` to resolve `!=(Sub,Sub)</div><div class="">&nbsp;</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class=""><div class=""></div><div class="">Can someone from the core team chime in and say whether this is intentional behavior? It feels wrong that simply changing the location where the operator is defined would change the behavior like this.</div><div class=""><br class=""></div><div class="">FWIW, to avoid these sharp edges, there's no need to implement `==` for subtypes; since you have to use an overridable `equals` method anyway, just have the base type implement `==` to delegate to it, and then have subtypes override `equals` alone.</div><div class=""><br class=""></div></div><div class="HOEnZb"><div class="h5"><br class=""><div class="gmail_quote"><div dir="ltr" class="">On Wed, Jan 18, 2017 at 9:36 AM Francisco Javier Fernández Toro &lt;<a href="mailto:fran@gokarumi.com" target="_blank" class="">fran@gokarumi.com</a>&gt; wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="m_-808359227615273680gmail_msg">Yeah guys, you are right, my code is busted, I was trying to point something different out:<div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">The next code is showing the possible issue. In theory to make a class Equatable, you just have to mark it with the Equatable protocol and implement `==` as a static function or as a global one.</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">If you don't override the equal method and you just invoke your super class equality method you'll get something like this:&nbsp;</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">```</div><div class="m_-808359227615273680gmail_msg">class Superclass : Equatable {</div><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"></div></div></div><div dir="ltr" class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; let foo: Int</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp;&nbsp;</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; init(foo: Int) { self.foo = foo }</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp;&nbsp;</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; func equal(to: Superclass) -&gt; Bool {</div></div></div></div><div dir="ltr" class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; return foo == to.foo</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; }</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp;&nbsp;</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; static func == (lhs: Superclass, rhs: Superclass) -&gt; Bool {</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; return lhs.equal(to: rhs)</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; }</div><div class="m_-808359227615273680gmail_msg">}</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div></div></div></div><div dir="ltr" class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg">class Subclass: Superclass {</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; let bar: Int</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; init(foo: Int, bar: Int) {</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; self.bar = bar</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; super.init(foo: foo)</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; }</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp;&nbsp;</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; func equal(to: Subclass) -&gt; Bool {</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; return bar == to.bar &amp;&amp; super.equal(to: to)</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; }</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp;&nbsp;</div></div></div></div><div dir="ltr" class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; static func == (lhs: Subclass, rhs: Subclass) -&gt; Bool {</div></div></div></div><div dir="ltr" class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; return lhs.equal(to: rhs)</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; }</div><div class="m_-808359227615273680gmail_msg">}</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">class SubclassWithDifferentOperator: Subclass {</div></div></div></div><div dir="ltr" class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; static func != (lhs: SubclassWithDifferentOperator, rhs: SubclassWithDifferentOperator) -&gt; Bool {</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; return !(lhs.equal(to: rhs))</div></div></div></div><div dir="ltr" class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; }</div><div class="m_-808359227615273680gmail_msg">}</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">let a = Subclass(foo: 1, bar: 1)</div><div class="m_-808359227615273680gmail_msg">let b = Subclass(foo: 1, bar: 2)</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div></div></div></div><div dir="ltr" class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg">(a == b) != (a != b) // Prints: false, not expected</div></div></div></div><div dir="ltr" class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">let x = SubclassWithDifferentOperator(<wbr class="">foo: 1, bar: 1)</div><div class="m_-808359227615273680gmail_msg">let y = SubclassWithDifferentOperator(<wbr class="">foo: 1, bar: 2)</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div></div></div></div><div dir="ltr" class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg">(x == y) != (x != y) // Prints: true, expected</div></div></div><div class="m_-808359227615273680gmail_msg">```</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">So, after adding a couple of `print` statement in those equal method what I can see is that for Subclass, when you are need to call `!=` what Swift is doing is using `func ==(Superclass, Superclass)` and apply `!` as Tony has pointed out.</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">What I cannot understand is why is not using `func == (Subclass, Subclass)`</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">I hope it makes more sense now.</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">---</div><div class="m_-808359227615273680gmail_msg">Fran Fernandez</div></div><div class="gmail_extra m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"><div class="gmail_quote m_-808359227615273680gmail_msg">On Wed, Jan 18, 2017 at 6:13 PM, Tony Allevato <span dir="ltr" class="m_-808359227615273680gmail_msg">&lt;<a href="mailto:tony.allevato@gmail.com" class="m_-808359227615273680gmail_msg" target="_blank">tony.allevato@gmail.com</a>&gt;</span> wrote:<br class="m_-808359227615273680gmail_msg"><blockquote class="gmail_quote m_-808359227615273680gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="m_-808359227615273680gmail_msg">This seems to work for me:<div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">```</div><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg">class Super: Equatable {&nbsp;</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; let x: Int</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; init(x: Int) {</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; self.x = x</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; }</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; func equals(_ rhs: Super) -&gt; Bool {&nbsp;</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; return x == rhs.x&nbsp;</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; }&nbsp;</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; static func ==(lhs: Super, rhs: Super) -&gt; Bool {&nbsp;</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; return lhs.equals(rhs)&nbsp;</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; }&nbsp;</div><div class="m_-808359227615273680gmail_msg">}&nbsp;</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">class Sub: Super {</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; let y: Int</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; init(x: Int, y: Int) {</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; self.y = y</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; super.init(x: x)</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; }</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; override func equals(_ rhs: Super) -&gt; Bool {</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; if let rhs = rhs as? Sub {</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return y == rhs.y &amp;&amp; super.equals(rhs)</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; &nbsp; &nbsp; return false</div><div class="m_-808359227615273680gmail_msg">&nbsp; &nbsp; } &nbsp;&nbsp;</div><div class="m_-808359227615273680gmail_msg">}</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">let a = Sub(x: 1, y: 1)</div><div class="m_-808359227615273680gmail_msg">let b = Sub(x: 1, y: 2)</div><div class="m_-808359227615273680gmail_msg">let c = Sub(x: 1, y: 1)</div></div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">a == b &nbsp;// false, expected</div><div class="m_-808359227615273680gmail_msg">a == c &nbsp;// true, expected</div><div class="m_-808359227615273680gmail_msg">a != b &nbsp;// true, expected</div><div class="m_-808359227615273680gmail_msg">a != c &nbsp;// false, expected</div><div class="m_-808359227615273680gmail_msg">```</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">Additionally, when I made the change Joe suggested, your code also worked, so maybe there was an error when you updated it?</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg">FWIW, the default implementation of != just invokes !(a == b) &lt;<a href="https://github.com/apple/swift/blob/master/stdlib/public/core/Equatable.swift#L179-L181" class="m_-808359227615273680gmail_msg" target="_blank">https://github.com/apple/<wbr class="">swift/blob/master/stdlib/<wbr class="">public/core/Equatable.swift#<wbr class="">L179-L181</a>&gt;, so I believe it's *impossible* (well, uh, barring busted RAM or processor I guess) for it to return the wrong value for the same arguments if you only implement ==.</div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680gmail_msg"><br class="m_-808359227615273680gmail_msg"></div><br class="m_-808359227615273680gmail_msg"><div class="gmail_quote m_-808359227615273680gmail_msg"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680m_-4542951819186758422h5 m_-808359227615273680gmail_msg"><div dir="ltr" class="m_-808359227615273680gmail_msg">On Wed, Jan 18, 2017 at 8:52 AM Francisco Javier Fernández Toro via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="m_-808359227615273680gmail_msg" target="_blank">swift-evolution@swift.org</a>&gt; wrote:<br class="m_-808359227615273680gmail_msg"></div></div></div><blockquote class="gmail_quote m_-808359227615273680gmail_msg" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="m_-808359227615273680gmail_msg"><div class="m_-808359227615273680m_-4542951819186758422h5 m_-808359227615273680gmail_msg"><div dir="ltr" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">Thank you for your answer Joe,<div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">you are right the <font face="monospace, monospace" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">equal(to:)</font> wasn't a valid override, but even after using the one you've proposed, the behavior is not the expected one</div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"></div></div><div dir="ltr" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><font face="monospace, monospace" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">let a = Subclass(foo: 1, bar: 1)</font></div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><font face="monospace, monospace" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">let b = Subclass(foo: 1, bar: 2)</font></div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><font face="monospace, monospace" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"></font></div></div></div><div dir="ltr" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><font face="monospace, monospace" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">(a == b) != (a != b) // Prints true</font></div></div></div><div dir="ltr" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><font face="monospace, monospace" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"></font></div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><font face="monospace, monospace" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">let x = SubclassWithDifferentOperator(<wbr class="">foo: 1, bar: 1)</font></div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><font face="monospace, monospace" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">let y = SubclassWithDifferentOperator(<wbr class="">foo: 1, bar: 2)</font></div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><font face="monospace, monospace" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"></font></div></div></div><div dir="ltr" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><font face="monospace, monospace" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">(x == y) != (x != y) // Prints false</font></div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">As you can see above if a subclass does not implement the global function <font face="monospace, monospace" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">!=</font>, the equal operation seems to be broken.</div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">---</div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"></div><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">Fran Fernandez</div></div></div><div dir="ltr" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><div class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><div class="gmail_extra m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><div class="gmail_quote m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">On Wed, Jan 18, 2017 at 5:44 PM, Joe Groff <span dir="ltr" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">&lt;<a href="mailto:jgroff@apple.com" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg" target="_blank">jgroff@apple.com</a>&gt;</span> wrote:<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><blockquote class="gmail_quote m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047m_2457570553868603841gmail- m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&gt; On Jan 18, 2017, at 2:59 AM, Francisco Javier Fernández Toro via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg" target="_blank">swift-evolution@swift.org</a>&gt; wrote:<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&gt;<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&gt; Hi,<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&gt;<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&gt; I've found that when you have a class hierarchy which implements Equatable, if you want to have the != operator working as expected, you need to override it, it's not enough with ==.<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&gt;<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&gt; If you don't define you own subclass != operator, Swift compiler will use the super class to resolve that operation.<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&gt;<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&gt; Is there any reason for that?<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
</span>The `equal(to:)` method inside `Subclass` is not a valid override of `Superclass` because its argument only accepts `Subclass` instances, but the parent method needs to work with all `Superclass` instances. If you write it as an override, it should work:<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
<span class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047m_2457570553868603841gmail- m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
class Subclass: Superclass {<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&nbsp; &nbsp; let bar: Int<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&nbsp; &nbsp; init(foo: Int, bar: Int) {<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&nbsp; &nbsp; &nbsp; &nbsp; self.bar = bar<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&nbsp; &nbsp; &nbsp; &nbsp; super.init(foo: foo)<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&nbsp; &nbsp; }<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
</span>&nbsp; &nbsp; override func equal(to: Superclass) -&gt; Bool {<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&nbsp; &nbsp; &nbsp; if let toSub = to as? Subclass {<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&nbsp; &nbsp; &nbsp; &nbsp; return bar == toSub.bar &amp;&amp; super.equal(to: to)<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&nbsp; &nbsp; &nbsp; }<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&nbsp; &nbsp; &nbsp; return false<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
&nbsp; &nbsp; }<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
}<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
We should probably raise an error, or at least a warning, instead of silently accepting your code as an overload. Would you be able to file a bug on <a href="http://bugs.swift.org/" rel="noreferrer" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg" target="_blank">bugs.swift.org</a> about that?<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
<span class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg m_-808359227615273680m_-4542951819186758422m_4931755600843731047m_2457570553868603841gmail-HOEnZb"><font color="#888888" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
-Joe</font></span></blockquote></div><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg"></div></div></div></div></div><span class="m_-808359227615273680gmail_msg">
______________________________<wbr class="">_________________<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
swift-evolution mailing list<br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
<a href="mailto:swift-evolution@swift.org" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg" target="_blank">swift-evolution@swift.org</a><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg" target="_blank">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-<wbr class="">evolution</a><br class="m_-808359227615273680m_-4542951819186758422m_4931755600843731047gmail_msg m_-808359227615273680gmail_msg">
</span></blockquote></div></div>
</blockquote></div><br class="m_-808359227615273680gmail_msg"></div>
</blockquote></div>
</div></div></blockquote></div><br class=""></div></div>
</div></blockquote><blockquote type="cite" class=""><div class=""><span class="">_______________________________________________</span><br class=""><span class="">swift-evolution mailing list</span><br class=""><span class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a></span><br class=""><span class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span><br class=""></div></blockquote></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></div></div></div></body></html>