> On Oct 16, 2017, at 1:08 PM, Xiaodi Wu via swift-evolution > <swift-evolution@swift.org> wrote: > > > On Mon, Oct 16, 2017 at 13:15 David Sweeris <daveswee...@mac.com > <mailto:daveswee...@mac.com>> wrote: > > On Oct 16, 2017, at 09:21, Michael Ilseman <milse...@apple.com > <mailto:milse...@apple.com>> wrote: > >> >> >>> On Oct 16, 2017, at 8:46 AM, David Sweeris via swift-evolution >>> <swift-evolution@swift.org <mailto: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. > > From the “value semantics” PoV, yes. But from the “unordered collection of > values” PoV, Sets/Dictionaries, being unordered, are semantically free to > rearrange the in-memory ordering of their elements without user intervention. > > No, they are not semantically free to do so. The semantics of Collection > forbid it, because the iteration order must be multi-pass. As long as the > value is unchanged, the iteration order is unchanged. That is a documented, > public guarantee of the API.
Of the Collection API. But `elementsEqual` is on Sequence, which carries no such guarantee. > > Maybe we need to add a mechanism for expressing the idea of a “value type > which has referential tendencies“ for these “managed” types of values? > > Perhaps a less abstract example would be a “RemoteDictionary”, which maps > each key to a remote server where the value is actually stored... I would > expect it to iterate over its values in whatever order it gets them back from > all the servers. And since dictionaries are unordered and network conditions > & server loads can change (quickly), I wouldn’t expect consecutive iterations > to necessarily be in the same order. > > - Dave Sweeris > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution