On Tue, Oct 31, 2017 at 23:43 David Sweeris <daveswee...@mac.com> wrote:
> > On Oct 31, 2017, at 20:58, Xiaodi Wu <xiaodi...@gmail.com> wrote: > > 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`? > > > Mostly because if I ever wrote a Password class, I’d probably make it > handle all the hashing and stuff internally so that the correct usage would > look like `if enteredPW != storedPW {...}`. I know they’re (generally) the > same, but I tend to think `_ != _` rather than `!(_ == _)`. > > I know it’d be a different thread (on a different mailing list), but does > anyone care if I propose that we change this? I’m strongly in favor of > providing a default implementation of !=, but I can’t think of why it > shouldn’t just be a *default* method... with the developers still having > the option to provide their own if they think they can get there faster > than the default implementation (or maybe even just because they want to > set a breakpoint on `!=` but not `==` or something). > You’d have to provide a convincing use case, but I’m not aware of one where evaluating “if x != y” should ever be different from “if !(x == y)”. Certainly, if you want != to log something, you would want == to log something. It is a feature, not a bug, that Swift guarantees that these are synonyms. >
_______________________________________________ swift-dev mailing list swift-dev@swift.org https://lists.swift.org/mailman/listinfo/swift-dev