On Apr 23, 2016, at 6:28 PM, Brent Royal-Gordon via swift-evolution 
<swift-evolution@swift.org> wrote:
> Simple and straightforward, but not actually accurate. In a strict total 
> order, all elements are ordered, but that's not true of the current 
> Comparable. For instance, floating-point NaNs are not ordered.
> In short, I propose we:
> 
> * Introduce a new `<=>` operator which implements a strict total ordering on 
> the Comparable type. Rather than returning a `Bool`, it returns a new `Order` 
> type which is similar to `NSComparisonResult`. This provides a semantic hint 
> that non-ordering is not an option for `<=>`.

I’m generally in favor of moving to a comparison model like you propose, where 
we get a spaceship operator, an “Order” enum with less/equal/greater members, 
and have all the other operators be derived from that.

However, I don’t understand how that would help for floating point NaN 
behavior.  Wouldn’t you have to add a fourth member to the enum (“unordered’) 
that all clients would have to handle?  An approach like that could make sense.

-Chris


> Here's what the new `Comparable` might look like:
> 
>       public enum Order {
>         case firstEarlier
>         case bothEqual
>         case firstLater
>       }
> 
>       /// Instances of conforming types can be compared using relational 
> operators.
>       /// 
>       /// Comparable includes both a total order, which sorts all possible 
> values, 
>       /// and a partial order, which compares only "normal" or "common" 
> values.
>       /// The partial order may consider some elements "unordered" and return 
> `false` 
>       /// for all operations.
>       /// 
>       /// The `<=>` operator implements the total order; the others implement 
> the 
>       /// partial order. You may define only the total order, and 
> `Comparable` will 
>       /// provide default implementations which use it. You may also define 
> both the 
>       /// `<=>` operator and the `<>` "unordered" operator, and Comparable 
> will 
>       /// provide default implementations for the rest of the partial order 
> which them. 
>       /// You may also choose to implement the `<`, `>`, `<=`, `>=`, `==`, 
> and 
>       /// `!=` operators to completely customize the implementation.
>       public protocol Comparable : Equatable {
>         /// A [total 
> order](http://en.wikipedia.org/wiki/Total_order#Strict_total_order)
>         /// over instances of `Self`. In a total order, no element is 
> permitted to be 
>         /// unordered relative to any other.
>         @warn_unused_result
>         func <=> (lhs: Self, rhs: Self) -> Order
>         
>         /// Returns `true` if, to partial order operators like `<` and `==`, 
> `lhs` is 
>         /// unordered relative to `rhs`.
>         @warn_unused_result
>         func <> (lhs: Self, rhs: Self) -> Bool
>         
>         /// Returns `true` if `lhs` is less than `rhs`. Should be consistent 
> with `<=>` except
>         /// when the elements are unordered relative to each other.
>         @warn_unused_result
>         func < (lhs: Self, rhs: Self) -> Bool
>         
>         /// Returns `true` if `lhs` is greater than `rhs`. Should be 
> consistent with `<=>` except
>         /// when the elements are unordered relative to each other.
>         @warn_unused_result
>         func > (lhs: Self, rhs: Self) -> Bool
>         
>         /// Returns `true` if `lhs` is less than or equal to `rhs`. Should be 
> consistent with `<=>` 
>         /// except when the elements are unordered relative to each other.
>         @warn_unused_result
>         func <= (lhs: Self, rhs: Self) -> Bool
>         
>         /// Returns `true` if `lhs` is greater than or equal to `rhs`. Should 
> be consistent with `<=>` except
>         /// when the elements are unordered relative to each other.
>         @warn_unused_result
>         func >= (lhs: Self, rhs: Self) -> Bool
>       }
> 
> Some APIs on Order which might be useful:
> 
>       public extension Order {
>         /// Returns the equivalent order for the two arguments reversed.
>         func reversed() -> Order {…}
>         /// Returns `x` and `y` reordered according to `self`, with the 
> earlier one first.
>         func reorder<T>(_ x: T, _ y: T) -> (T, T) {…}
>         /// Returns `x` and `y` reordered with the earlier one first.
>         static func reorder<T: Comparable>(_ x: T, _ y: T) -> (T, T) {…}
>       }
> 
> Alternate designs:
> 
> * The `<>` operator is arguably not very obvious, or too confusable with some 
> languages' use of that operator for "not equals". It could instead be a 
> different operator, an instance method, or a class method.
> * It might make sense to instead use `<>` to say "is comparable" and `!<>` to 
> say "is incomparable".
> * It may also be better to define Comparable such that certain *values* are 
> incomparable with any value, rather than certain *pairs* of values being 
> incomparable. If so, we would want an `isIncomparable` property instead of a 
> method or function. That works for `FloatingPoint`, but it might not suit 
> other types. (For instance, with the `<>` operator in place, `String.Index` 
> could be made incomparable with indices from other strings, but all 
> `String.Index`es would still have a total order. That design wouldn't be 
> possible with an `isIncomparable` property.)
> * The `<=>` operator is common from other languages, but it might still be 
> too jargony. One interesting design for this would be to expose the total 
> order as a method on `Comparable` which is used as an implementation hook for 
> an `Order.init(_:_:)` initializer.
> * The cases of Order are highly bikesheddable. I like these names more than 
> `ascending` and `descending` because I have an easier time understanding what 
> they mean, but others might disagree.
> * I'm also toying with the idea that the partial order, which includes `==`, 
> may have a looser definition of equality than the total order; this would 
> mean that, for instance, `String`'s total order could fall back to 
> `UnicodeScalar.value` comparison to distinguish between strings which have 
> equal graphemes. I'm not sure how useful that would be in practice, though.
> 
> Any thoughts?
> 
> -- 
> Brent Royal-Gordon
> Architechies
> 
> _______________________________________________
> 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