<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=""><div class="">This is incorrect. If I have a Set&lt;Fruit&gt;, I should expect that the set may contain Apples and Bananas. If you really want a different hash value, the parent equality function has to be conservative and say that the different types are different. But that’s <i class="">your</i>&nbsp;choice, because <i class="">you</i>&nbsp;wrote the implementation of Equatable for the base class. (And if you <i class="">didn’t,</i>&nbsp;then you should be concerned, because any functions that came with the base class will assume the Apple and the Banana are interchangeable.)</div><div class=""><br class=""></div><div class="">Remember, hashValue can return 0 for all instances and still be correct. The implications only work one way.</div><div class=""><br class=""></div><div class="">if a == b, then a.hashValue == b.hashValue</div><div class="">if a != b, then we know nothing about the hash values</div><div class="">if a.hashValue == b.hashValue, then we know nothing about a == b</div><div class="">if a.hashValue != b.hashValue, a != b</div><div class=""><br class=""></div><div class="">I’ll finish by repeating what I said earlier: if you plan to have a base class be Equatable, you need to design your == in such a way that it makes sense for subclasses. If you can’t do that, you either can’t be Equatable or can’t allow subclasses, or common uses of the standard library will break. How you <i class="">want</i>&nbsp;it work doesn’t matter if you don’t control ==.</div><div class=""><br class=""></div><div class="">Jordan</div><div class=""><br class=""></div><br class=""><div><blockquote type="cite" class=""><div class="">On Sep 1, 2016, at 22:50, Zhao Xin &lt;<a href="mailto:owenzx@gmail.com" class="">owenzx@gmail.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class="gmail_default" style="font-family:georgia,serif">No. I don't think what you so called principle should be applied here. For example, I have a `class Fruit`, then I have a `class Apple:Fruit`. If they are using different `hashValue` generating method, you suggest me to use composition instead of inheritance?</div><div class="gmail_default" style="font-family:georgia,serif"><br class=""></div><div class="gmail_default" style="font-family:georgia,serif">Also, it is very common for subclass to override super class `hashValue`. Supposing opposite, if we also have another class called `class Banana:Fruit`, we may get the result that an `Apple` is equals to a `Banana`, using `Fruit`, &nbsp;just because they have the same `hashValue`.</div><div class="gmail_default" style="font-family:georgia,serif"><br class=""></div><div class="gmail_default" style="font-family:georgia,serif">If we stick to the super class `hashValue`, we may also not get the differences between instances of a certain subclass. For example, we may get the result that a `redApple` equals to a `greenApple`.</div><div class="gmail_default" style="font-family:georgia,serif"><br class=""></div><div class="gmail_default" style="font-family:georgia,serif">So in my option, if one instance equals to another instance, the foundation should be that the `type(of:instance)` equals. If you want to enlarge the type to their super class, you need to be careful, as they are not guaranteed automatically.</div><div class="gmail_default" style="font-family:georgia,serif"><br class=""></div><div class="gmail_default" style="font-family:georgia,serif">Zhaoxin</div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Fri, Sep 2, 2016 at 7:32 AM, Jordan Rose <span dir="ltr" class="">&lt;<a href="mailto:jordan_rose@apple.com" target="_blank" class="">jordan_rose@apple.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 style="word-wrap:break-word" class=""><div class="">The&nbsp;<a href="https://en.wikipedia.org/wiki/Liskov_substitution_principle" target="_blank" class="">Liskov substitution principle</a>&nbsp;says that a B should always be able to be treated like an A. Your Set&lt;A&gt; may <i class="">already</i>&nbsp;contain Bs, even without them ever being statically typed as B. If you think A and B are unrelated types, you should be using composition rather than inheritance.</div><div class=""><br class=""></div><div class="">If a subclass overrides hashValue, they must be in a position to affect == as well, and it must work no matter which object is on the left-hand side. NSObject does this by having == call the isEqual(_:) method, but you still need to design your class hierarchy and isEqual(_:) methods carefully.</div><span class="HOEnZb"><font color="#888888" class=""><div class=""><br class=""></div><div class="">Jordan</div></font></span><div class=""><div class="h5"><div class=""><br class=""></div><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Sep 1, 2016, at 16:28, Zhao Xin &lt;<a href="mailto:owenzx@gmail.com" target="_blank" class="">owenzx@gmail.com</a>&gt; wrote:</div><br class=""><div class=""><div dir="ltr" class=""><div class="gmail_default" style="font-family:georgia,serif">I believe if B inherits A, they are not the same type. So the rule doesn't apply here.</div><div class="gmail_default" style="font-family:georgia,serif"><br class=""></div><div class="gmail_default" style="font-family:georgia,serif">Zhaoxin</div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Fri, Sep 2, 2016 at 7:02 AM, Nick Brook <span dir="ltr" class="">&lt;<a href="mailto:nrbrook@gmail.com" target="_blank" class="">nrbrook@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 style="word-wrap:break-word" class="">Hi Jordan,<div class=""><br class=""></div><div class="">Thanks for the advice.</div><div class=""><br class=""></div><div class="">What if a subclass does implement hashValue differently? It seems you are saying a subclass should never override hashValue? Should Set not compare elements with == instead of hashValue?<br class=""><div class=""><br class=""></div><div class="">
Thanks<br class=""><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important" class="">Nick</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class=""><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class=""><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline!important" class="">M: <a href="tel:%2B44%20%280%297986%20048%20141" value="+447986048141" target="_blank" class="">+44 (0)7986 048 141</a></span><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class="">W:&nbsp;<a href="http://nickbrook.me/" target="_blank" class="">http://nickbrook.me</a></div>
</div><div class=""><div class="">
<br class=""><div class=""><blockquote type="cite" class=""><div class="">On 1 Sep 2016, at 23:55, Jordan Rose &lt;<a href="mailto:jordan_rose@apple.com" target="_blank" class="">jordan_rose@apple.com</a>&gt; wrote:</div><br class=""><div class=""><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class=""><blockquote type="cite" class=""><div class=""><br class="">On Sep 1, 2016, at 15:44, Zhao Xin via swift-users &lt;<a href="mailto:swift-users@swift.org" target="_blank" class="">swift-users@swift.org</a>&gt; wrote:</div><br class=""><div class=""><div dir="ltr" class=""><div class="gmail_default" style="font-family:georgia,serif">Hi Nick,</div><div class="gmail_default" style="font-family:georgia,serif"><br class=""></div><div class="gmail_default" style="font-family:georgia,serif">Glad to help.</div><div class="gmail_default" style="font-family:georgia,serif"><br class=""></div><blockquote class="gmail_quote" 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">but when using third party classes I don’t know if the hash values are comparable<br class=""></blockquote><div class=""><br class=""></div><div class="gmail_default" style="font-family:georgia,serif">You can create an extension with a convenient init(:), which creates a new instance of &nbsp;the super class basing on the instance of the sub class. That will guarantee the subtraction.&nbsp;Below code works in Xcode 7.3.1 with Swift 2.2.<br class=""></div><div class="gmail_default" style="font-family:georgia,serif"><br class=""></div><div class="gmail_default"><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span style="color:rgb(187,44,162)" class="">import</span><span class=""><span class="">&nbsp;</span>Foundation</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal;min-height:13px" class=""><span class=""></span><br class=""></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span style="color:rgb(187,44,162)" class="">func</span><span class=""><span class="">&nbsp;</span>==(lhs:<span class="">&nbsp;</span></span><span style="color:rgb(79,129,135)" class="">Foo</span><span class="">, rhs:<span class="">&nbsp;</span></span><span style="color:rgb(79,129,135)" class="">Foo</span><span class="">) -&gt;<span class="">&nbsp;</span></span><span style="color:rgb(112,61,170)" class="">Bool</span><span class=""><span class="">&nbsp;</span>{</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span class="">&nbsp; &nbsp;<span class="">&nbsp;</span></span><span style="color:rgb(187,44,162)" class="">return</span><span class=""><span class="">&nbsp;</span>lhs.</span><span style="color:rgb(79,129,135)" class="">id</span><span class=""><span class="">&nbsp;</span>== rhs.</span><span style="color:rgb(79,129,135)" class="">id</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span class="">}</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal;min-height:13px" class=""><span class=""></span><br class=""></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal;color:rgb(112,61,170)" class=""><span style="color:rgb(187,44,162)" class="">class</span><span class=""><span class="">&nbsp;</span>Foo:</span><span class="">Hashable</span><span class=""><span class="">&nbsp;</span>{</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span class="">&nbsp; &nbsp;<span class="">&nbsp;</span></span><span style="color:rgb(187,44,162)" class="">let</span><span class=""><span class="">&nbsp;</span>id:</span><span style="color:rgb(112,61,170)" class="">Int</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span class="">&nbsp; &nbsp;<span class="">&nbsp;</span></span><span style="color:rgb(187,44,162)" class="">var</span><span class=""><span class="">&nbsp;</span>hashValue:<span class="">&nbsp;</span></span><span style="color:rgb(112,61,170)" class="">Int</span><span class=""><span class="">&nbsp;</span>{</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span class="">&nbsp; &nbsp; &nbsp; &nbsp;<span class="">&nbsp;</span></span><span style="color:rgb(187,44,162)" class="">return</span><span class=""><span class="">&nbsp;</span></span><span style="color:rgb(79,129,135)" class="">id</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span class="">&nbsp; &nbsp; }</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal;min-height:13px" class=""><span class="">&nbsp; &nbsp;&nbsp;</span><br class=""></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span class="">&nbsp; &nbsp;<span class="">&nbsp;</span></span><span style="color:rgb(187,44,162)" class="">required</span><span class=""><span class="">&nbsp;</span></span><span style="color:rgb(187,44,162)" class="">init</span><span class="">(</span><span style="color:rgb(187,44,162)" class="">_</span><span class=""><span class="">&nbsp;</span>id:</span><span style="color:rgb(112,61,170)" class="">Int</span><span class="">) {</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span class="">&nbsp; &nbsp; &nbsp; &nbsp;<span class="">&nbsp;</span></span><span style="color:rgb(187,44,162)" class="">self</span><span class="">.</span><span style="color:rgb(79,129,135)" class="">id</span><span class=""><span class="">&nbsp;</span>= id</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span class="">&nbsp; &nbsp; }</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span class="">}</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal;min-height:13px" class=""><span class=""></span><br class=""></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span style="color:rgb(187,44,162)" class="">class</span><span class=""><span class="">&nbsp;</span>Bar:</span><span style="color:rgb(79,129,135)" class="">Foo</span><span class=""><span class="">&nbsp;</span>{</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span class="">&nbsp; &nbsp;<span class="">&nbsp;</span></span><span style="color:rgb(187,44,162)" class="">override</span><span class=""><span class="">&nbsp;</span></span><span style="color:rgb(187,44,162)" class="">var</span><span class=""><span class="">&nbsp;</span>hashValue:<span class="">&nbsp;</span></span><span style="color:rgb(112,61,170)" class="">Int</span><span class=""><span class="">&nbsp;</span><wbr class="">{</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span class="">&nbsp; &nbsp; &nbsp; &nbsp;<span class="">&nbsp;</span></span><span style="color:rgb(187,44,162)" class="">return</span><span class=""><span class="">&nbsp;</span></span><span style="color:rgb(79,129,135)" class="">id</span><span class=""><span class="">&nbsp;</span>*<span class="">&nbsp;</span></span><span style="color:rgb(39,42,216)" class="">5</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span class="">&nbsp; &nbsp; }</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span class="">}</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal;min-height:13px" class=""><span class=""></span><br class=""></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span style="color:rgb(187,44,162)" class="">var</span><span class=""><span class="">&nbsp;</span>fooSet:</span><span style="color:rgb(112,61,170)" class="">Set</span><span class="">&lt;</span><span style="color:rgb(79,129,135)" class="">Foo</span><span class="">&gt; = [</span><span style="color:rgb(79,129,135)" class="">Foo</span><span class="">(</span><span style="color:rgb(39,42,216)" class="">10</span><span class="">),<span class="">&nbsp;</span></span><span style="color:rgb(79,129,135)" class="">Foo</span><span class="">(</span><span style="color:rgb(39,42,216)" class="">9</span><span class="">),<span class="">&nbsp;</span></span><span style="color:rgb(79,129,135)" class="">Foo</span><span class="">(</span><span style="color:rgb(39,42,216)" class="">8</span><span class="">),<span class="">&nbsp;</span></span><span style="color:rgb(79,129,135)" class="">Foo</span><span class="">(</span><span style="color:rgb(39,42,216)" class=""><wbr class="">7</span><span class="">)]</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span style="color:rgb(187,44,162)" class="">var</span><span class=""><span class="">&nbsp;</span>barSet:</span><span style="color:rgb(112,61,170)" class="">Set</span><span class="">&lt;</span><span style="color:rgb(79,129,135)" class="">Bar</span><span class="">&gt; = [</span><span style="color:rgb(79,129,135)" class="">Bar</span><span class="">(</span><span style="color:rgb(39,42,216)" class="">8</span><span class="">),<span class="">&nbsp;</span></span><span style="color:rgb(79,129,135)" class="">Bar</span><span class="">(</span><span style="color:rgb(39,42,216)" class="">7</span><span class="">),<span class="">&nbsp;</span></span><span style="color:rgb(79,129,135)" class="">Bar</span><span class="">(</span><span style="color:rgb(39,42,216)" class="">6</span><span class="">),<span class="">&nbsp;</span></span><span style="color:rgb(79,129,135)" class="">Bar</span><span class="">(</span><span style="color:rgb(39,42,216)" class="">5</span><span class=""><wbr class="">)]</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal;min-height:13px" class=""><span class=""></span><br class=""></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal;color:rgb(0,132,0)" class=""><span class="">//fooSet.subtract(barSet) // error: cannot invoke 'subtract' with an argument list of type '(Set&lt;Bar&gt;)'</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal;color:rgb(79,129,135)" class=""><span class="">fooSet</span><span class=""><span class="">&nbsp;</span>=<span class="">&nbsp;</span></span><span class="">fooSet</span><span class="">.</span><span style="color:rgb(61,29,129)" class="">subtract</span><span class="">(</span><span class="">barSe<wbr class="">t</span><span class=""><span class="">&nbsp;</span></span><span style="color:rgb(187,44,162)" class="">as</span><span class=""><span class="">&nbsp;</span></span><span style="color:rgb(112,61,170)" class="">Set</span><span class="">&lt;</span><span class="">Foo</span><span class="">&gt;)&nbsp;</span><span style="color:rgb(0,132,0);font-family:menlo" class="">// works, but not what we want</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal" class=""><span style="color:rgb(79,129,135)" class="">fooSet</span><span class="">.</span><span style="color:rgb(61,29,129)" class="">forEach</span><span class=""><span class="">&nbsp;</span>{<span class="">&nbsp;</span></span><span style="color:rgb(61,29,129)" class="">print</span><span class="">(</span><span style="color:rgb(209,47,27)" class="">"</span><span class="">\</span><span style="color:rgb(209,47,27)" class="">(</span><span class="">$0.</span><span style="color:rgb(187,44,162)" class="">d<wbr class="">ynamicType</span><span style="color:rgb(209,47,27)" class="">), id:</span><span class="">\</span><span style="color:rgb(209,47,27)" class="">(</span><span class="">$0.</span><span style="color:rgb(79,129,135)" class="">id</span><span style="color:rgb(209,47,27)" class="">)"</span><span class="">) }</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal;color:rgb(0,132,0)" class=""><span class="">/*</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal;color:rgb(0,132,0)" class=""><span class="">&nbsp;Foo, id:7</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal;color:rgb(0,132,0)" class=""><span class="">&nbsp;Foo, id:10</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal;color:rgb(0,132,0)" class=""><span class="">&nbsp;Foo, id:9</span></div><div style="font-family:menlo;margin:0px;font-size:11px;line-height:normal;color:rgb(0,132,0)" class=""><span class="">*/</span></div></div></div></div></blockquote><br class=""></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class="">This isn't really a sensible thing to do. The rules for Hashable require that `a == b` implies `a.hashValue == b.hashValue`, and `a.hashValue != b.hashValue` implies `a != b`. If you break these rules you're going to have problems no matter what static types you're using.</div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class=""><br class=""></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class="">Upcasting from Set&lt;Bar&gt; to Set&lt;Foo&gt; is the most concise way to solve this problem.</div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class=""><br class=""></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" class="">Jordan</div></div></blockquote></div><br class=""></div></div></div></div></blockquote></div><br class=""></div>
</div></blockquote></div><br class=""></div></div></div></blockquote></div><br class=""></div>
</div></blockquote></div><br class=""></body></html>