<div dir="ltr">On Thu, Nov 2, 2017 at 5:22 PM, Matthew Johnson <span dir="ltr">&lt;<a href="mailto:matthew@anandabits.com" target="_blank">matthew@anandabits.com</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:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><br><div><blockquote type="cite"><span class="gmail-"><div>On Nov 2, 2017, at 5:20 PM, Jonathan Hull via swift-dev &lt;<a href="mailto:swift-dev@swift.org" target="_blank">swift-dev@swift.org</a>&gt; wrote:</div><br class="gmail-m_9196866851710290294Apple-interchange-newline"></span><div><div style="overflow-wrap: break-word;"><span class="gmail-">It looks like we have a good solution.  Per Steve and David’s suggestions:<div><br></div><div>1) Make FloatingPoint == reflexive</div><div><br></div><div>2) Add &amp;== to FloatingPoint for those who specifically want IEEE behavior</div><div><br></div><div>3) Add a warning + fixit to ‘a != a’ </div><div><br></div></span><div>We should take this to evolution…</div></div></div></blockquote><div><br></div>Looks like a winner to me.</div></div></blockquote><div><br></div><div>Again, there remain several problems with this design. In the concrete context, the syntax `&amp;==` suggests that it is a compatibility, legacy, or specialized function not to be preferred over `==`. This makes Swift deviate from every other programming language, creating a new footgun for experienced developers, and encourages a performance hit where one is not demonstrably necessary (most operations that ask about UI coordinates, say, will never have NaN as an input). Again also, this design eliminates the possibility of writing a class of useful algorithms that use Numeric. It also doesn&#39;t address the problem of sorting (as NaN would still compare unordered to all other values). These are serious questions that require careful consideration.<br></div><div><br></div><div>In initiating this conversation, my goal has been to start a conversation about possible designs for `Equatable` and `Comparable` that permis useful generic algorithms to work correctly with floating point without hampering performance or changing syntax for concrete numerics. Unless this is clearly impossible, the leap of changing the behavior of `==` for a numeric type should absolutely not be the proposed solution, in my view.<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><div class="gmail-h5"><div><blockquote type="cite"><div><div style="overflow-wrap: break-word;"><div><br><div><blockquote type="cite"><div>On Nov 1, 2017, at 10:02 AM, Stephen Canon via swift-dev &lt;<a href="mailto:swift-dev@swift.org" target="_blank">swift-dev@swift.org</a>&gt; wrote:</div><br class="gmail-m_9196866851710290294Apple-interchange-newline"><div><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><blockquote type="cite" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">On Nov 1, 2017, at 12:51 PM, Greg Titus via swift-dev &lt;<a href="mailto:swift-dev@swift.org" target="_blank">swift-dev@swift.org</a>&gt; wrote:<br><br><blockquote type="cite">On Nov 1, 2017, at 9:16 AM, Ben Cohen via swift-dev &lt;<a href="mailto:swift-dev@swift.org" target="_blank">swift-dev@swift.org</a>&gt; wrote:<br><blockquote type="cite">On Oct 31, 2017, at 10:11 PM, Chris Lattner via swift-dev &lt;<a href="mailto:swift-dev@swift.org" target="_blank">swift-dev@swift.org</a>&gt; wrote:<br>On Oct 31, 2017, at 9:07 AM, Stephen Canon via swift-dev &lt;<a href="mailto:swift-dev@swift.org" target="_blank">swift-dev@swift.org</a>&gt; wrote:<br><blockquote type="cite">[Replying to the thread as a whole]<br><br>There have been a bunch of suggestions for variants of `==` that either trap on NaN or return `Bool?`. I think that these suggestions result from people getting tunnel-vision on the idea of “make FloatingPoint equality satisfy desired axioms of Equatable / Comparable”. This is misguided. Our goal is (should be) to make a language usable by developers; satisfying axioms is only useful in as much as they serve that goal.<br><br>Trapping or returning `Bool?` does not make it easier to write correct concrete code, and it does not enable writing generic algorithms that operate on Comparable or Equatable. Those are the problems to be solved.<br></blockquote><br>+100.  Swift isn’t the first language to face the problems of floating point, nor is it the first to try to shoehorn it into a framework like Equatable.  <br></blockquote><br>Java and C# do not have this problem with their generic algorithms (albeit possibly because of limitations in their languages that Swift doesn’t have). Swift is setting itself up as a major language with confusing and unjustifiable behavior by comparison. That some other languages are also bad at this doesn’t seem relevant.<br></blockquote><br>The common (and correct!) wisdom in _any_ programming language that uses IEEE floating point is that checking equality of two floating point values is almost always a terrible idea. Usually what you want in any real world code is to check for a difference less than some epsilon value, which depends upon context. There are just too many issues with values that aren’t exactly representable, rounding errors during computations, et cetera, for perfectly normal floats even if you completely left aside equality rules for NaN.<br></blockquote><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline">The common wisdom is fundamentally bogus. One should *often* use a tolerance for floating-point comparison, but there’s a whole host of situations in which exact equality is perfectly appropriate. Of particular note for us, those situations include most generic contexts based on Equatable or Comparable.</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span class="gmail-m_9196866851710290294Apple-tab-span" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:pre-wrap;word-spacing:0px">        </span><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline">s.contains(2)</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline">should not return `true` if `s` contains something two-ish. It should return `true` if and only if `s` contains the actual value `2`.</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline">One might want to have an additional method on sets of FloatingPoint-conforming types that uses a tolerance, but contains should do precisely what it says on the tin.</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><blockquote type="cite" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">I completely understand the desire in this thread to make floating point really satisfy the axioms of Equatable, but the fact is, even if you did, using a generic algorithm that depends upon equatability with floating point types is almost always just a programming error waiting to happen. It’s implicit in the representation and use of floating point values themselves, no matter what particular implementation you decide on for == or &amp;==.<br><br>If you really want to make the language better for developers, provide and emphasize fixed point or infinite precision or rational types for doing various things instead, and encourage them to shun floats as much as possible. If you really need to change anything about the standard library of Swift, my preferred solution would be to continue to provide ==(lhs : Float, rhs: Float) and != but NOT declare conformance to Equatable at all so that generic algorithms involving floats would fail to compile.<br></blockquote><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline">Fixed point representations have their place[1], but rationals are strictly worse than floating-point representations in every way except for their ability to exactly represent 1/3 in toy problems and efficiency of division until you saturate the size of the denominator. I am not exaggerating. They waste space, they have a highly non-uniform distribution of representable values, they have many redundant representations, and denominators grow exponentially in almost every non-toy problem.</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline">Floating-point is the worst approximation to the real numbers except for all the others.</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline">– Steve</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline">[1] Unfortunately they are generally unusable for libraries due to complete lack of scale invariance. This can be worked around, but doing so requires more hand-holding than floating-point.</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline">______________________________<wbr>_________________</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><span style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px;float:none;display:inline">swift-dev mailing list</span><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><a href="mailto:swift-dev@swift.org" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" target="_blank">swift-dev@swift.org</a><br style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><a href="https://lists.swift.org/mailman/listinfo/swift-dev" style="font-family:Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-dev</a></div></blockquote></div><br></div></div>______________________________<wbr>_________________<br>swift-dev mailing list<br><a href="mailto:swift-dev@swift.org" target="_blank">swift-dev@swift.org</a><br><a href="https://lists.swift.org/mailman/listinfo/swift-dev" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-dev</a><br></div></blockquote></div><br></div></div></div></blockquote></div><br></div></div>