We have a bunch of model structs that mostly contains other models and doubles and ints.
With Swift 4.1 we get automatic Equatable implementations and that is great. But a bunch of our unit tests now fails because comparing two Doubles with == fails. Their values are as equal as is practically possible given the circumstances in which they are produced.
To loosen the equals requirements a bit I would like to do something like this
I can’t help but ask: what is the significance of “now” in the above statement. Did existing tests start failing when Equatable was synthesized in 4.1? I can’t think of a reason why that should be so.
Similarly, I wonder: is this humorous understatement? This would be a really, really terrible idea. Apart from the fact that none of your code could compare small values for equality (in other contexts where small differences matter), it could fail with large values, if the representation inaccuracy was above the 0.000001 threshold.
You could try testing the significand rather than the absolute value, but that would leave edge cases in the neighborhood of 0 and 1.
But even that only takes into account the representation inaccuracy (of fixed-width floating point representing real-world values). It still would be wrong if the calculation or measurement error exceeded your threshold.
The reason that fixed-width floating point doesn’t come with a built-in comparison threshold is that it’s an insoluble problem in general. I don’t see that you have any choice but to define a custom threshold test for each of your custom types.
(Also, personally, I wouldn’t use a threshold, but rather round values to a fixed-size grid, then test for equal grid positions. But I don’t know the details of your use-case.)
Extending on what @QuinceyMorris wrote, beyond the particular way the tolerance is applied being a bit crude, making == use a tolerance is always a really bad idea, because:
a) it makes == no longer transitive.
b) it makes == not imply substitutability.*
These are assumptions that a lot of code depends on. Breaking them causes all sorts of trouble.
If you want to compare with a tolerance, use an explicit function, not ==.
[*] == already doesn’t quite imply substitutability for floats because of +/-0, but in practice this distinction almost never matters. The breakage from == having a tolerance is a lot worse. I’m waving my hands a bit here, but it’s really much, much worse.