<div dir="ltr">On Tue, Apr 18, 2017 at 10:40 AM, Ben Cohen 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:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><br><div><span class=""><blockquote type="cite"><div>On Apr 17, 2017, at 9:40 PM, Chris Lattner via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:</div><br class="m_844702649746363335Apple-interchange-newline"><div><div><br><blockquote type="cite">On Apr 17, 2017, at 9:07 AM, Joe Groff via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:<br><br><br><blockquote type="cite">On Apr 15, 2017, at 9:49 PM, Xiaodi Wu via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:<br><br>For example, I expect `XCTAssertEqual&lt;T : FloatingPoint&gt;(_:_:)` to be vended as part of XCTest, in order to make sure that `XCTAssertEqual(<wbr>resultOfComputation, Double.nan)` always fails.<br></blockquote><br>Unit tests strike me as an example of where you really *don&#39;t* want level 1 comparison semantics. If I&#39;m testing the output of an FP operation, I want to be able to test that it produces nan when I expect it to, or that it produces the right zero.<br></blockquote><br>I find it very concerning that == will have different results based on concrete vs generic type parameters.  This can only lead to significant confusion down the road.  I’m highly concerned about situations where taking a concrete algorithm and generalizing it (with generics) will change its behavior.<br><br></div></div></blockquote><div><br></div></span><div>It is already the case that you can start with a concrete algorithm, generalize it, and get confusing results – just with a different starting point. If you start with a concrete algorithm on Int, then generalize it to all Equatable types, then your algorithm will have unexpected behavior for floats, because these standard library types fail to follow the rules explicitly laid out for conforming to Equatable. </div><div><br></div><div>This is bad. Developers need to be able to rely on those rules. The standard library certainly does:</div><div><br></div><div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures;color:#ba2da2">let</span><span style="font-variant-ligatures:no-common-ligatures"> a: [</span><span style="font-variant-ligatures:no-common-ligatures;color:#703daa">Double</span><span style="font-variant-ligatures:no-common-ligatures">] = [(</span><span style="font-variant-ligatures:no-common-ligatures;color:#272ad8">0</span><span style="font-variant-ligatures:no-common-ligatures">/</span><span style="font-variant-ligatures:no-common-ligatures;color:#272ad8">0</span><span style="font-variant-ligatures:no-common-ligatures">)]</span></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo"><span style="font-variant-ligatures:no-common-ligatures;color:#ba2da2">var</span><span style="font-variant-ligatures:no-common-ligatures"> b = </span><span style="font-variant-ligatures:no-common-ligatures;color:#4f8187">a</span></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><span style="font-variant-ligatures:no-common-ligatures"></span><br></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><span style="color:rgb(0,132,0)">// true, because fast path buffer pointer comparison:</span></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0)"><span style="font-variant-ligatures:no-common-ligatures;color:#4f8187">a</span><span style="font-variant-ligatures:no-common-ligatures;color:#000000"> == </span><span style="font-variant-ligatures:no-common-ligatures;color:#4f8187">b</span></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0)"><span style="font-variant-ligatures:no-common-ligatures;color:#4f8187"><br></span></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(62,30,129)"><div style="margin:0px;font-stretch:normal;line-height:normal;color:rgb(0,132,0)"><span style="font-variant-ligatures:no-common-ligatures;color:#4f8187">b</span><span style="font-variant-ligatures:no-common-ligatures;color:#000000">.</span><span style="font-variant-ligatures:no-common-ligatures;color:#3e1e81">reserveCapacity</span><span style="font-variant-ligatures:no-common-ligatures;color:#000000">(</span><span style="font-variant-ligatures:no-common-ligatures;color:#272ad8">10</span><span style="font-variant-ligatures:no-common-ligatures;color:#000000">) </span><span style="font-variant-ligatures:no-common-ligatures">// force a reallocation</span></div><div><span style="font-variant-ligatures:no-common-ligatures"><br></span></div></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0)"><span style="font-variant-ligatures:no-common-ligatures;color:#4f8187"><span style="color:rgb(0,132,0)">// now false, because memberwise comparison and nan != nan,</span></span></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0)"><span style="font-variant-ligatures:no-common-ligatures;color:#4f8187"><span style="color:rgb(0,132,0)">// violating the reflexivity requirement of Equatable:</span></span></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0)"><span style="font-variant-ligatures:no-common-ligatures;color:#4f8187">a</span><span style="font-variant-ligatures:no-common-ligatures;color:#000000"> == </span><span style="font-variant-ligatures:no-common-ligatures;color:#4f8187">b</span><span style="font-variant-ligatures:no-common-ligatures;color:#000000"> </span></div><div style="margin:0px;font-stretch:normal;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><br><span style="font-variant-ligatures:no-common-ligatures"></span></div></div><div><br></div><div>Maybe we could go through and special-case all the places in the standard library that rely on this, accounting for the floating point behavior (possibly reducing performance as a result). But we shouldn&#39;t expect users to.</div></div></div></blockquote><div><br></div><div>I was not thinking about the issue illustrated above, but this is definitely problematic to me.</div><div><br></div><div>To be clear, this proposal promises that `[0 / 0 as Double]` will be made to compare unequal with itself, yes? It is very clear that here we are working with a concrete FP type and not in a generic context, and thus all IEEE FP behavior should apply.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><div><div>This is a bump in the rug – push it down in one place, it pops up in another. I feel like this proposal at least moves the bump to where fewer people will trip over it. I think it highly likely that the intersection of developers who understand enough about floating point to write truly correct concrete code, but won’t know about or discover the documented difference in generic code, is far smaller than the set of people who hit problems with the existing behavior.</div></div></div></blockquote><div><br></div><div>So, to extend this analogy, I&#39;d rather say that the bump is not in the rug [Comparable] but rather in a section of the floor [FP NaN]. The rug might overlie the bump, but the bump will always be there and people will find it as they walk even if they don&#39;t immediately see it. If we don&#39;t want people to trip over the bump while walking on the rug, one very good alternative, IMHO, is to shape the rug so that it doesn&#39;t cover the bump.</div><div><br></div><div>My purpose in exploring an alternative design is to see if it would be feasible for non-FP-aware comparison operators to refuse to compare NaN, rather than giving different answers depending on context. I now strongly believe that this may make for a design simultaneously _less_ complex *and* _more_ comprehensive (as measured by the flatness-of-rug metric).</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><div><div></div><div><div> A more comprehensive solution, with additional protocols or overloads, representation of unordered comparison etc, might be able to flatten the rug completely, but probably at the cost of introducing complexity that could act as a barrier to entry into the world of writing generic code.</div></div><div><br></div><blockquote type="cite"><div><div>-Chris<span class=""><br><br>______________________________<wbr>_________________<br>swift-evolution mailing list<br><a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br></span></div></div></blockquote></div><br></div><br>______________________________<wbr>_________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br>
<br></blockquote></div><br></div></div>