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:
A
where val1 == val2
would not be legal?==
, !=
to a type?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 ==
?This comparison is not really illegal, it is just undefined.
The given
solution is more flexible than a trait
, but you can just define ==
on your type if you prefer.
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.