On Tue, Oct 31, 2017 at 10:50 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote:
> On Tue, Oct 31, 2017 at 10:23 PM, David Sweeris <daveswee...@mac.com> > wrote: > >> >> On Oct 31, 2017, at 7:26 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote: >> >> On Tue, Oct 31, 2017 at 5:56 PM, David Sweeris <daveswee...@mac.com> >> wrote: >> >>> >>> On Oct 31, 2017, at 09:07, 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)! { >>> } >>> >>> // Programmer considers NaNs. Unchanged from what we have currently, >>> // except that we replace || with ??. >>> if a == b ?? (a.isNaN && b.isNaN) { >>> } >>> >>> 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”. >>> >>> >>> One more thought — and it’s crazy enough that I’m not even sure it’s >>> worth posting — does Swift’s `Equatable` semantics require that `(a == b) >>> != (a != b)` *always* evaluate to `true`? >>> >> >> Yes. `!=` is an extension method that cannot be overridden >> >> >> Wait, what? So if I have a `Password` type, and want to trigger extra >> logging if the `!=` function is called too many times within a second or >> something, that won't get called in generic code? That seems... >> unintuitive... >> > > That's correct, as it is for all protocol extension methods (for example, > most of the collection APIs). > Incidentally, even if it were desirable to log on comparison, why would you want to log only if `!=` returns `true` and not when `==` returns `false`?
_______________________________________________ swift-dev mailing list swift-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-dev