Daniel Duan Sent from my iPhone
> On Jul 23, 2016, at 3:15 PM, Ross O'Brien via swift-evolution > <swift-evolution@swift.org> wrote: > > This might be a radical suggestion ... or possibly a naive or unoriginal one, > I'll find out once I suggest it. > > Swift took the bold step of establishing optionals as a central type, rather > than assigning dual meanings to 'default' values such as zero or false. > Recognising the concept of not having a value, and safeguarding against that, > is core to Swift. Optional is nothing new or "bold". It's been main stream for years. Even C++ has it :) > Is it possible for Swift to recognise that there are values which simply > aren't comparable, rather than forcing a choice between ascending, same, > descending? Could we add a fourth: incomparable? > The problem we are trying to solve here is strict total ordering: https://en.m.wikipedia.org/wiki/Total_order > What if a sort operation didn't simply return an array of ordered values? > What if it partitioned the values into comparable and incomparable values, > and returned a sorted array of the former and an unordered collection of the > latter? > Maybe, this being Swift, we could use some kind of 'sort!' exclamation mark > to forcibly express that every value in the collection-to-be-sorted is > implicitly comparable, if we're sure. > > >> On Sat, Jul 23, 2016 at 10:37 PM, Xiaodi Wu via swift-evolution >> <swift-evolution@swift.org> wrote: >>> On Sat, Jul 23, 2016 at 4:19 PM, Nevin Brackett-Rozinsky >>> <nevin.brackettrozin...@gmail.com> wrote: >>> Another option would be to leave the IEEE 754 NaN hijinks in Float and >>> Double (as numerics people expect), and create a new type (with a nice >>> approachable name) that “acts like” Double but does not model NaN. Then any >>> operation which would ordinarily produce a NaN, instead traps for the new >>> type. That way its comparison operators only have to worry about non-NaN >>> values, which makes everything much cleaner. >>> >>> Sorting Doubles would retain its present functionality, warts and all, >>> which numerics people should be expected to handle. Whereas the new type >>> (“Number” sounds good, especially if we can make it subsume NSNumber) would >>> never have a NaN in the first place. >> >> The other comment I would make here is that, as mentioned earlier by Pyry, >> there are other types for which we'll need to reckon with domain-specific >> "hijinks" that don't offer easy notions of identity, Unicode being one >> example. I'd expect that many types that model an existing domain of human >> endeavor will run into something like this. Thus, carefully working through >> a design for fundamental protocols like Equatable and Comparable that don't >> fall down with FP will prove more broadly fruitful. I don't think that >> segregating all hijinks and modeling what we *wish* the world to be is as >> beneficial in terms of allowing generic algorithms to work meaningfully with >> types that people actually use in real-world scenarios. >> >>> Nevin >>> >>> >>> >>>> On Sat, Jul 23, 2016 at 4:57 PM, Xiaodi Wu via swift-evolution >>>> <swift-evolution@swift.org> wrote: >>>> Sorry to overwhelm with more emails. I'd like to show some work and >>>> further analysis for your consideration that refines the sketch I just >>>> wrote: >>>> >>>> Two FP values a and b can be, with respect to each other: >>>> >>>> * ordered or unordered (per IEEE, NaN compares unordered to everything, >>>> including itself) >>>> * identical or not identical (for these purposes, we adopt Steve's >>>> proposed test for identity: substitutable for all operations; thus +0 is >>>> not identical to -0, but different binary representations of the same >>>> value are identical) >>>> * equal or not equal (i.e. the behavior of the == operator today) >>>> >>>> So, if a and b are, with respect to each other: >>>> >>>> * ordered, identical, equal -- this is what happens ordinarily with two >>>> equal, non-NaN values >>>> * ordered, identical, not equal -- this can never happen >>>> * ordered, not identical, equal -- only +0 and -0 >>>> * ordered, not identical, not equal -- this is what happens ordinarily >>>> with two unequal, non-NaN values >>>> >>>> * unordered, identical, equal -- this can never happen, but if NaNs are to >>>> be well-behaved (for a true equivalence relation), then we will need an >>>> equivalence relation in which NaN == NaN >>>> * unordered, identical, not equal -- this is what always happens, but if >>>> NaNs are to be well-behaved, then such behavior will need to change >>>> * unordered, not identical, equal -- this can never happen >>>> * unordered, not identical, not equal -- this is what ordinarily happens >>>> with one NaN and one non-NaN value >>>> >>>> Equatable can have === and my proposed ==? as part of its protocol; a >>>> generic ==, as originally proposed, would be defined outside the protocol. >>>> A default implementation of ==? will forward to ===, and the generic == >>>> will be defined as `{ return (lhs ==? rhs) ?? (lhs === rhs) }`. >>>> For floating point, ==? will be specialized and cease to forward to === so >>>> that +0 and -0 compare true and NaN and anything compare nil, and floating >>>> point == will be defined notionally as `{ return (lhs ==? rhs) ?? false }`. >>>> >>>> >>>> On Sat, Jul 23, 2016 at 3:09 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote: >>>>> Throwing out some more radical ideas here. Suppose we had instead (taking >>>>> inspiration from IEEE notation): >>>>> >>>>> [Pardon any errors; I'm writing freehand in Gmail] >>>>> >>>>> infix operator ==? { /* figure out precedence later */ } >>>>> >>>>> protocol Equatable { >>>>> static func ==? (lhs: Self, rhs: Self) -> Bool? >>>>> /* semantics: >>>>> this function returns nil if lhs and rhs are unordered with respect >>>>> to each other >>>>> otherwise, evaluate by means of a legal equivalence relation */ >>>>> } >>>>> >>>>> func == <T: Equatable>(lhs: T, rhs: T) -> Bool { >>>>> return (lhs ==? rhs) ?? false >>>>> } >>>>> >>>>> protocol Comparable : Equatable { >>>>> static func <=> (lhs: Self, rhs: Self) -> Ordering >>>>> /* semantics: >>>>> this is a total ordering; thus: >>>>> if `(a ==? b) == true`, then `(a <=> b) == .same` >>>>> if `(a ==? b) == false`, then `(a <=> b) != .same` >>>>> but, if `(a ==? b) == nil`, then `a <=> b` may yield any result >>>>> */ >>>>> } >>>>> >>>>> >>>>>> On Sat, Jul 23, 2016 at 2:35 PM, Pyry Jahkola <pyry.jahk...@iki.fi> >>>>>> wrote: >>>>>> Given all this, I propose a simpler model that makes `a <=> b` follow >>>>>> the expected behaviour of < and ==, with the tradeoff that `a <=> .nan` >>>>>> and `.nan <=> b` will abort with a precondition failure: >>>>>> >>>>>> 1) We keep the current Interface of Equatable unchanged, with != >>>>>> defined in terms of ==. >>>>>> >>>>>> 2) Comparable would still refine Equatable, and include all the >>>>>> comparison operators, adding the new <=>: >>>>>> >>>>>> protocol Comparable : Equatable { >>>>>> static func <=>(lhs: Self, rhs: Self) -> Ordering >>>>>> static func <(lhs: Self, rhs: Self) -> Bool >>>>>> static func >(lhs: Self, rhs: Self) -> Bool >>>>>> static func <=(lhs: Self, rhs: Self) -> Bool >>>>>> static func >=(lhs: Self, rhs: Self) -> Bool >>>>>> } >>>>>> >>>>>> The comparison operators are kept in the interface so that partially >>>>>> ordered types such as Double can be supported in generic code. However, >>>>>> the documentation should recommend against defining `<` manually. >>>>>> >>>>>> 3) Default implementations for <Self : Comparable> are provided for the >>>>>> following operators: ==, <, >, <=, and >=. >>>>>> >>>>>> 4) User-defined types will need to define just <=> to conform to >>>>>> Comparable. (Even == can be omitted!) >>>>>> >>>>>> 5) FloatingPoint types implement custom versions of ==, <, >, <=, and >= >>>>>> using the standard IEEE 754 definition (i.e. comparisons involving NaN >>>>>> return false). Zero is zero; `0.0 == -0.0 && !(-0.0 < 0.0)` holds. >>>>>> >>>>>> 6) FloatingPoint types implement <=> as: >>>>>> >>>>>> func <=> <T : FloatingPoint>(lhs: T, rhs: T) -> Ordering { >>>>>> if lhs < rhs { return .ascending } >>>>>> if rhs < lhs { return .descending } >>>>>> precondition(lhs == rhs) >>>>>> return .same >>>>>> } >>>>>> >>>>>> 7) Algorithms using <=> directly should mention so in their >>>>>> documentation as a precondition that they require total order between >>>>>> elements. Many generic algorithms can be defined in terms of == or <, >>>>>> and should. >>>>>> >>>>>> If we took the oroginally planned route that distinguished between >>>>>> identities such as -0.0 vs. +0.0, or between the 2⁴⁹ - 2 ≈ 5.6 × 10¹⁴ >>>>>> possible NaN values that Double has, we'd also need to consider other >>>>>> oddballs like the difference and ordering between the Strings "ä" and >>>>>> "a\u{308}", which are considered equal but produce a different Unicode >>>>>> representation. I think it's best to hide those identities behind >>>>>> another interface than Equatable and Comparable, and let the protocols >>>>>> serve more mundane application logic. >>>>>> >>>>>> — Pyry >>>>>> >>>>>> > Dave Abrahams wrote: >>>>>> > >>>>>> > >>>>>> >> on Sat Jul 23 2016, Xiaodi Wu <xiaodi.wu-AT-gmail.com> wrote: >>>>>> >> >>>>>> >> On Fri, Jul 22, 2016 at 11:34 PM, Stephen Canon <sca...@apple.com> >>>>>> >> wrote: >>>>>> >> >>>>>> >>>> The point of this design is that `===` means identity and that >>>>>> >>>> `.same ` >>>>>> >>>> also means identity. >>>>>> >>>> >>>>>> >>>> Since this is new territory I suppose we get to decide what identity >>>>>> >>>> means for floating point. Should +0 and -0 have the same identity >>>>>> >>>> or >>>>>> >>>> not? I’ll leave the answer to folks more knowledgable about >>>>>> >>>> numerics >>>>>> >>>> than I. >>>>>> >>> >>>>>> >>> Boy, I take my wife out for a movie and come back to 50 new messages >>>>>> >>> on SE. >>>>>> >>> >>>>>> >>> I need to read the entire thread more carefully, but off the top of >>>>>> >>> my >>>>>> >>> head, I think that `-0 === +0` is False. If we’re going to have an >>>>>> >>> `isSame` / `isIdentical` / whatever it's called, I would expect it >>>>>> >>> to imply >>>>>> >>> substitutability. Although -0 == +0, they are not equivalent when >>>>>> >>> substituted: >>>>>> >>> >>>>>> >>> - 1/(-0) != 1/0 >>>>>> >>> - Float(-0).sign != Float(+0).sign >>>>>> >>> - etc >>>>>> >>> >>>>>> >>> This probably then implies that `<=>` is not `.same` either. I’ll >>>>>> >>> read >>>>>> >>> the rest of this and respond more completely tomorrow. >>>>>> >> >>>>>> >> Eagerly await your evaluation of the discussion. In the meantime: >>>>>> >> >>>>>> >> I think Dave's view that `===` defines identity in terms of >>>>>> >> "essential" >>>>>> >> qualities implies that two identical values can be >>>>>> >> different/non-substitutable in "inessential" qualities. For generic >>>>>> >> purposes, the sign of zero could be one such inessential quality. >>>>>> > >>>>>> > Yes, and I think our view of how people work with numbers in swift (and >>>>>> > their protocol conformances) reflect this approach. >>>>>> > >>>>>> > http://article.gmane.org/gmane.comp.lang.swift.evolution/16321 >>>>>> > >>>>>> > My sense is that we want to choose the default notions of identity and >>>>>> > ordering so as to support the way people think about these numeric >>>>>> > types, inexact though it may be. Therefore, finding 0.0 in a sequence >>>>>> > of floats should succeed when the sequence contains -0.0, and a stable >>>>>> > sort on floating point keys should preserve the relative order of all >>>>>> > elements having +0.0 and -0.0 keys. >>>>>> > >>>>>> > People that want to work with inessential qualities such as the sign of >>>>>> > zero can always pass Float.totalOrdering (or whatever) to their >>>>>> > closure-accepting algorithms. >>>>>> > >>>>>> > [In order to support the user model, we still need to fix the semantics >>>>>> > of the default identity and ordering operations so that things like >>>>>> > sorting and searching work, which is why == and < won't cut it for >>>>>> > these >>>>>> > purposes] >>>>>> > >>>>>> >> On the other hand, the stdlib stride algorithm is going to be borked >>>>>> >> if -0 >>>>>> >> < +0. Of course, as we already started to do there, we could >>>>>> >> specialize for >>>>>> >> floating point and then adjust accordingly. However, it seems to me >>>>>> >> that >>>>>> >> every generic algorithm that performs comparisons and can take >>>>>> >> floating >>>>>> >> point arguments would have to be specialized to account for floating >>>>>> >> point >>>>>> >> -0 != +0 (`index(of:)` being the previous example). This appears to >>>>>> >> defeat >>>>>> >> the aim of trying to accommodate FP at all in this revised design for >>>>>> >> Comparables. >>>>>> > >>>>>> > Yes, that would be a disaster, generically speaking. >>>>>> > >>>>>> >> The argument for `-0 === +0` is that -0 and +0 should be equivalent >>>>>> >> when >>>>>> >> substituted for every comparison operation. For FP operations, you'd >>>>>> >> continue to test (as you have to test now) `a == b && a.sign == >>>>>> >> b.sign` if >>>>>> >> you cared about the sign of zero. For non-FP arithmetic operations, >>>>>> >> hmm, >>>>>> >> not sure how to square that circle. >>>>>> > >>>>>> > I followed all of this... except, what are you getting at with that >>>>>> > last >>>>>> > sentence? >>>>>> > >>>>>> > -- >>>>>> > Dave >>>>>> > _______________________________________________ >>>>>> > 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 >>>> >>> >> >> >> _______________________________________________ >> 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
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution