> 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.


> 
>>>> 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??

-Thorsten
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to