Search code examples
scalascala-3

Scala 3 multiversal equality of type parameters


In Scala 3, with -language:strictEquality, this code:

trait X[A]:
    def val1: A
    def val2: A
    def f() =
        if val1 == val2 then
            println("Same")

produces this error:

Values of types A and A cannot be compared with == or !=

I looked for some trait that would tell the compiler that A can be compared to itself, but couldn't find one. The solution I found was to add this line:

given CanEqual[A, A] = CanEqual.derived

However, I still have several questions:

  1. How come you can't compare two instances of the same type? What are some instances of A where val1 == val2 would not be legal?
  2. Is there a trait that would add ==, != to a type?
  3. If the compiler can't figure out that you can compare A to A when A is a type parameter, then how come given CanEqual[A, A] = CanEqual.derived keeps it happy? What is the magic in CanEqual.derived and why can't it be applied by default when using ==?

Solution

    1. This comparison is not really illegal, it is just undefined.

    2. The given solution is more flexible than a trait, but you can just define == on your type if you prefer.

    3. You have explicitly told the compiler that you don't want it to generate a default == operator. That's what strictEquality means.

    The logic behind strictEquality is that there are different kinds of equality and the compiler shouldn't arbitrarily chose one kind. Objects can be compared by reference or by contents, and it neither is "correct" in every case.

    Without strictEquality the compiler implements referential equality by default, which means two values are the same only if they refer to the same object. case class implements structural equality by checking each field for equality, so two different instances are "equal" if all the values of all the fields are the same. Other classes can implement equality by comparing only a relevant subset of field, or by other criteria.

    According to the documentation strict equality is opt-in for for compatibility and migration reasons.