> Am 16.10.2017 um 00:41 schrieb Xiaodi Wu via swift-evolution 
> <swift-evolution@swift.org>:
> 
> On Sun, Oct 15, 2017 at 2:32 PM, Kevin Nattinger <sw...@nattinger.net> wrote:
>>> […]
>>> Sets, as a mathematical concept, have no intrinsic order. However, 
>>> instances of `Set`, which can be iterated over, *do* have at least one 
>>> order which can be said to be intrinsic in the following sense: as long as 
>>> iteration is possible, no API design can prevent that order from being 
>>> observed and associated with the instance. Put another way, if you can use 
>>> an instance of a type in a for...in loop, intrinsic to that functionality 
>>> is a publicly visible order.
>> 
>> You keep saying this, I keep saying it’s only a technical “order” that is an 
>> implementation detail
> 
> You keep saying it's an implementation detail, which it emphatically is 
> *not*. It's a *public guarantee* by the protocol that you can use an instance 
> of `Set` in a `for...in` loop, thereby exposing a publicly visible order. An 
> implementation detail is something

Being able to use a Set in a for...in loop does *not* make it ordered! The 
purpose is is just being able to do something with each element. That a 
for...loop works sequentially is just a side effect. Just imagine we had 
parallelized for...in loops.


> that could go away with an alternative implementation. By contrast, no 
> implementation that permits an instance of `Set` being iterated over in a 
> `for...in` loop can avoid exposing at least one publicly visible order, 
> because it's not a matter of implementation. Put another way, by allowing 
> iteration, a type necessarily exposes at least one publicly visible order and 
> thereby models a sequence in at least one way.

Wrong. I could easily implement Set or another type to iterate in a random 
order over its elements, so each iteration would expose a different 
(meaningless) order.
This demonstrates that being able to be used in a for...in loop is about doing 
somthing with each element and not about element order. The latter is an 
additional property which should be expressed in an additional protocol like 
Kevin suggested.

-Thorsten



>  
>> and can’t be relied upon for anything and so we shouldn’t provide methods 
>> that rely on it. I think this part of the discussion has reached the “agree 
>> to disagree” stage.
>> 
>>>> […]
>>>> You’re a fan of the principal of least surprise. Tell me, which would be 
>>>> less surprising: Set.dropFirst() actually drops a random element, or Set 
>>>> doesn’t have a dropFirst()? And if you think dropFirst() removing an 
>>>> element at random is not surprising, please explain why.
>>> 
>>> I think Set.dropFirst removing the first element that I observe on 
>>> iteration is the least surprising answer, because Swift tells me that the 
>>> stdlib Set models a set but that it is also a sequence.
>> 
>> Your logic is backwards. You’re saying it’s “least surprising” because 
>> that’s how it’s currently implemented, not that it should be implemented 
>> that way because it’s least surprising.
> 
> No, I'm saying it's least surprising because any type that supports iterated 
> access thereby exposes an order--not as an implementation detail but as a 
> matter of public API--and in the absence of any other order, "first" must 
> refer to that order so exposed.
>>>>>>>>> […]
>>>> 
>>>> And that’s PRECISELY why lexicographicallyEqual does not make sense to 
>>>> apply to unordered sets. There is no lexicographical comparison possible, 
>>>> so why do you keep insisting they should have a method that falsely claims 
>>>> to lexicographically compare them?
>>> 
>>> I agree! It doesn't make sense if no comparison is possible! But Swift 
>>> tells me that a `Set` is a `Sequence`!
>> 
>> You keep making the circular argument that a Set should do things because it 
>> currently does them. If you want to argue against changing things, argue 
>> that things shouldn’t be changed, not that the current implementation is 
>> correct because it is the current implementation.
> 
> No, I'm arguing that `Set`, by supporting iterated access, is not wrong to 
> conform to a protocol called `Sequence` because it does have an intrinsic and 
> publicly observable order, which is not an accident of a particular 
> implementation but is inherent to any type that supports iterated access. 
> Now, whether it's the *best choice* to conform `Set` to `Sequence` and offer 
> order-dependent functions is a matter of taste, but it isn't *wrong*.
>>> […]
>>> You will always have to account for this possibility, because Swift's 
>>> `Equatable` explicitly allows "special values" to be not equal to 
>>> themselves. This is, at least in part, in order to accommodate the IEEE 
>>> decree that NaN != NaN:
>> 
>>> 
>>> ```
>>> let x = [Double.nan]
>>> x.elementsEqual(x) // false
>>> ```
>> 
>> NaN is special, one-shot and unordered sequences are not. Unless you think 
>> that all unordered and single-pass sequences should compare false for 
>> `elementsEqual`, this is irrelevant for any sequence that doesn’t contain 
>> NaN and well-defined (false) for any that does.
> 
> Certainly, not all single-pass sequences should compare false to themselves, 
> but some should: for instance, an infinite single-pass stream of all 1's 
> should compare true to itself, but an infinite single-pass stream of 
> alternating 1's and 0's should compare false to itself. If you write generic 
> code that calls `elementsEqual`, it is pervasively incorrect to test for 
> identity by assuming that elementsEqual will return true on reflexive 
> comparison. NaN is only one of many reasons why such code would blow up.
>  
>> 
>>> Changing this behavior is way beyond the scope of this thread (and has been 
>>> the topic of hours (actually, weeks and weeks) of fun on this list 
>>> previously).
>> 
>> Yes, I’ve seen the discussion on NaN and Comparable. It’s not the same 
>> discussion.
>> 
>>> […]
>>>>>> 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.
>>> Wouldn't it then suffice to document, say, that a set's iteration order is 
>>> the insertion order?
>> 
>> Now this actually gave me pause. I guess it does match what I said, but I 
>> still take issue with the fact that two Sets could compare `==` but not 
>> `elementsEqual`. I think that defining iteration order as insertion order 
>> adds a piece of publicly documented state that goes beyond what a Set really 
>> is. What you describe is really an OrderedSet, just without the 
>> random-access manipulation.
> 
> a) There is no semantic requirement on the part of `==` to be equivalent to 
> an elementwise comparison when it is defined on a collection; in fact, one 
> could imagine that some exotic sequence might legitimately define equality in 
> a way that has nothing to do with elementwise comparison. Put another way, 
> `==` returning `true` does not imply `elementsEqual` returning `true`, and 
> `elementsEqual` returning `true` does not imply `==` returning `true`. This 
> applies equally to ordered collections and is independent of the question of 
> how to model unordered collections.
> 
> b) You keep writing that some Foo is really some Bar, but those are really 
> just names. What would be the harm if Swift's `Set` indeed simply models an 
> ordered set without random-access manipulation?
> 
>> I’ll have to mull this over to see if I can come up with a coherent and 
>> (more) specific requirement for what makes an Iterable a Sequence, since 
>> clearly “documented” isn’t enough.  Perhaps something along the lines that 
>> any two Sequences that compare equal must iterate the same.
>> 
>>> […]
>>> Apple documentation calls this one of the "order-dependent" methods. It is 
>>> surely acceptable for a type that conforms to an order-dependent protocol 
>>> to have methods that are order-dependent; they do, however, have to be 
>>> clearly order-dependent to avoid confusion on unordered types.
>> 
>> I’m not clear on what you’re trying to get across here. It seems you’re 
>> saying unordered types shouldn’t have order-dependent methods, which is 
>> exactly what I’ve been arguing.
> 
> No, I'm saying, essentially, that there are no truly unordered types in 
> Swift; `Set` and `Dictionary` lead double lives modeling unordered 
> collections on the one hand and ordered collections on the other. The 
> order-dependent methods can continue to exist; they just need to be clearly 
> named so that users know when they're using an instance of `Set` in the 
> manner of an unordered collection and when they're using an instance of `Set` 
> in the manner of an ordered collection.
>  
>> 
>>>  [...]
>>>> Then there are all the methods that imply a specific order of iteration. 
>>>> If the “sequence” is unordered, who knows what you’ll get? It is 
>>>> incredibly easy for an engineer to write a method that implicitly relies 
>>>> on a passed sequence being intrinsically ordered and another engineer to 
>>>> pass it an unordered “sequence.”  The first engineer could neglect to 
>>>> document the dependency, or even not notice it; or the second engineer 
>>>> could just fail to read the documentation thoroughly enough.  There is 
>>>> currently no way for the compiler to enforce passing only an object that 
>>>> is (or at least claims to be) intrinsically ordered.
>>> 
>>> It is also incredibly easy for such an engineer to use `for...in` instead 
>>> to accomplish the same task, generic over ordered and unordered sequences 
>>> whatever you name such distinguished protocols. I think your beef really 
>>> still boils down to Set being compatible with `for...in` at all, as Jon 
>>> acknowledges.
>> 
>> Not providing ordered functions for unordered collections makes the 
>> developers think about what they actually need. If any object will do, they 
>> can use for…in, .makeIterator().next(), or an `anyObject()` we provide as a 
>> convenience. If they actually need the first from some specific order, it’s 
>> a reminder they need to sort the objects first to get the right one.
> 
> The whole point of protocol hierarchies is to enable useful generic 
> algorithms. Here, the purpose of having a protocol that unites both ordered 
> and unordered collections is to permit the writing of generic algorithms that 
> operate on both; a user would want the first item from an ordered collection 
> or an arbitrary item (but the same one on multiple passes) from an unordered 
> collection. The name for that is currently `first`. Brent demonstrated a 
> trivial one-line example of such a use.
> 
>> That’s particularly useful for functions that actually need an ordered 
>> sequence; using OrderedSequence instead of Iterable (just as placeholders) 
>> would be a firm reminder not to pass in an unordered collection.
>> 
>>>>> […]
>>> 
>>> As I said, you're welcome to tackle the protocol hierarchy, but I really 
>>> doubt it's within the realm of realistic endpoints for Swift 5. I'm just 
>>> trying to propose a narrowly targeted pragmatic solution to one specific 
>>> limited harm that might be deliverable by the next point release. As a 
>>> great man once said, Swift is a pragmatic language.
>> 
>> If you want a pragmatic solution, fix the bug in functionality, don’t try 
>> and rename the method to something obscure to cover it up.
> 
> What I'm arguing is that there *is no bug in functionality*, only a naming 
> problem. It is true that the current protocol hierarchy would not be my 
> preferred design, but that's a matter of taste in terms of, again, where to 
> draw the line between too much modeling or not enough. But that's not 
> tantamount to a *bug*.
>  
>> If you want to limit the harm, override `equalObjects` on unordered 
>> sequences to use `==` (very strongly preferred), or always `false` (less 
>> desirable, but at least consistent)
>> 
>>>>> […]
>> 
>>> 
>>> The Swift stdlib deliberately eschews modeling everything in protocol 
>>> hierarchies with the highest level of granularity. There's some fudging, 
>>> deliberately, to find a happy medium between obtuse and approachable, 
>>> between too many/too specialized and not enough. For example, I pushed for 
>>> protocols such as `Field` and `Ring` at the top of the numeric hierarchy, 
>>> which might allow complex number types to slot into the hierarchy more 
>>> sensibly, for example. But we have a compromise protocol `Numeric` which 
>>> doesn't quite have the same guarantees but is much more approachable. 
>>> Notice that we also don't break down numeric protocols into `Addable`, 
>>> `Subtractable`, etc.; we also have that fudge factor built into 
>>> `Equatable`, as I mentioned.
>> 
>> Eh, one or two corner cases on a protocol is probably fine. What’s not fine 
>> is over half (Sequence) or almost all (Collection) the methods not being 
>> applicable.  There is a very clear gap there. We don’t need to fix 
>> everything, but this is something that can and should be addressed.
> 
> This would be based on the premise that an instance of `Set` has no intrinsic 
> order; I disagree for the reasons above.
> _______________________________________________
> 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

Reply via email to