Equal protection under Eq law

Hi, I’ve been thinking equality lately, and I wrote ‘equal protection under Eq law’.

Here’s the short version: The relationship given to Int and Long should be exactly the same as the relationship third-party library like Spire can write UInt or Rational with the first-class numeric types.

  • We should make 1 == 1L an error under strictEquality
  • We should allow custom types to participate in constant expression conversion using FromDigits

why?

Besides making the comparison of Int and Long more consistent with what’s available to UInt etc, the benefit for this is making == closer to Any#equals method. We won’t be able to immediately remove cooperative equality, but this opens the possibility to remove cooperative equality down the line if / when strict equality becomes the default mode.

Previous discussion on this topic - Can we get rid of cooperative equality?

6 Likes

As I mentioned on this issue, I think if we removed == and != from Any and implemented them as extension instead, it would have solved all our troubles (and perhaps added others).

5 Likes

If we can drastically redesign == that might solve many problems but as Martin wrote there we need to work under the constraints of keeping the compatibility and interoperability with Scala 2.13.

Making 1 == 1L not compile is a few tweaks to the existing multiversal equality mechanism. Here’s a quick implementation I attempted - https://github.com/lampepfl/dotty/pull/8303

REPL demo looks like this:

scala> 1 == 1L
val res0: Boolean = true

scala> 1 != 1L
val res1: Boolean = false

scala> {
     |   import scala.language.strictEquality
     |   val l = 1L
     |   l == 1
     | }
4 |  l == 1
  |  ^^^^^^
  |  Values of types Long and Int cannot be compared with == or !=

scala> {
     |   import scala.language.strictEquality
     |   1L == 1
     | }
3 |  1L == 1
  |  ^^^^^^^
  |  Values of types Long and Int cannot be compared with == or !=

That would be pretty inconvenient I think. And if I understand http://cr.openjdk.java.net/~briangoetz/valhalla/sov/02-object-model.html correctly, in the future “reference equality” between wrapper classes like Integer will behave like primitive equality, so it might be best to sit and wait for value classes on the JVM before tweaking things even more on our end.

The document says:

two inline objects are == if they are of the same type, and each of their fields are pairwise equal according to == for the static type of that field (except for float and double , which compare according to the semantics of Float::equals and Double::equals ). This definition says that two inline objects are equal if and only they are substitutable – we can discern no difference between them.

Valhalla says inline objects are equal if and only if they are substitutable. Using the rule, the Valhalla unboxed int value 1 would no longer == long value 1L.

It’s true that reference to inline types would use the == semantics of the underlying inline types, but it seems like int#== becomes more like Integer#equals in that world.

1 Like

Yeah it’s a bit unclear from the text but it seems extremely unlikely that they would change the semantics such that 1 == 1L would suddenly start returning false.