<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div><blockquote type="cite" class=""><div class=""><br class="">On Apr 13, 2017, at 3:23 PM, John McCall via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=us-ascii" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class="">On Apr 13, 2017, at 4:17 PM, Ben Cohen via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div dir="auto" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class=""><h3 id="comparisonresult-conveniences" style="color: rgb(17, 17, 17); margin: 21px 0px; font-size: 20px; line-height: 21px; font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;" class="">ComparisonResult Conveniences</h3><p style="color: rgb(17, 17, 17); font-family: 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif; word-wrap: break-word; margin: 1.3125em 0px; font-size: 1.1429em; line-height: 1.3125em;" class="">There are a few conveniences we could consider providing to make ComparisonResult more ergonomic to manipulate. Such as:</p><pre style="margin-top: 21px; margin-bottom: 21px; tab-size: 4; color: rgb(17, 17, 17); font-size: 11.999999046325684px; background-color: rgb(248, 248, 248); height: 140px;" class=""><code class="swift hljs" style="line-height: inherit; display: block; overflow-x: auto; padding: 0.5em; color: rgb(51, 51, 51); height: auto;"><span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// A way to combine orderings</span>
<span class="hljs-function"><span class="hljs-keyword" style="font-weight: bold;">func</span> <span class="hljs-title" style="color: rgb(153, 0, 0); font-weight: bold;">ComparisonResult</span>.<span class="hljs-title" style="color: rgb(153, 0, 0); font-weight: bold;">breakingTiesWith</span><span class="hljs-params">(<span class="hljs-number" style="color: rgb(0, 128, 128);">_</span> order: <span class="hljs-params">()</span></span></span> -> <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">ComparisonResult</span>) -> <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">ComparisonResult</span>
array.<span class="hljs-built_in" style="color: rgb(0, 134, 179);">sort</span> {
$<span class="hljs-number" style="color: rgb(0, 128, 128);">0</span>.x.compare($<span class="hljs-number" style="color: rgb(0, 128, 128);">0</span>.y)
.breakingTiesWith { $<span class="hljs-number" style="color: rgb(0, 128, 128);">0</span>.y.compare($<span class="hljs-number" style="color: rgb(0, 128, 128);">1</span>.y) }
== .orderedAscending
}</code></pre></div></div></div></div></blockquote></div><div class="">The really nice thing about compare being an operator is that you can very nicely combine it with an operator here and get a much more light-weight syntax for chained comparisons, e.g.:</div><div class=""><br class=""></div><div class="">struct MyPoint : Comparable {</div><div class=""> var x, y, z: Double</div><div class=""> func compare(_ other: MyPointer) -> ComparisonResult {</div><div class=""> return self.x <=> other.x || self.y <=> other.y || self.z <=> other.z</div></div></div></blockquote><div><br class=""></div><div>Wow, this is elegant!</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""> }</div><div class="">}</div><div class=""><br class=""></div><div class="">as opposed to, I guess,</div><div class=""> return self.x.compare(other.x).breakingTiesWith { self.y.compare(other.y).breakingTiesWith { self.z.compare(other.z) } }</div><div class=""><br class=""></div><div class="">But this is mostly useful for defining custom comparisons, so perhaps it's not worth having to paint a bikeshed for <=> and whatever the combining operator is.</div></div></div></blockquote><div><br class=""></div><div>For the record, I would strongly prefer `<=>` to an instance `compare` method. That said, I’d also prefer a static `compare` function to the asymmetric instance method if the spelling `compare` were absolutely desired.</div><div><br class=""></div><div>It’s probably worth noting somewhere that an instance `compare` method performs dynamic dispatch on the left-hand argument while a static function (as well as the current operators `==` and `<`) perform static dispatch. I realize NSObject set a precedent with `isEqual:` and `compare:` instance methods, but I’m not convinced that’s necessarily the best design. If dynamic dispatch is desired, an implementation can always delegate to such a method.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""></div><div class="">Also, in this example:</div><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div dir="auto" class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><div class=""><pre class="" style="margin-top: 21px; margin-bottom: 21px; tab-size: 4; color: rgb(17, 17, 17); font-size: 11.999999046325684px; background-color: rgb(248, 248, 248); height: 140px;"><code class="swift hljs" style="line-height: inherit; display: block; overflow-x: auto; padding: 0.5em; color: rgb(51, 51, 51); height: auto;"><span class="hljs-comment" style="color: rgb(153, 153, 136); font-style: italic;">// A way to combine orderings</span>
<span class="hljs-function"><span class="hljs-keyword" style="font-weight: bold;">func</span> <span class="hljs-title" style="color: rgb(153, 0, 0); font-weight: bold;">ComparisonResult</span>.<span class="hljs-title" style="color: rgb(153, 0, 0); font-weight: bold;">breakingTiesWith</span><span class="hljs-params">(<span class="hljs-number" style="color: rgb(0, 128, 128);">_</span> order: <span class="hljs-params">()</span></span></span> -> <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">ComparisonResult</span>) -> <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">ComparisonResult</span>
array.<span class="hljs-built_in" style="color: rgb(0, 134, 179);">sort</span> {
$<span class="hljs-number" style="color: rgb(0, 128, 128);">0</span>.x.compare($<span class="hljs-number" style="color: rgb(0, 128, 128);">0</span>.y)
.breakingTiesWith { $<span class="hljs-number" style="color: rgb(0, 128, 128);">0</span>.y.compare($<span class="hljs-number" style="color: rgb(0, 128, 128);">1</span>.y) }
== .orderedAscending
}</code></pre></div></div></div></blockquote><div class="">Requiring this last "== .orderedAscending" seems like a tragic failure of ergonomics. I understand that sorting doesn't actually require a tri-valued comparison, but is it really worth maintaining two currencies of comparison result over that? Are there any types that can answer '<' substantially more efficiently than they can answer 'compare'? And I assume this is related to why you've kept < in the protocol.</div></div></div></blockquote><div><br class=""></div><div><p style="box-sizing: border-box; margin-bottom: 16px; color: rgb(36, 41, 46); margin-top: 0px !important;" class="">I would strongly support replacing <code style="box-sizing: border-box; padding: 0.2em 0px; margin: 0px; background-color: rgba(27, 31, 35, 0.0470588); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">(T, T) -> Bool</code> with <code style="box-sizing: border-box; padding: 0.2em 0px; margin: 0px; background-color: rgba(27, 31, 35, 0.0470588); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">(T, T) -> ComparisonResult</code> variants.</p><ol style="box-sizing: border-box; padding-left: 2em; margin-top: 0px; margin-bottom: 16px; color: rgb(36, 41, 46);" class=""><li style="box-sizing: border-box; margin-left: 0px;" class="">The <code style="box-sizing: border-box; padding: 0.2em 0px; margin: 0px; background-color: rgba(27, 31, 35, 0.0470588); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">areInIncreasingOrder</code> variant is confusing at the call-site since the definition must be consulted to determine which order the comparison expects.</li><li style="box-sizing: border-box; margin-top: 0.25em; margin-left: 0px;" class="">The <code style="box-sizing: border-box; padding: 0.2em 0px; margin: 0px; background-color: rgba(27, 31, 35, 0.0470588); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">areInIncreasingOrder</code> implementation is very dirty when an <code style="box-sizing: border-box; padding: 0.2em 0px; margin: 0px; background-color: rgba(27, 31, 35, 0.0470588); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;" class="">==</code> result is desired. This is especially bad if we expect other authors to mirror this API:</li></ol><div class="highlight highlight-source-swift" style="box-sizing: border-box; margin-bottom: 16px; color: rgb(36, 41, 46); overflow: visible !important;"><pre style="box-sizing: border-box; font-family: SFMono-Regular, Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 11.899999618530273px; margin-top: 0px; margin-bottom: 0px; line-height: 1.45; word-wrap: normal; padding: 16px; overflow: auto; background-color: rgb(246, 248, 250); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal;" class=""><span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">if</span> <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">!</span><span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">areInIncreasingOrder</span>(a, b) <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">&&</span> <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">!</span><span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">areInIncreasingOrder</span>(b, a) {
<span class="pl-c" style="box-sizing: border-box; color: rgb(150, 152, 150);"><span class="pl-c" style="box-sizing: border-box;">//</span> equal!</span>
<span class="pl-c" style="box-sizing: border-box; color: rgb(150, 152, 150);"></span>}</pre></div><div style="box-sizing: border-box; margin-top: 0px; color: rgb(36, 41, 46); margin-bottom: 0px !important;" class="">Not only is this unintuitive, but it is also less performant in many cases.</div></div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""></div><div class="">John.</div></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></body></html>