<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=""><br class=""><div><blockquote type="cite" class=""><div class="">On Oct 17, 2017, at 12:04 AM, Gwendal Roué 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 style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">Modeling is, by definition, imperfect. The question is, what imperfect model is most useful _to Swift_. The idea is that conforming Set and Dictionary to Collection is on balance more useful than not doing so; that having two protocols, Sequence and Collection, is on balance more useful than having one or three, and that the set of semantic guarantees of Collection are on balance more useful than other possible sets of semantic guarantees.<br class=""></div></div></div></div></div></blockquote><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">That is your idea which is disputed and underlined with arguments whereas you keep repeating that Set behaves as dictated by its conformance without giving use cases why this should be useful.</span></div></blockquote><br class=""></div><div class="">Hello,</div><div class=""><br class=""></div><div class=""><div class="">You can't *control* the ordering of a set or a dictionary, but you can still *rely* on it.</div></div><div class=""><br class=""></div><div class="">For example, to find a key in a dictionary that is associated a given value, you can rely on the fact that a dictionary's order is guaranteed to be stable, and that on top of that its indexes can address the dictionary itself, but also its keys and values sequences. The code below has no bug;</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(209, 47, 27); background-color: rgb(255, 255, 255);" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="color: #ba2da2" class="">let</span><span style="" class=""> dict = [</span>"a"<span style="" class="">: </span>"foo"<span style="" class="">, </span>"b"<span style="" class="">: </span>"bar"<span style="" class="">, </span>"c"<span style="" class="">: </span>"needle"<span style="" class="">]</span></div><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Helvetica; min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; line-height: normal; color: rgb(0, 132, 0);" class="">// Find a key associated with "needle"</div><div style="margin: 0px; line-height: normal;" class=""><span style="color: #ba2da2" class="">if</span> <span style="color: #ba2da2" class="">let</span> index = dict.values.index(of: <span style="color: #d12f1b" class="">"needle"</span>) {</div><div style="margin: 0px; line-height: normal;" class="">&nbsp; &nbsp; <span style="color: #ba2da2" class="">let</span> key = dict.keys[index]</div><div style="margin: 0px; line-height: normal;" class="">&nbsp; &nbsp; print(key) <span style="color: #008400" class="">// prints "c"</span></div><div style="margin: 0px; line-height: normal;" class="">}</div></div></div></div></div></blockquote><div><br class=""></div><div>You are using the index from one collection to index into another collection. &nbsp;Isn’t that something the documentation explicitly tells us not to do? &nbsp;Or is there a special (documented) guarantee that these collections will always sync indices?</div><div><br class=""></div><div>I guess you could do:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>if let key =&nbsp;dict.first(where {$1 == “needle}).0 {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>print(key)</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><br class=""></div><div>…although note that which element is “first” if there are multiple keys with needle as the value may shift around on you as you mess with the dictionary (and also on separate runs even if you don’t mess with the dictionary).</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">It's more difficult to find a use case for set's ordering and indexes. But since you ask, here is an example. The goal is to find any element which is not equal to another value, in any collection:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="color: #ba2da2" class="">extension</span> <span style="color: #703daa" class="">Collection</span> <span style="color: #ba2da2" class="">where</span> Element: Equatable {</div><div style="margin: 0px; line-height: normal; color: rgb(0, 116, 105);" class=""><span style="" class="">&nbsp; &nbsp; </span>/// Returns any element which is not equal to the given element</div><div style="margin: 0px; line-height: normal;" class="">&nbsp; &nbsp; <span style="color: #ba2da2" class="">func</span> anyElement(notEqualTo v: <span style="color: #703daa" class="">Element</span>) -&gt; <span style="color: #703daa" class="">Element</span>? {</div><div style="margin: 0px; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ba2da2" class="">if</span> <span style="color: #ba2da2" class="">let</span> i = <span style="color: #3e1e81" class="">index</span>(of: v) {</div><div style="margin: 0px; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ba2da2" class="">if</span> <span style="color: #ba2da2" class="">let</span> alt = <span style="color: #3e1e81" class="">index</span>(i, offsetBy: <span style="color: #272ad8" class="">1</span>, limitedBy: <span style="color: #703daa" class="">endIndex</span>), alt != <span style="color: #703daa" class="">endIndex</span> {</div><div style="margin: 0px; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ba2da2" class="">return</span> <span style="color: #ba2da2" class="">self</span>[alt]</div><div style="margin: 0px; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="margin: 0px; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ba2da2" class="">if</span> i == <span style="color: #703daa" class="">startIndex</span> {</div><div style="margin: 0px; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ba2da2" class="">return</span> <span style="color: #ba2da2" class="">nil</span></div><div style="margin: 0px; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="margin: 0px; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ba2da2" class="">return</span> <span style="color: #703daa" class="">first</span></div><div style="margin: 0px; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div style="margin: 0px; line-height: normal;" class="">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #ba2da2" class="">return</span> <span style="color: #703daa" class="">first</span></div><div style="margin: 0px; line-height: normal;" class="">&nbsp; &nbsp; }</div><div style="margin: 0px; line-height: normal;" class="">}</div><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Helvetica; min-height: 14px;" class=""><br class=""></div><div style="margin: 0px; line-height: normal;" class=""><span style="color: #703daa" class="">Set</span>([<span style="color: #272ad8" class="">1</span>, <span style="color: #272ad8" class="">2</span>, <span style="color: #272ad8" class="">3</span>]).<span style="color: #31595d" class="">anyElement</span>(notEqualTo: <span style="color: #272ad8" class="">1</span>) <span style="color: #008400" class="">// 2 or 3</span></div><div style="margin: 0px; line-height: normal;" class=""><span style="color: #703daa" class="">Set</span>([<span style="color: #272ad8" class="">1</span>, <span style="color: #272ad8" class="">2</span>]).<span style="color: #31595d" class="">anyElement</span>(notEqualTo: <span style="color: #272ad8" class="">1</span>)&nbsp; &nbsp; <span style="color: #008400" class="">// 2</span></div><div style="margin: 0px; line-height: normal;" class=""><span style="color: #703daa" class="">Set</span>([<span style="color: #272ad8" class="">1</span>]).<span style="color: #31595d" class="">anyElement</span>(notEqualTo: <span style="color: #272ad8" class="">1</span>) &nbsp; &nbsp; &nbsp; <span style="color: #008400" class="">// nil</span></div><div style="margin: 0px; line-height: normal;" class=""><span style="color: #703daa" class="">Set</span>([<span style="color: #272ad8" class="">2</span>]).<span style="color: #31595d" class="">anyElement</span>(notEqualTo: <span style="color: #272ad8" class="">1</span>) &nbsp; &nbsp; &nbsp; <span style="color: #008400" class="">// 2</span></div><div style="margin: 0px; line-height: normal;" class=""><span style="color: #703daa" class="">Set</span>([]).<span style="color: #31595d" class="">anyElement</span>(notEqualTo: <span style="color: #272ad8" class="">1</span>)&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008400" class="">// nil</span></div><div style="margin: 0px; font-size: 12px; line-height: normal; font-family: Helvetica; min-height: 14px;" class=""><br class=""></div></div></div><div class="">That *can* be useful, isn't it?</div></div></div></blockquote><div><br class=""></div><div>Yes, although this could easily be provided using iteration without indexing.</div><div><br class=""></div><div><br class=""></div><div>Note that my current favorite solution is to simply provide an additional guarantee on set/dictionary that the iteration order will always be the same for the same contents (regardless of history), but the order would still be otherwise arbitrary. &nbsp;That is a non-source-breaking change (renaming IS source breaking). &nbsp;It won’t fix everything, but it will fix some of the biggest gotchas. &nbsp;As a bonus, elementsEqual will 'just work'™ for sets/dictionaries.&nbsp;</div><div><br class=""></div><div>Thanks,</div><div>Jon</div><div><br class=""></div><div><br class=""></div></div></body></html>