> Am 16.10.2017 um 18:19 schrieb Michael Ilseman <milse...@apple.com>: > > > >> On Oct 16, 2017, at 7:20 AM, Thorsten Seitz via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >> >> >> >> Am 16.10.2017 um 07:19 schrieb Xiaodi Wu <xiaodi...@gmail.com >> <mailto:xiaodi...@gmail.com>>: >> >>> On Sun, Oct 15, 2017 at 11:57 PM, Thorsten Seitz <tseit...@icloud.com >>> <mailto:tseit...@icloud.com>> wrote: >>> >>> >>> Am 16.10.2017 um 00:41 schrieb Xiaodi Wu via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>: >>> >>>> On Sun, Oct 15, 2017 at 2:32 PM, Kevin Nattinger <sw...@nattinger.net >>>> <mailto: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. >>> >>> No, it is not at all a "side effect." A for...in loop is a way of >>> controlling the flow of code which accesses elements in a sequence one >>> after another, and the correct behavior of code inside the loop depends on >>> these semantics. A "parallel for" loop would be a totally different thing; >>> arbitrary for...in loops can't be automatically "upgraded" to a "parallel >>> for" loop because they have different semantics, and types that support >>> "parallel for" would likely have to conform to a protocol other than >>> `Sequence`. >> >> Exactly. >> >>>> 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. >>> >>> No, you cannot implement `Set` in this way because it conforms to >>> `Collection`, which guarantees a multi-pass sequence. Set *must expose the >>> same order on every iteration*. >> >> Set conforming to Collection is even worse than just conforming to Sequence >> as a quote from the documentation shows: "In addition to the operations that >> collections inherit from the Sequence protocol, you gain access to methods >> that depend on accessing an element at a specific position in a collection." >> Clearly the elements of a Set do not have specific positions. >> > > That’s not at all clear to me, could you elaborate? My understanding is that > elements of Set definitely *do* have a position, and that’s why you can use > an index on a set to retrieve the element. The same index on the same set > retrieves the same element.
That might be true, by virtue of implementation. But the notion of a Set is unordered (OrderedSet would be different but with a meaningful and stable order) so the notion of positions within a Set do not make sense IMHO. The indices provided by the Collection interface do might even make sense as references for a set but the concept of distances between such indices is just weird for sets. -Thorsten > > >> Furthermore my argument still stands for types derived from Sequence, so >> sidestepping it by pointing out that the situation is even worse for the >> current implementation of Set won't work. Can you explain why a type derived >> from Sequence which will iterate over its elements in random order should >> have methods like dropFirst()? >> >> >>> >>> 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. >>> >>> Again, Sequence *already doesn't* require the order to be meaningful or >>> even repeatable. >> >> I know. That's why I am arguing that certain methods of Sequence make no >> sense. At least we have reached that common ground. >> So why do you insist on Sequence having methods like dropFirst() if the >> notion of "first" does not make any sense? >> >>> Notice that, above, I said at least one order. A conforming type could >>> expose as many different orders as iterations, but that changes nothing. I >>> can still map an instance of that type to get an array of elements, and >>> that array will reveal some order which is the result of the inner workings >>> of the type. >>> >>> The latter is an additional property which should be expressed in an >>> additional protocol like Kevin suggested. >>> >>> What useful generic algorithms would this protocol support that are not >>> already possible? >> >> It would allow expressing generic algorithms depending on an order. >> >> -Thorsten >> >> >>> >>> -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 <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 <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