<div dir="ltr">On Sat, Apr 15, 2017 at 3:12 PM, Dave Abrahams via swift-evolution <span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br>
on Thu Apr 13 2017, Xiaodi Wu <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br>
<br>
> Getting this sorted out is definitely a worthwhile effort. I do have<br>
> thoughts about this proposal:<br>
><br>
> I continue to have reservations about an identical spelling (e.g. `==`)<br>
> giving two different answers with the same values of the same type,<br>
> depending on the generic context. It is a very *clever* design, but it is<br>
> also a very *subtle* behavior that I can see leading to much confusion and<br>
> befuddlement for any user who is not well versed *both* in the intricacies<br>
> of IEEE floating point *and* in the intricacies of Swift.<br>
<br>
</span>I can't help but think that the concern over confusion here is not<br>
informed by any realistic situations. Please describe<span class=""><br></span></blockquote><div><br></div><div>To be clear, I'm not claiming that my concerns about the proposal outweigh my enthusiasm for it.</div><div><br></div><div>But here, the confusion I'm concerned about stems from the essential conclusion by the proposal authors that types (including, but not necessarily only limited to FP types) which are ordinarily compared in a way that treats certain "special values" differently must also present an alternative notion of comparison that accounts for all possible values. The special casing of certain values already makes comparison operations difficult to understand; I guess I'm simply stating what is unavoidably true, that having a "non-special-cased" comparison *in addition* to that adds additional difficulty.</div><div><br></div><div>One example where this comes to mind is this: `XCTAssertEqual(+0.0, -0.0)` will pass or fail depending on whether XCTAssertEqual provides a FP-specific specialization. This is something that cannot be determined by reading the testing code itself: that is, it requires not merely knowledge about whether or not the call site "knows" that it's operating on a FP type, but also knowledge about whether XCTest itself is FP-aware.</div><div><br></div><div>The issue increases in difficulty when it comes to non-stdlib types. Suppose I were to write a Rational type. (I am writing a Rational type, but we can talk about that later.) This Rational type is capable of representing NaN (`(0 / 0 as Rational<Int>).isNaN == true`) and, for consistency with FP types, `Rational<Int>.nan != Rational<Int>.nan`. If this proposal is implemented, *I* would be responsible for making XCTest Rational-aware, vending `XCTAssertEqual<Rational<T>>(_:_:)`. In fact, to ensure that users of Rational get the expected behavior everywhere, I would have to vend special Rational-aware versions of every stdlib, core library, and _third-party_ function that is FP-aware, which it is not possible to do.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
> Actually, the fact that this behavior cannot even be achieved without<br>
> currently non-existent compiler features means that it is not possible<br>
> to understand what's truly going on without reading *this document*,<br>
<br>
</span>This doesn't seem like a reasonable argument. New compiler features get<br>
documented outside of the proposals they come from. Nobody's going to<br>
have to go read a proposal to understand what @implements means.</blockquote><div><br></div><div>I do not mean that I seriously believe @_implements will never be documented. (Although, as an underscored attribute, it does not need to be documented outside of the apple/swift repo, in the same way that @_transparent and its ilk are not documented outside the repo.) I am simply saying that fully understanding how `Comparable` and `FloatingPoint` interact with each other will require learning one additional advanced feature of the language than is required now, and that this feature does not even currently exist.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br>
> after mastering *both* IEEE floating point *and* Swift<br>
> generics/protocols/extensions/<wbr>static vs. dynamic dispatch. All to use<br>
> `==` correctly.<br>
<br>
</span>I don't understand this argument. The *whole* point of this proposal is<br>
that you use `==` correctly *without* the need for any special knowledge.<br>
<span class=""><br>
> Which is to say, most people will simply not even know if they happen<br>
> to be using the `==` they did not intend to use.<br>
<br>
</span>Most people aren't aware that IEEE comparison is quirky and don't know<br>
what they intend with respect to those semantics, but anyone who *is*<br>
aware of his intention has an easy way to understand what's happening.<br>
Does this code know it's operating on floating point numbers? If so,<br>
it's IEEE. If not, it's an equivalence relation.<br>
<span class=""><br>
> I think consideration should be given to a design that achieves a<br>
> user-facing but not onerous differentiation between level 1 and level 2<br>
> equality. However, the only one I can think of is essentially a different<br>
> shade of the `PartiallyComparable` alternative already outlined in the<br>
> document.<br>
<br>
</span>I am *deeply* opposed to such a protocol. It is purely syntactic in<br>
nature and thus useless for correctly constraining generic algorithms.<br></blockquote><div><br></div><div>But there do exist types for which some pairs of values cannot be compared to each other. A generic algorithm that blows up if a value cannot be compared to another value should not operate on such types, no?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
People will use it anyway, resulting in algorithms that statically<br>
accept, but are incorrect for, floating point. In my opinion there's<br>
only one feasible answer that doesn't use the static/dynamic distinction<br>
we've proposed: throw IEEE semantics under the bus, making it available<br>
only under a different syntax.<br>
<br>
This would be a drastic move whose primary downside is that floating<br>
point code ported from C would need to be carefully audited and may<br>
become less easy to read. But at least it would be viable.<span class=""><br></span></blockquote><div><br></div><div>Yes I agree that it would be a much more drastic move that would make Swift difficult to use for numerics, and I, at least, would not want to go down that road.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
> Yet I cannot help but think that the rejected alternative may be<br>
> advantageous in one key aspect. `FloatingPoint` comparison is in a<br>
> sense "less refined" (not exactly precise language, I know) than the<br>
> level 2 ordering proposed here, at least in the sense that the latter<br>
> offers more semantic guarantees about the relationships between<br>
> comparison operators.<br>
<br>
</span>No, they are effectively refinement siblings. If it was a hierarchical<br>
relationship, we could just make the floating point types conform to<br>
Equatable. But floating point types are *required* by IEEE to have<br>
comparison semantics that conflict with Equatable.<br>
<span class=""><br>
> It's weird that the less refined `FloatingPoint` refines the more<br>
> refined `Comparable`,<br>
<br>
</span>Do you want to be able to sort floating point numbers without providing<br>
a comparison predicate (one that has to be spelled less obviously than<br>
"<")? If so, floating point numbers must be Comparable. If not, we<br>
could talk about breaking this refinement relationship.<br>
<span class=""><br>
> and I think the acrobatics with compiler support illustrate how the<br>
> design is actively working against Swift's overarching direction.<br>
<br>
</span>It's not more acrobatic than things we already do in the standard<br>
library to ensure that people transparently see the right behavior (see<br>
.lazy), and we could probably even find ways to do it without language<br>
features. It would be less principled, harder to understand, and more<br>
fragile than designing a language feature that addresses the need<br>
directly.</blockquote></div><br></div><div class="gmail_extra">I have an incipient idea. It begins with:</div><div class="gmail_extra"><br></div><div class="gmail_extra">enum ComparisonResult {</div><div class="gmail_extra"> case orderedAscending, orderedSame, orderedDescending, unordered</div><div class="gmail_extra">}</div><div class="gmail_extra"><br></div><div class="gmail_extra">I am sure there is something I am missing which makes this design a horrible idea, but I'm interested in hearing them.</div><div class="gmail_extra"><br></div></div>