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