<div dir="ltr">Ben Cohen asked to continue this conversation on swift-dev--<div><br></div><div><br></div><div>Included in PR #12503 is a small tweak to accommodate so-called &quot;exceptional values&quot; (such as NaN) in comparisons of array equality.</div><div><br></div><div>Currently, `Array.==` first looks to referential equality of underlying buffers, then (if false) compares elementwise equivalence as defined by `Element.==`. As a consequence, an array of NaN compares equal to another array of NaN if they share the same buffer, but otherwise false. This is an undesirable outcome.</div><div><br></div><div>In my analysis, this problem in fact comprises two issues.</div><div><br></div><div><br></div><div># The proximate issue</div><div><br></div><div>The proximate issue is that `Array.==` is exposing an implementation detail that the user should not need to reason about. Regardless of whether or not it is wise for the partial equivalence relation `FloatingPoint.==` to be deemed as semantically satisfactory for the purposes of `Equatable`, the fact remains that Swift deliberately ships with such a conformance, and `Array.==` should not blow up given that explicitly contemplated design decision. This PR resolves that proximal issue.</div><div><br></div><div>I believe that this fix is strictly an improvement upon the status quo and orthogonal to the second, more distal issue.</div><div><br></div><div># The distal issue</div><div><br></div><div>The distal issue has to do with `FloatingPoint.==` and the conformance of that protocol to `Equatable`.</div><div><br></div><div>The last time that this topic was brought up, competing demands voiced by different people were not possible to reconcile:</div><div><br></div><div>1) Equatable `==` must be a full equivalence relation.</div><div><br></div><div>2) Floating-point types must conform to `Equatable` and not to some alternative such as `PartiallyEquatable`.</div><div><br></div><div>3) Floating-point `==` must be IEEE-compliant (at least in the concrete context), and therefore *not* a full equivalence relation.</div><div><br></div><div>4) IEEE-compliant floating-point equivalence must be spelled `==` and not some alternative such as `&amp;==`.</div><div><br></div><div>5) Behavior of `==` must not change between generic and concrete contexts.<br></div><div><br></div><div>Any solution must abolish one or more of the above must-haves. The questions to be settled before any API-changing issues are broached are therefore:</div><div><br></div><div>A) Must `Equatable.==` be a full equivalence relation?</div><div><br></div><div>By explicitly allowing exceptions in the documentation written for `Comparable`, and by vending `FloatingPoint : Equatable`, the Swift standard library currently tolerates `==` being a partial equivalence relation, but some standard library algorithms assume that it is a full equivalence relation.</div><div><br></div><div>In my view, this is an open topic for debate, as a non-trivial number of generic algorithms can tolerate a partial equivalence relation (if NaN != NaN, then it&#39;s perfectly correct for Set not to deduplicate NaNs). Other algorithms can be explicitly documented to require all elements to be in the domain of arguments for a full equivalence relation and/or take a custom predicate.</div><div><br></div><div>B) Must floating-point types conform to `Equatable`?</div><div><br></div><div>In my view, this is clear, and I don&#39;t believe it&#39;s a very controversial opinion. Chris Lattner (I think?) was the one who pointed out that the Rust experience with PartialEq and Eq, PartialOrd and Ord has been unsuccessful because the same problems are being punted to PartialEq and PartialOrd. The idea is that people avoid writing generic algorithms that exclude the use of floating-point types; therefore, whatever protocol guarantees some relation named `==` and includes both floating-point types and other types will be the one that&#39;s used for generic algorithms, even if users need full equivalence semantics not guaranteed by that protocol.</div><div><br></div><div>C) Must (concrete) floating-point `==` be IEEE-compliant?</div><div><br></div><div>In my view, yes; the alternative would make Swift utterly unsuitable for numerics. I don&#39;t believe this is very controversial.</div><div><br></div><div>D) Must floating-point IEEE-compliant equivalence be spelled `==`?</div><div><br></div><div>In my view, this is something open for debate. I see no reason why it cannot be migrated to `&amp;==` if it were felt that `==` *must* be a full equivalence relation. I believe this is controversial, however.</div><div><br></div><div>E) Must the behavior of `==` be the same in generic and concrete contexts?</div><div><br></div><div>In my view, it absolutely must be. Differing behavior in generic and concrete contexts is simply too subtle to be understandable to the reader. The explanation that a method on `Float` is a &quot;floating-point context&quot; but a method on `[Float]` is *not a &quot;floating point context&quot;* is, IMO, indefensible.</div><div><br></div><div><br></div></div>