Can we get rid of cooperative equality?

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.

1 Like

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 Floats and Doubles have fewer bits to store the value than Ints and Longs.

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.