<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 16, 2017, at 1:29 PM, Adam Kemp via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> 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; line-break: after-white-space;" class=""><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Oct 16, 2017, at 12:35 PM, Thorsten Seitz via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><br class=""></div><div class="">IMHO `elementsEqual` provides a nice example for a method which only makes sense on something meaningfully ordered:</div><div class="">What is the use case for `elementsEqual` that works with a Set?</div></div></div></div></blockquote></div><br class=""><div class="">There may not be one, but here’s the problem:</div><div class=""><br class=""></div><div class="">1. It’s generally useful for Set to conform to a protocol that allows you to iterate over its elements.</div><div class="">2. It’s generally useful to be able to ask if two objects that you can iterate over are equal by comparing the elements in the order that they’re iterated over.</div><div class=""><br class=""></div><div class="">The argument being made is that these two protocols should be different, but I don’t think the proponents of that idea have fully thought through what that would mean in practice. Consider a function like map, which takes a Sequence and produces another Sequence. This function is useful for both ordered and unordered elements so it would have to be defined in terms of the looser (unordered) type, which means its output type would be unordered. Imagine starting with an ordered enumerable and calling map on it. What’s the result? An unordered enumerable (the return type of map would be unordered to match its input type). Now you can’t use any of the methods that require the stricter (ordered) protocol on the result, even though you haven’t actually lost the order. You would have to do something to fix up the type and make the compiler see it as ordered again. Maybe there’s an asOrdered method or something. Imagine having to sprinkle that throughout your code just to make things compile. Does that sound like a usable API?</div><div class=""><br class=""></div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">let people:[Person] = [] // Ordered</div><div class="">let orderedNames:[String] = [] // Ordered</div><div class="">let names = people.map { $0.fullName } // Result is unordered</div><div class="">return names.elementsEqual(orderedNames) // compile error: names is unordered</div><div class="">// Maybe: return names.asOrdered().elementsEqual(orderedNames)?</div></blockquote><br class=""><div class="">Avoiding this mess would require overloading such that every function that supports either ordered or unordered would have to be written both ways, which would just be a different mess.</div></div></div></blockquote><div><br class=""></div>That is a great point. Once we allow covariant functions to satisfy protocol requirements and have generalized existentials and recursive protocol requirements, wouldn't we be able to update thusly:</div><div><br class=""></div><div>protocol Unordered {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>func map<T>(…) -> Any<U: Unordered where U.Element == T></div><div>}</div><div>protocol Ordered: Unordered {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>func map<T>(…) -> Any<O: Ordered where O.Element == T></div><div>}</div><div><br class=""></div><div>?</div><div><br class=""></div><div><div>Or the following; it also requires generalized existentials and recursive protocol requirements but not covariance; though I can imagine people arguing against introducing more associated types:</div><div> </div><div>protocol Unordered {</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>associatedtype MapResultType: Unordered</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>func map<T>(…) -> Any<M: MapResultType where M.Element == T></div><div>}</div><div><br class=""></div><div>This would even allow an ordered collection to map to an unordered one or vice-versa. Maybe a collection type that spits out an ordered list when mapping to Comparables.</div><div>(n.b. the more I think about it, the more I like this option. Where are our existentials and recursive requirements? :) )</div><div><br class=""></div><div>In this case we wouldn't even need an Ordered override; using concrete classes directly it would just work, and a function that requires an ordered result could specify it as any other constraint just as you do today:</div><div><br class=""></div><div>func foo<O: Ordered>(in seq: O) where O.Element == Int, O.MapResultType: Ordered {</div><div> let orderedMapping = seq.map { $0 + 1 } // type = Any<O: Ordered where O.Element == Int></div><div> …</div><div>}</div><div><br class=""></div><div>I'd be ok with `map` and `filter` keeping their array returns (and that's what's in my original email about this) until we get the language features needed to support these. And I think we'd want to revisit the definitions of much of what is currently Sequence once we get these language features anyway.</div></div><div><br class=""></div><div><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class=""><br class=""></div><div class="">All of that would be to solve a problem that in practice doesn’t seem to really cause any problems. I’m not aware of any evidence to suggest that this type causes a significant number of bugs, and we have another language/runtime (C#/.Net) with a large number of active developers and code bases with the same design and the same lack of evidence of a problem.</div></div></div></blockquote><div><br class=""></div><div>As I've been saying all along, elementsEqual returning a functionally random result when an unordered type is involved is a problem. At the least, we should make an OrderedSequence (conforming to Sequence, but could even be otherwise empty), move at least elementsEqual and lexicographicallyPrecedes to functions or extensions on that, and conform the appropriate stdlib types. Which would obviously not include Set or Dictionary. </div><br class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class="">It seems like we’re being asked to make the library significantly harder to work with in order to solve a set of bugs that, as far as I can tell, doesn’t really exist in practice. I think in order to even consider this we would need to see the evidence that there’s a real problem to solve, and see a solution that didn’t make the library significantly harder to use.</div></div></blockquote><div><br class=""></div><div>My aim for any such changes is to make the library more correct to use with little to no breakage of correct code. Done right, I think `Sequence: Iterable` can be done with little to no breakage beyond the direct use of Set or Dictionary as ordered, which I and others view as incorrect to begin with.</div><br class=""><blockquote type="cite" class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></blockquote></div><br class=""></body></html>