<div dir="ltr">Yeah guys, you are right, my code is busted, I was trying to point something different out:<div><br></div><div>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><br></div><div>If you don't override the equal method and you just invoke your super class equality method you'll get something like this: </div><div><br></div><div>```</div><div>class Superclass : Equatable {</div><div><div><div> let foo: Int</div><div> </div><div> init(foo: Int) { self.foo = foo }</div><div> </div><div> func equal(to: Superclass) -> Bool {</div><div> return foo == to.foo</div><div> }</div><div> </div><div> static func == (lhs: Superclass, rhs: Superclass) -> Bool {</div><div> return lhs.equal(to: rhs)</div><div> }</div><div>}</div><div><br></div><div>class Subclass: Superclass {</div><div> let bar: Int</div><div> init(foo: Int, bar: Int) {</div><div> self.bar = bar</div><div> super.init(foo: foo)</div><div> }</div><div> </div><div> func equal(to: Subclass) -> Bool {</div><div> return bar == to.bar && super.equal(to: to)</div><div> }</div><div> </div><div> static func == (lhs: Subclass, rhs: Subclass) -> Bool {</div><div> return lhs.equal(to: rhs)</div><div> }</div><div>}</div><div><br></div><div>class SubclassWithDifferentOperator: Subclass {</div><div> static func != (lhs: SubclassWithDifferentOperator, rhs: SubclassWithDifferentOperator) -> Bool {</div><div> return !(lhs.equal(to: rhs))</div><div> }</div><div>}</div><div><br></div><div>let a = Subclass(foo: 1, bar: 1)</div><div>let b = Subclass(foo: 1, bar: 2)</div><div><br></div><div>(a == b) != (a != b) // Prints: false, not expected</div><div><br></div><div>let x = SubclassWithDifferentOperator(foo: 1, bar: 1)</div><div>let y = SubclassWithDifferentOperator(foo: 1, bar: 2)</div><div><br></div><div>(x == y) != (x != y) // Prints: true, expected</div></div></div><div>```</div><div><br></div><div>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><br></div><div>What I cannot understand is why is not using `func == (Subclass, Subclass)`</div><div><br></div><div>I hope it makes more sense now.</div><div><br></div><div>---</div><div>Fran Fernandez</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jan 18, 2017 at 6:13 PM, Tony Allevato <span dir="ltr"><<a href="mailto:tony.allevato@gmail.com" target="_blank">tony.allevato@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">This seems to work for me:<div><br></div><div>```</div><div><div>class Super: Equatable { </div><div> let x: Int</div><div> init(x: Int) {</div><div> self.x = x</div><div> }</div><div> func equals(_ rhs: Super) -> Bool { </div><div> return x == rhs.x </div><div> } </div><div> static func ==(lhs: Super, rhs: Super) -> Bool { </div><div> return lhs.equals(rhs) </div><div> } </div><div>} </div><div><br></div><div>class Sub: Super {</div><div> let y: Int</div><div> init(x: Int, y: Int) {</div><div> self.y = y</div><div> super.init(x: x)</div><div> }</div><div> override func equals(_ rhs: Super) -> Bool {</div><div> if let rhs = rhs as? Sub {</div><div> return y == rhs.y && super.equals(rhs)</div><div> }</div><div> return false</div><div> } </div><div>}</div><div><br></div><div>let a = Sub(x: 1, y: 1)</div><div>let b = Sub(x: 1, y: 2)</div><div>let c = Sub(x: 1, y: 1)</div></div><div><br></div><div>a == b // false, expected</div><div>a == c // true, expected</div><div>a != b // true, expected</div><div>a != c // false, expected</div><div>```</div><div><br></div><div>Additionally, when I made the change Joe suggested, your code also worked, so maybe there was an error when you updated it?</div><div><br></div><div>FWIW, the default implementation of != just invokes !(a == b) <<a href="https://github.com/apple/swift/blob/master/stdlib/public/core/Equatable.swift#L179-L181" target="_blank">https://github.com/apple/<wbr>swift/blob/master/stdlib/<wbr>public/core/Equatable.swift#<wbr>L179-L181</a>>, 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><br></div><div><br></div><br><div class="gmail_quote"><div><div class="h5"><div dir="ltr">On Wed, Jan 18, 2017 at 8:52 AM Francisco Javier Fernández Toro via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:<br></div></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="h5"><div dir="ltr" class="m_4931755600843731047gmail_msg">Thank you for your answer Joe,<div class="m_4931755600843731047gmail_msg"><br class="m_4931755600843731047gmail_msg"></div><div class="m_4931755600843731047gmail_msg">you are right the <font face="monospace, monospace" class="m_4931755600843731047gmail_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_4931755600843731047gmail_msg"><br class="m_4931755600843731047gmail_msg"></div><div class="m_4931755600843731047gmail_msg"><br class="m_4931755600843731047gmail_msg"></div><div class="m_4931755600843731047gmail_msg"></div></div><div dir="ltr" class="m_4931755600843731047gmail_msg"><div class="m_4931755600843731047gmail_msg"><div class="m_4931755600843731047gmail_msg"><font face="monospace, monospace" class="m_4931755600843731047gmail_msg">let a = Subclass(foo: 1, bar: 1)</font></div><div class="m_4931755600843731047gmail_msg"><font face="monospace, monospace" class="m_4931755600843731047gmail_msg">let b = Subclass(foo: 1, bar: 2)</font></div><div class="m_4931755600843731047gmail_msg"><font face="monospace, monospace" class="m_4931755600843731047gmail_msg"><br class="m_4931755600843731047gmail_msg"></font></div></div></div><div dir="ltr" class="m_4931755600843731047gmail_msg"><div class="m_4931755600843731047gmail_msg"><div class="m_4931755600843731047gmail_msg"><font face="monospace, monospace" class="m_4931755600843731047gmail_msg">(a == b) != (a != b) // Prints true</font></div></div></div><div dir="ltr" class="m_4931755600843731047gmail_msg"><div class="m_4931755600843731047gmail_msg"><div class="m_4931755600843731047gmail_msg"><font face="monospace, monospace" class="m_4931755600843731047gmail_msg"><br class="m_4931755600843731047gmail_msg"></font></div><div class="m_4931755600843731047gmail_msg"><font face="monospace, monospace" class="m_4931755600843731047gmail_msg">let x = SubclassWithDifferentOperator(<wbr>foo: 1, bar: 1)</font></div><div class="m_4931755600843731047gmail_msg"><font face="monospace, monospace" class="m_4931755600843731047gmail_msg">let y = SubclassWithDifferentOperator(<wbr>foo: 1, bar: 2)</font></div><div class="m_4931755600843731047gmail_msg"><font face="monospace, monospace" class="m_4931755600843731047gmail_msg"><br class="m_4931755600843731047gmail_msg"></font></div></div></div><div dir="ltr" class="m_4931755600843731047gmail_msg"><div class="m_4931755600843731047gmail_msg"><div class="m_4931755600843731047gmail_msg"><font face="monospace, monospace" class="m_4931755600843731047gmail_msg">(x == y) != (x != y) // Prints false</font></div><div class="m_4931755600843731047gmail_msg"><br class="m_4931755600843731047gmail_msg"></div><div class="m_4931755600843731047gmail_msg">As you can see above if a subclass does not implement the global function <font face="monospace, monospace" class="m_4931755600843731047gmail_msg">!=</font>, the equal operation seems to be broken.</div><div class="m_4931755600843731047gmail_msg"><br class="m_4931755600843731047gmail_msg"></div><div class="m_4931755600843731047gmail_msg">---</div><div class="m_4931755600843731047gmail_msg"><br class="m_4931755600843731047gmail_msg"></div><div class="m_4931755600843731047gmail_msg">Fran Fernandez</div></div></div><div dir="ltr" class="m_4931755600843731047gmail_msg"><div class="m_4931755600843731047gmail_msg"><div class="gmail_extra m_4931755600843731047gmail_msg"><br class="m_4931755600843731047gmail_msg"><div class="gmail_quote m_4931755600843731047gmail_msg">On Wed, Jan 18, 2017 at 5:44 PM, Joe Groff <span dir="ltr" class="m_4931755600843731047gmail_msg"><<a href="mailto:jgroff@apple.com" class="m_4931755600843731047gmail_msg" target="_blank">jgroff@apple.com</a>></span> wrote:<br class="m_4931755600843731047gmail_msg"><blockquote class="gmail_quote m_4931755600843731047gmail_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_4931755600843731047m_2457570553868603841gmail- m_4931755600843731047gmail_msg"><br class="m_4931755600843731047gmail_msg">
> On Jan 18, 2017, at 2:59 AM, Francisco Javier Fernández Toro via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="m_4931755600843731047gmail_msg" target="_blank">swift-evolution@swift.org</a>> wrote:<br class="m_4931755600843731047gmail_msg">
><br class="m_4931755600843731047gmail_msg">
> Hi,<br class="m_4931755600843731047gmail_msg">
><br class="m_4931755600843731047gmail_msg">
> 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_4931755600843731047gmail_msg">
><br class="m_4931755600843731047gmail_msg">
> If you don't define you own subclass != operator, Swift compiler will use the super class to resolve that operation.<br class="m_4931755600843731047gmail_msg">
><br class="m_4931755600843731047gmail_msg">
> Is there any reason for that?<br class="m_4931755600843731047gmail_msg">
<br class="m_4931755600843731047gmail_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_4931755600843731047gmail_msg">
<span class="m_4931755600843731047m_2457570553868603841gmail- m_4931755600843731047gmail_msg"><br class="m_4931755600843731047gmail_msg">
class Subclass: Superclass {<br class="m_4931755600843731047gmail_msg">
let bar: Int<br class="m_4931755600843731047gmail_msg">
init(foo: Int, bar: Int) {<br class="m_4931755600843731047gmail_msg">
self.bar = bar<br class="m_4931755600843731047gmail_msg">
super.init(foo: foo)<br class="m_4931755600843731047gmail_msg">
}<br class="m_4931755600843731047gmail_msg">
<br class="m_4931755600843731047gmail_msg">
</span> override func equal(to: Superclass) -> Bool {<br class="m_4931755600843731047gmail_msg">
if let toSub = to as? Subclass {<br class="m_4931755600843731047gmail_msg">
return bar == toSub.bar && super.equal(to: to)<br class="m_4931755600843731047gmail_msg">
}<br class="m_4931755600843731047gmail_msg">
return false<br class="m_4931755600843731047gmail_msg">
}<br class="m_4931755600843731047gmail_msg">
}<br class="m_4931755600843731047gmail_msg">
<br class="m_4931755600843731047gmail_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_4931755600843731047gmail_msg" target="_blank">bugs.swift.org</a> about that?<br class="m_4931755600843731047gmail_msg">
<span class="m_4931755600843731047m_2457570553868603841gmail-HOEnZb m_4931755600843731047gmail_msg"><font color="#888888" class="m_4931755600843731047gmail_msg"><br class="m_4931755600843731047gmail_msg">
-Joe</font></span></blockquote></div><br class="m_4931755600843731047gmail_msg"></div></div></div></div></div><span class="">
______________________________<wbr>_________________<br class="m_4931755600843731047gmail_msg">
swift-evolution mailing list<br class="m_4931755600843731047gmail_msg">
<a href="mailto:swift-evolution@swift.org" class="m_4931755600843731047gmail_msg" target="_blank">swift-evolution@swift.org</a><br class="m_4931755600843731047gmail_msg">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" class="m_4931755600843731047gmail_msg" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br class="m_4931755600843731047gmail_msg">
</span></blockquote></div></div>
</blockquote></div><br></div>