<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Thu, Dec 17, 2015 at 2:17 PM, Etan Kissling via swift-users <span dir="ltr"><<a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div style="word-wrap:break-word">
I want to use instances of a custom class as Dictionary key.
<div>This requires the class to conform to Hashable.</div>
<div><br>
</div>
<div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">func</span> ==(lhs:
<span style="color:#4f8187">
KeyType1</span>, rhs: <span style="color:#4f8187">
KeyType1</span>) -> <span style="color:#703daa">
Bool</span> { <span style="color:#bb2ca2">
return</span> lhs.<span style="color:#4f8187">id</span> == rhs.<span style="color:#4f8187">id</span> }</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px">
<br>
</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)">
<span style="color:#bb2ca2">final</span><span style="color:#000000">
</span><span style="color:#bb2ca2">class</span><span style="color:#000000"> KeyType1:
</span>Hashable<span style="color:#000000">,
</span>CustomStringConvertible<span style="color:#000000"> {</span></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">
let</span> id: <span style="color:#703daa">
String</span></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">
init</span>(id: <span style="color:#703daa">
String</span>) { <span style="color:#bb2ca2">
self</span>.<span style="color:#4f8187">id</span> = id }</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">
var</span> hashValue: <span style="color:#703daa">
Int</span> { <span style="color:#bb2ca2">
return</span> <span style="color:#4f8187">
id</span>.<span style="color:#703daa">hashValue</span> }</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">
var</span> description: <span style="color:#703daa">
String</span> { <span style="color:#bb2ca2">
return</span> <span style="color:#4f8187">
id </span>}</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
}</div>
</div>
<div><br>
</div>
<div><br>
</div>
<div>Now I can use KeyType1 instances as key in Dictionary.</div>
<div><br>
</div>
<div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">var</span> collection1 = [<span style="color:#4f8187">KeyType1</span>(id:
<span style="color:#d12f1b">
"foo"</span>) : <span style="color:#703daa">
NSObject</span>()]</div>
</div>
<div><br>
</div>
<div><br>
</div>
<div>Testing works fine:</div>
<div><br>
</div>
<div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">let</span> key =
<span style="color:#4f8187">
collection1</span>.<span style="color:#703daa">first</span>!.<span style="color:#272ad8">0</span></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(209,47,27)">
<span style="color:#000000">
</span><span style="color:#3d1d81">print</span><span style="color:#000000">(</span>" Key stored in collection:
<span style="color:#000000">
\</span>(<span style="color:#3d1d81">unsafeAddressOf</span><span style="color:#000000">(key)</span>) --
<span style="color:#000000">
\</span>(<span style="color:#000000">key</span>)"<span style="color:#000000">)</span></div>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px">
<br>
</p>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">
let</span> keyCopy = <span style="color:#4f8187">
KeyType1</span>(id: key.<span style="color:#4f8187">id</span>)</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(209,47,27)">
<span style="color:#000000">
</span><span style="color:#3d1d81">print</span><span style="color:#000000">(</span>" Key copy:
<span style="color:#000000">
\</span>(<span style="color:#3d1d81">unsafeAddressOf</span><span style="color:#000000">(keyCopy)</span>) --
<span style="color:#000000">
\</span>(<span style="color:#000000">keyCopy</span>)"<span style="color:#000000">)</span></div>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px">
<br>
</p>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(209,47,27)">
<span style="color:#000000">
</span><span style="color:#3d1d81">print</span><span style="color:#000000">(</span>" Keys equal:
<span style="color:#000000">
\</span>(<span style="color:#000000">key
</span><span style="color:#31595d">==</span><span style="color:#000000"> keyCopy</span>)"<span style="color:#000000">)</span></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(209,47,27)">
<span style="color:#000000">
</span><span style="color:#3d1d81">print</span><span style="color:#000000">(</span>" Hash values equal:
<span style="color:#000000">
\</span>(<span style="color:#000000">key.</span><span style="color:#4f8187">hashValue</span><span style="color:#000000">
== keyCopy.</span><span style="color:#4f8187">hashValue</span>)"<span style="color:#000000">)</span></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(209,47,27)">
<span style="color:#000000">
</span><span style="color:#3d1d81">print</span><span style="color:#000000">(</span>" Collection has item for key:
<span style="color:#000000">
\</span>(<span style="color:#4f8187">collection1</span><span style="color:#000000">[key] !=
</span><span style="color:#bb2ca2">nil</span>)"<span style="color:#000000">)</span></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(209,47,27)">
<span style="color:#000000">
</span><span style="color:#3d1d81">print</span><span style="color:#000000">(</span>"Collection has item for key copy:
<span style="color:#000000">
\</span>(<span style="color:#4f8187">collection1</span><span style="color:#000000">[keyCopy] !=
</span><span style="color:#bb2ca2">nil</span>)"<span style="color:#000000">)</span></div>
</div>
<div><br>
</div>
<div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<b> Key stored in collection: 0x0000608000043d80 -- foo</b></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<b> Key copy: 0x00006080000440b0 -- foo</b></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<b> Keys equal: true</b></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<b> Hash values equal: true</b></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<b> Collection has item for key: true</b></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<b>Collection has item for key copy: true</b></div>
</div>
<div><br>
</div>
<div><br>
</div>
<div><br>
</div>
<div>Next, I repeat the same set up -- but this time KeyType is a descendant of NSObject.</div>
<div><br>
</div>
<div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">func</span> ==(lhs:
<span style="color:#4f8187">
KeyType2</span>, rhs: <span style="color:#4f8187">
KeyType2</span>) -> <span style="color:#703daa">
Bool</span> { <span style="color:#bb2ca2">
return</span> lhs.<span style="color:#4f8187">id</span> == rhs.<span style="color:#4f8187">id</span> }</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px">
<br>
</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0)">
<span style="color:#bb2ca2">final</span><span style="color:#000000">
</span><span style="color:#bb2ca2">class</span><span style="color:#000000"> KeyType2:
</span><span style="color:#703daa">NSObject</span><span style="color:#000000"> {
</span>// NSObject conforms to Hashable and CustomStringConvertible.</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">
let</span> id: <span style="color:#703daa">
String</span></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">
init</span>(id: <span style="color:#703daa">
String</span>) { <span style="color:#bb2ca2">
self</span>.<span style="color:#4f8187">id</span> = id;
<span style="color:#bb2ca2">
super</span>.<span style="color:#bb2ca2">init</span>() }</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">
override</span> <span style="color:#bb2ca2">
var</span> hashValue: <span style="color:#703daa">
Int</span> { <span style="color:#bb2ca2">
return</span> <span style="color:#4f8187">
id</span>.<span style="color:#703daa">hashValue</span> }</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">
override</span> <span style="color:#bb2ca2">
var</span> description: <span style="color:#703daa">
String</span> { <span style="color:#bb2ca2">
return</span> <span style="color:#4f8187">
id </span>}</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
}</div>
</div>
<div><br>
</div>
<div>Again, I create a Dictionary based on this key class.</div>
<div><br>
</div>
<div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">var</span> collection2 = [<span style="color:#4f8187">KeyType2</span>(id:
<span style="color:#d12f1b">
"foo"</span>) : <span style="color:#703daa">
NSObject</span>()]</div>
</div>
<div><br>
</div>
<div>Using the same tests, they fail now.</div>
<div><br>
</div>
<div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">let</span> key =
<span style="color:#4f8187">
collection2</span>.<span style="color:#703daa">first</span>!.<span style="color:#272ad8">0</span></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(209,47,27)">
<span style="color:#000000">
</span><span style="color:#3d1d81">print</span><span style="color:#000000">(</span>" Key stored in collection:
<span style="color:#000000">
\</span>(<span style="color:#3d1d81">unsafeAddressOf</span><span style="color:#000000">(key)</span>) --
<span style="color:#000000">
\</span>(<span style="color:#000000">key</span>)"<span style="color:#000000">)</span></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px">
<br>
</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<span style="color:#bb2ca2">
let</span> keyCopy = <span style="color:#4f8187">
KeyType2</span>(id: key.<span style="color:#4f8187">id</span>)</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(209,47,27)">
<span style="color:#000000">
</span><span style="color:#3d1d81">print</span><span style="color:#000000">(</span>" Key copy:
<span style="color:#000000">
\</span>(<span style="color:#3d1d81">unsafeAddressOf</span><span style="color:#000000">(keyCopy)</span>) --
<span style="color:#000000">
\</span>(<span style="color:#000000">keyCopy</span>)"<span style="color:#000000">)</span></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px">
<br>
</div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(209,47,27)">
<span style="color:#000000">
</span><span style="color:#3d1d81">print</span><span style="color:#000000">(</span>" Keys equal:
<span style="color:#000000">
\</span>(<span style="color:#000000">key
</span><span style="color:#31595d">==</span><span style="color:#000000"> keyCopy</span>)"<span style="color:#000000">)</span></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(209,47,27)">
<span style="color:#000000">
</span><span style="color:#3d1d81">print</span><span style="color:#000000">(</span>" Hash values equal:
<span style="color:#000000">
\</span>(<span style="color:#000000">key.</span><span style="color:#4f8187">hashValue</span><span style="color:#000000">
== keyCopy.</span><span style="color:#4f8187">hashValue</span>)"<span style="color:#000000">)</span></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(209,47,27)">
<span style="color:#000000">
</span><span style="color:#3d1d81">print</span><span style="color:#000000">(</span>" Collection has item for key:
<span style="color:#000000">
\</span>(<span style="color:#4f8187">collection2</span><span style="color:#000000">[key] !=
</span><span style="color:#bb2ca2">nil</span>)"<span style="color:#000000">)</span></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(209,47,27)">
<span style="color:#000000">
</span><span style="color:#3d1d81">print</span><span style="color:#000000">(</span>"Collection has item for key copy:
<span style="color:#000000">
\</span>(<span style="color:#4f8187">collection2</span><span style="color:#000000">[keyCopy] !=
</span><span style="color:#bb2ca2">nil</span>)"<span style="color:#000000">)</span></div>
</div>
<div><br>
</div>
<div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<b> Key stored in collection: 0x0000608000044080 -- foo</b></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<b> Key copy: 0x00006080000440e0 -- foo</b></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<b> Keys equal: true</b></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<b> Hash values equal: true</b></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<b> Collection has item for key: true</b></div>
<div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
<b>Collection has item for key copy: false</b></div>
</div>
<div><br>
</div>
<div><br>
</div>
<div>What am I missing here?</div></div></blockquote><div><br></div><div>The == overload in the second case is not the one that gets put into the protocol witness table. When you call == on two instances of your type, upcast to NSObject, the isEqual() method is called.</div><div><br></div><div>We are aware of this issue and it will be fixed when we move operators into types.</div><div><br></div><div>Dmitri</div></div><div><br></div>-- <br><div class="gmail_signature">main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if<br>(j){printf("%d\n",i);}}} /*Dmitri Gribenko <<a href="mailto:gribozavr@gmail.com" target="_blank">gribozavr@gmail.com</a>>*/</div>
</div></div>