> On Oct 16, 2017, at 8:46 AM, David Sweeris via swift-evolution > <swift-evolution@swift.org> wrote: > > > On Oct 16, 2017, at 07:20, Xiaodi Wu via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: > >> >> On Mon, Oct 16, 2017 at 05:48 Jonathan Hull <jh...@gbis.com >> <mailto:jh...@gbis.com>> wrote: >> >>> On Oct 15, 2017, at 9:58 PM, Xiaodi Wu <xiaodi...@gmail.com >>> <mailto:xiaodi...@gmail.com>> wrote: >>> >>> On Sun, Oct 15, 2017 at 8:51 PM, Jonathan Hull <jh...@gbis.com >>> <mailto:jh...@gbis.com>> wrote: >>> >>>> On Oct 14, 2017, at 10:48 PM, Xiaodi Wu <xiaodi...@gmail.com >>>> <mailto:xiaodi...@gmail.com>> wrote: >>>>>> That ordering can be arbitrary, but it shouldn’t leak internal >>>>>> representation such that the method used to create identical things >>>>>> affects the outcome of generic methods because of differences in >>>>>> internal representation. >>>>>> >>>>>> >>>>>>> It would be better to say that the iteration order is well-defined. >>>>>>> That will almost always mean documented, and usually predictable though >>>>>>> obviously e.g. RNGs and iterating in random order will not be >>>>>>> predictable by design. >>>>>>> >>>>>>>> That's actually more semantically constrained than what Swift calls a >>>>>>>> `Collection` (which requires conforming types to be multi-pass and(?) >>>>>>>> finite). By contrast, Swift's `SpongeBob` protocol explicitly permits >>>>>>>> conforming single-pass, infinite, and/or unordered types. >>>>>>> >>>>>>> I think you’re talking about Sequence here, I’ve lost track of your >>>>>>> nonsense by now. Yes, the current Swift protocol named Sequence allows >>>>>>> unordered types. You seem to keep asserting that but not actually >>>>>>> addressing my argument, which is that allowing Sequences to be >>>>>>> unordered with the current API is undesired and actively harmful, and >>>>>>> should therefore be changed. >>>>>>> >>>>>>> What is harmful about it? >>>>>> >>>>>> After thinking about it, I think the harmful bit is that unordered >>>>>> sequences are leaking internal representation (In your example, this is >>>>>> causing people to be surprised when two sets with identical elements are >>>>>> generating different sequences/orderings based on how they were >>>>>> created). You are correct when you say that this problem is even true >>>>>> for for-in. >>>>>> >>>>>> I would not say it is a problem. Rather, by definition, iteration >>>>>> involves retrieving one element after another; if you're allowed to do >>>>>> that with Set, then the elements of a Set are observably ordered in some >>>>>> way. Since it's not an OrderedSet--i.e., order doesn't matter--then the >>>>>> only sensible conclusion is that the order of elements obtained in a >>>>>> for...in loop must be arbitrary. If you think this is harmful, then you >>>>>> must believe that one should be prohibited from iterating over an >>>>>> instance of Set. Otherwise, Set is inescapably a Sequence by the Swift >>>>>> definition of Sequence. All extension methods on Sequence like >>>>>> drop(while:) are really just conveniences for common things that you can >>>>>> do with iterated access; to my mind, they're essentially just >>>>>> alternative ways of spelling various for...in loops. >>>>> >>>>> I think an argument could be made that you shouldn’t be able to iterate >>>>> over a set without first defining an ordering on it (even if that >>>>> ordering is somewhat arbitrary). Maybe we have something like a >>>>> “Sequenc(e)able” protocol which defines things which can be turned into a >>>>> sequence when combined with some sort of ordering. One possible ordering >>>>> could be the internal representation (At least in that case we are >>>>> calling it out specifically). If I had to say >>>>> “setA.arbitraryOrder.elementsEqual(setB.arbitraryOrder)” I would >>>>> definitely be less surprised when it returns false even though setA == >>>>> setB. >>>>> >>>>> Well, that's a totally different direction, then; you're arguing that >>>>> `Set` and `Dictionary` should not conform to `Sequence` altogether. >>>>> That's fine (it's also a direction that some of us explored off-list a >>>>> while ago), but at this point in Swift's evolution, realistically, it's >>>>> not within the realm of possible changes. >>>> >>>> I am actually suggesting something slightly different. Basically, Set and >>>> Dictionary’s conformance to Collection would have a different >>>> implementation. They would conform to another protocol declaring that >>>> they are unordered. That protocol would fill in part of the conformance to >>>> sequence/collection using a default ordering, which is mostly arbitrary, >>>> but guaranteed to produce the same ordering for the same list of elements >>>> (even across collection types). This would be safer, but a tiny bit >>>> slower than what we have now (We could also potentially develop a way for >>>> collections like set to amortize the cost). For those who need to recover >>>> speed, the new protocol would also define a property which quickly returns >>>> a sequence/iterator using the internal ordering (I arbitrarily called it >>>> .arbitraryOrder). >>>> >>>> I believe it would not be source breaking. >>>> >>>> That is indeed something slightly different. >>>> >>>> In an ideal world--and my initial understanding of what you were >>>> suggesting--Set and Dictionary would each have a member like `collection`, >>>> which would expose the underlying data as a `SetCollection` or >>>> `DictionaryCollection` that in turn would conform to `Collection`; >>>> meanwhile, Set and Dictionary themselves would not offer methods such as >>>> `prefix`, or indexing by subscript, which are not compatible with being >>>> unordered. For those who want a particular ordering, there'd be something >>>> like `collection(ordered areInIncreasingOrder: (T, T) -> Bool) -> >>>> {Set|Dictionary}Collection`. >>>> >>>> What you suggest here instead would be minimally source-breaking. However, >>>> I'm unsure of where these guarantees provide benefit to justify the >>>> performance cost. Certainly not for `first` or `dropFirst(_:)`, which >>>> still yields an arbitrary result which doesn't make sense for something >>>> _unordered_. We *could* have an underscored customization point named >>>> something like `_customOrderingPass` that is only invoked from >>>> `elementsEqual` or other such methods to pre-rearrange the internal >>>> ordering of unordered collections in some deterministic way before >>>> comparison. Is that what you have in mind? >>> >>> >>> Something like that. Whatever we do, there will be a tradeoff between >>> speed, correctness, and ergonomics. >>> >>> My suggestion trades speed for correctness, and provides a way to recover >>> speed through additional typing (which is slightly less ergonomic). >>> >>> You haven't convinced me that this is at all improved in "correctness." It >>> trades one arbitrary iteration order for another on a type that tries to >>> model an unordered collection. >>> >>> We could do something like you suggest. I don’t think the method would need >>> to be underscored… the ordering pass could just be a method on the protocol >>> which defines it as unordered. Then we could provide a special conformance >>> for things where order really matters based on adherence to that protocol. >>> That might be an acceptable tradeoff. It would give us speed at the cost >>> of having the correct implementation being less ergonomic and more error >>> prone (you have to remember to check that it is unordered and call the >>> ordering method when it mattered). >>> >>> I’d still be a bit worried that people would make incorrect generic >>> algorithms based on expecting an order from unordered things, but at least >>> it would be possible for them check and handle it correctly. I think I >>> could get behind that tradeoff/compromise, given where we are in the swift >>> process and Swift's obsession with speed (though I still slightly prefer >>> the safer default). At least the standard library would handle all the >>> things correctly, and that is what will affect the majority of programmers. >>> >>> What is an example of such an "incorrect" generic algorithm that would be >>> made correct by such a scheme? >> >> To start with, the one you gave as an example at the beginning of this >> discussion: Two sets with identical elements which have different internal >> storage and thus give different orderings as sequences. You yourself have >> argued that the confusion around this is enough of a problem that we need to >> make a source-breaking change (renaming it) to warn people that the results >> of the ‘elementsEqual’ algorithm are undefined for sets and dictionaries. >> >> No, I am arguing that the confusion about ‘elementsEqual’ is foremost a >> problem with its name; the result of this operation is not at all undefined >> for two sets but actually clearly defined: it returns true if two sets have >> the same elements in the same iteration order, which is a publicly >> observable behavior of sets (likewise dictionaries). > > How is the iteration order of an unordered set or dictionary “publicly > observable”? If either is implemented such that it can asynchronously > optimize its storage (maybe by rebalancing a tree or merging two > non-contiguous array segments or something), its iteration order could change > without changing what values it contains. Seems like consecutive calls to > “elementsEquals” (or whatever we’re calling it) should return the same > answer, if we don’t add, remove, or mutate elements. >
Sets are values. If you add, remove, or mutate any elements you have a different Set and thus a potentially different ordering of elements. > - Dave Sweeris > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org <mailto:swift-evolution@swift.org> > https://lists.swift.org/mailman/listinfo/swift-evolution > <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution