> On Oct 31, 2017, at 9:07 AM, Stephen Canon via swift-dev 
> <swift-dev@swift.org> wrote:
> 
> [Replying to the thread as a whole]
> 
> 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.
> 
> 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.
> 
> Why do they not help write correct concrete code? The overwhelming majority 
> of cases in which IEEE 754 semantics lead to bugs are due to non-reflexivity 
> of equality, so let’s focus on that. In the cases where this causes a bug, 
> the user has code that looks like this:
> 
>       // Programmer fails to consider NaN behavior.
>       if a == b {
>       }
> 
> but the correct implementation would be:
> 
>       // Programmer has thought about how to handle NaN here.
>       if a == b || (a.isNaN && b.isNaN) {
>       }
> 
> W.r.t ease of writing correct *concrete* code, the task is to make *this* 
> specific case cleaner and more intuitive. What does this look like under 
> other proposed notions of equality? Suppose we make comparisons with NaN trap:
> 
>       // Programmer fails to consider NaN behavior.  This now traps if a or b 
> is NaN.
>       // That’s somewhat safer, but almost surely not the desired behavior.
>       if a == b {
>       }
> 
>       // Programmer considers NaNs. They now cannot use `==` until they rule 
> out
>       // either a or b is NaN. This actually makes the code *more* 
> complicated and
>       // less readable. Alternatively, they use `&==` or whatever we call the 
> unsafe
>       // comparison and it’s just like what we had before, except now they 
> have a
>       // “weird operator”.
>       if (!a.isNaN && !b.isNaN && a == b) || (a.isNaN && b.isNaN) {
>       }
> 
> Now what happens if we return Bool?
> 
>       // Programmer fails to consider NaN behavior.  Maybe the error when they
>       // wrote a == b clues them in that they should. Otherwise they just 
> throw in
>       // a `!` and move on. They have the same bug they had before.
>       if (a == b)! {
>       }

Same bug, yes, but at least it'd crash when the nil gets force-unwrapped.


>       // Programmer considers NaNs. Unchanged from what we have currently,
>       // except that we replace || with ??.
>       if a == b ?? (a.isNaN && b.isNaN) {
>       }

`(a == b) != false` would be more compact (assuming they didn't want to use 
`&==` for some reason), but, yes, that's still not as simple as `a == b`


> If we are going to do the work of introducing another notion of 
> floating-point equality, it should directly solve non-reflexivity of equality 
> *by making equality reflexive*. My preferred approach would be to simply 
> identify all NaNs:
> 
>       // Programmer fails to consider NaN behavior. Now their code works!
>       if a == b {
>       }
> 
>       // Programmer thinks about NaNs, realizes they can simplify their 
> existing code:
>       if a == b {
>       }
> 
> What are the downsides of this?
> 
>       (a) it will confuse sometimes experts who expect IEEE 754 semantics.
>       (b) any code that uses `a != a` as an idiom for detecting NaNs will be 
> broken.
> 
> (b) is by far the bigger risk. It *will* result in some bugs. Hopefully less 
> than result from people failing to consider NaNs. The only real risk with (a) 
> is that we get a biennial rant posted to hacker news about Swift equality 
> being broken, and the response is basically “read the docs, use &== if you 
> want that behavior”.

"<whatever> != <whatever>" is a pretty specific pattern... Could we warn or 
have a fix-it or something on that?


> One specific response:
> 
>> I see the handling of NaN as a legacy/compatibility issue due to 
>> committee/vendor politics from the 1980’s.  I am pretty sure if they could 
>> do it over with modern tech, we would just have isNan() and NaN == NaN… or 
>> we might just have optionals instead.
> 
> With the exception of how they interact with non-floating-point types 
> (comparisons, conversions to/from integers and strings), NaNs are just Maybes 
> with fast hardware support. Integers and booleans and strings are outside the 
> scope of IEEE 754, so it was not in the standard’s purview to do anything 
> else for those operations. They are not some exotic legacy thing leftover 
> from the 1980’s; they were quite ahead of their time.

Agreed. I wish int/string/etc supported that bit of semantics... it'd make 
dealing with floats more consistent with other types.

- Dave Sweeris
_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

Reply via email to