Can we have a strict comparison like ===
that behaves strictly, e.g. not compiling 1 == 1L
, as wished by lots of people in this thread, and make ==
consistent to Java or whatever? Using ==
in programs can introduce really unexpected bugs and the language should offer a stricter version IMHO, so users don’t have to go for scalaz for such basic stuff.
What would ===
mean? As noted earlier, ==
is in general equivalent to:
How would ===
be defined?
Well most importantly it would have the same type for both arguments
final def === (that: A): Boolean = ...
where A
is type of this
.
At best you could define that as an extension method:
implicit final class EqOps[A](val self: A) extends AnyVal {
def === (that: A): Boolean = ??? // How is this defined though?
}
However, that can’t be defined on Any
like ==
is.
Additionally, what is the right-hand side? is it just a call to ==
?
And what about collections? If you want to compare a List
and a Vector
, do you need to cast them to Seq
?
I was looking into Float
recently, so I’ll note this here.
scala> for {
i <- 0 to 64
} {
val x: Int = Int.MaxValue - i
val y: Float = (1L << 31).toFloat
println(s"$i: x = $x; y = $y; x == y: ${x == y}; x.## == y.##: ${x.## == y.##}")
}
0: x = 2147483647; y = 2.14748365E9; x == y: true; x.## == y.##: false
1: x = 2147483646; y = 2.14748365E9; x == y: true; x.## == y.##: false
2: x = 2147483645; y = 2.14748365E9; x == y: true; x.## == y.##: false
...
63: x = 2147483584; y = 2.14748365E9; x == y: true; x.## == y.##: false
64: x = 2147483583; y = 2.14748365E9; x == y: false; x.## == y.##: false
This shows that Int
to Float
is lossy, which makes sense because it’s a binary faction with 23 bits in the significand.
scala> Set[Float](2147483584, 2147483645, 2147483646, 2147483647)
res1: scala.collection.immutable.Set[Float] = Set(2.14748365E9)
This is not a specific phenomena to Float
. We can do the same with Double
using Long
.
scala> Set[Double](99999999991234561L, 99999999991234562L, 99999999991234563L)
res2: scala.collection.immutable.Set[Double] = Set(9.999999999123456E16)
I think the problem is not just cooperative equality, but weak conformance involving IEEE floats.
I don’t think the integer to floating point problem is particular to IEEE floating point behaviour (and numeric equivalence); just to the fact that Float
s and Double
s have fewer bits to store the value than Int
s and Long
s.
scalafix 0.6.0-M4+ lets you disable Object.equals/hashCode. e.g. see my config https://gitlab.com/fommil/drone-dynamic-agents/blob/master/project/scalafix.conf and further improvements in the semanticdb will ensure reliability will improve over time.
Thus ends my interest in this topic.