> Am 17.10.2017 um 14:44 schrieb Xiaodi Wu <xiaodi...@gmail.com>: > > >> On Tue, Oct 17, 2017 at 00:56 Thorsten Seitz <tseit...@icloud.com> wrote: >> >> >>> Am 17.10.2017 um 00:13 schrieb Xiaodi Wu <xiaodi...@gmail.com>: >>> >>> >>> On Mon, Oct 16, 2017 at 14:21 Thorsten Seitz <tseit...@icloud.com> wrote: >>>>> Am 16.10.2017 um 16:20 schrieb Xiaodi Wu via swift-evolution >>>>> <swift-evolution@swift.org>: >>>>> >>>>> >>>>> On Mon, Oct 16, 2017 at 05:48 Jonathan Hull <jh...@gbis.com> wrote: >>>>>> >>>>>>> On Oct 15, 2017, at 9:58 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote: >>>>>>> >>>>>>>> On Sun, Oct 15, 2017 at 8:51 PM, Jonathan Hull <jh...@gbis.com> wrote: >>>>>>>> >>>>>>>>>> On Oct 14, 2017, at 10:48 PM, Xiaodi Wu <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). >>>> >>>> But it is a behavior which has absolutely no meaning at all because the >>>> order does not depend on the elements of the set but on the history of how >>>> the set has been reached its current state. >>>> So why should I ever use this method on a set? >>>> What is the use case? >>> >>> One example: you can use it to check an instance of Set<Float> to determine >>> if it has a NaN value. (The “obvious” way of doing it is not guaranteed to >>> work since NaN != NaN.) >> >> How would I do that? I'd rather expect to use a property isNaN on Float to >> do that. > > set.elementsEqual(set)
If this is the only use case for `elementsEqual` I suggest we remove that method and just use Float.isNaN: set.contains { $0.isNaN } which I argue is far more readable (intention revealing). -Thorsten > >>>>>> I don’t see why a non-source-breaking change is suddenly off-limits. >>>>>> >>>>>> But more than that, any generic algorithm which is assuming that the >>>>>> sequence is coming from an ordered source (i.e. many things using >>>>>> first/last). Some uses of first are ok because the programmer actually >>>>>> means ‘any’, but anywhere where they actually mean first/last may be >>>>>> problematic. >>>>> >>>>> Such as...? >>>>> >>>>>> Currently, there is no way to test for ordered-ness, so there is no way >>>>>> for even a careful programmer to mitigate this problem. By adding a >>>>>> protocol which states that something is unordered, we can either branch >>>>>> on it, or create a separate version of an algorithm for things which >>>>>> conform. >>>>> >>>>> It is clearly the case that Swift’s protocol hierarchy fits sets and >>>>> collections imperfectly; however, it is in the nature of modeling that >>>>> imperfections are present. The question is not whether it is possible to >>>>> incur performance, API surface area, and other trade-offs to make the >>>>> model more faithful, but rather whether this usefully solves any problem. >>>>> What is the problem being mitigated? As I write above, Swift’s Set and >>>>> Dictionary types meet the semantic requirements for Collection and >>>>> moonlight as ordered collections. What is a generic algorithm on an >>>>> ordered collection that is “not OK” for Set and Dictionary? >>>>> (“elementsEqual”, as I’ve said, is not such an example.) >>>> >>>> On the contrary, `elementsEqual` is exactly such an example, because it >>>> makes no sense to use it on a Set. >>>> >>>> let s1 = Set([1,2,3,4,5,6]) >>>> let s2 = Set([6,5,4,3,2,1]) >>>> >>>> Both sets have different iteration orders. Comparing those sets with some >>>> other collection using `elementsEqual` will give no meaningful result >>>> because the order - and therefore the result of `elementsEqual` - is in >>>> effect random. >>> >>> No, it is not such an example; it’s misleadingly named but works >>> correctly—that is, its behavior matches exactly the documented behavior, >>> which relies on only the semantic guarantees of Sequence, which Set >>> correctly fulfills. >> >> Fulfills to the letter. Again, what can you do with it if the result is >> random?? > > The result is not random. >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution