<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="">The&nbsp;<a href="https://en.wikipedia.org/wiki/Liskov_substitution_principle" 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><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 16:28, 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">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-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: 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-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: 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-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: 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-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: 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-variant-ligatures: normal; font-variant-position: normal; font-variant-caps: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: 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="h5">
<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=""></body></html>