[swift-evolution] [pitch] Comparison Reform

Dave Abrahams dabrahams at apple.com
Mon Apr 17 11:36:48 CDT 2017


on Sun Apr 16 2017, Xiaodi Wu <swift-evolution at swift.org> wrote:

> On Sun, Apr 16, 2017 at 1:13 AM, Dave Abrahams via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>> <snip>
>>
>>> > I have an incipient idea. It begins with:
>> >> >
>> >> > enum ComparisonResult {
>> >> >   case orderedAscending, orderedSame, orderedDescending, unordered
>> >> > }
>> >> >
>> >> > I am sure there is something I am missing which makes this design a
>> >> > horrible idea, but I'm interested in hearing them.
>> >>
>> >> It's not a horrible idea, but to be fair it's not really a design yet,
>> >> either.  You haven't said anything about what it's supposed to mean, how
>> >> it is supposed to be used, how people write, use, and compose generic
>> >> algorithms with it, how it deals with floating point, etc.
>> >>
>> >
>> > I've evolved my thinking based on the discussion. Let's see:
>> >
>> > ```
>> > public enum ComparisonResult : Equatable {
>> >   case orderedAscending, equivalent, orderedDescending, unordered
>> >   // I have renamed one case, in the hopes of emphasizing that two values
>> >   // that compare `equivalent` are not merely ordered the same, but
>> should
>> >   // satisfy the three conditions of an equivalence relation.
>> > }
>> > // I will have to leave the question of how to bridge from Obj-C
>> > // NSComparisonResult up to more capable hands.
>> >
>> > public protocol Comparable : Equatable {
>> >   func compared(to other: Self) -> ComparisonResult
>> > }
>> > // This will have to be modified as necessarily to support compiler magic
>> > // necessary for source-compatibility with Swift 3
>> >
>> > extension Comparable {
>> >   public static func == (lhs: Self, rhs: Self) -> Bool {
>> >     let comparison = lhs.compared(to: rhs)
>> >     precondition(comparison != .unordered)
>> >     return comparison == .equivalent
>> >   }
>> >
>> >   public static func < (lhs: Self, rhs: Self) -> Bool {
>> >     let comparison = lhs.compared(to: rhs)
>> >     precondition(comparison != .unordered)
>> >     return comparison == .orderedAscending
>> >   }
>> >   // etc.
>> >
>> >   // Something I thought I'd never want to see, but on reflection not
>> > terrible:
>> >   public static func &== (lhs: Self, rhs: Self) -> Bool {
>> >     return lhs.compared(to: rhs) == .equivalent
>> >   }
>> >
>> >   public static func &< (lhs: Self, rhs: Self) -> Bool {
>> >     return lhs.compared(to: rhs) == .orderedAscending
>> >   }
>> >   // etc.
>> > }
>> >
>> > extension FloatingPoint : Comparable {
>> >   public func compared(to other: Self) -> ComparisonResult {
>> >     if isNaN || other.isNaN { return .unordered }
>> >     if isLess(than: other) { return .orderedAscending }
>> >     if other.isLess(than: self) { return .orderedDescending }
>> >
>> >     // On reconsideration, probably actually least surprising if +0.0 ==
>> > -0.0
>> >     // no matter what. It does not matter that division can give
>> different
>> >     // results for two equivalent values, only that the three rules of an
>> >     // equivalence relation will hold, and it does.
>> >     //
>> >     // If a user is really savvy to the sign of zero, there is
>> > FloatingPoint.sign,
>> >     // which is necessary in any case for working with FP operations that
>> >     // distinguish between +0 and -0. I can't think of a generic
>> algorithm
>> > over
>> >     // all Comparable types that could make use of the distinction
>> between
>> > +0
>> >     // and -0.
>> >     return .equivalent
>> >   }
>> > }
>> > ```
>> >
>> > In this design, `==`, `<`, etc. correspond to IEEE "signaling" operators,
>> > while `&==`, `&<`, etc. correspond to C-style operators, which IEEE calls
>> > "quiet" and actually notates using "?==", "?<", etc.
>>
>> It's interesting, but what's missing here is a description of the user
>> model.  How do users program with this design?  What should my
>> expectations be w.r.t. generic algorithms like sort() and floating point
>> numbers, particularly NaN?  If, as I suspect, sorting a collection
>> containing NaN is going to trap (unless the collection has only one
>> element?), why is that the right behavior?
>
> I've spent some time fleshing out this idea:
> https://gist.github.com/xwu/e864ffdf343160a8a26839388f677768

More interesting still, but you still failed to answer the final
question above.

-- 
-Dave



More information about the swift-evolution mailing list