Refer to the following code snippet:
trait Fruit {
val color:String
def == (fruit:Fruit) = this.color == fruit.color
}
case class Orange(color:String) extends Fruit
case class Apple(color:String) extends Fruit
As expected, Orange("red") == Orange("red")
is true
. However, I would like to enforce that only the same type of fruits can be compared, so for instance Orange("red") == Apple("red")
should give an error. Can we enforce this in the signature of ==
in trait Fruit
in an elegant way?
EDIT: I want the error to be caught at compile time, not at runtime.
Scalaz has an Equal "type class" that solves this problem, albeit with a different operator.
https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/Equal.scala
The heart of it is basically this (although I use === where they use some unicode)
/** Defines a type safe === operator */
trait Equals[A] {
def ===(y : A) : Boolean
}
/** A conventient way to define Equals traits based on the == operator */
def equalA[A](x : A) = new Equals[A] {
def ===(y : A) = x == y
}
And is used like so
// one for oranges
implicit val EqualsOrange = equalA[Orange] _
// one for apples
implicit val EqualsApple = equalA[Apple] _
Orange("red") === Orange("red") // true
Orange("red") === Orange("green") // false
Orange("red") === Apple("red") // Compile error
Unfortunately, you can't check this statically... At least, not using ==
, which uses Java's Object#equals
method where everything is emphatically defined in terms of raw objects.
If you want type safety, then your only choice is to implement another operator, perhaps something like =|=
, then combine this with type classes to ensure your safety.
I believe that scalaz also has something useful for type-safe equality, but don't know the library well enough to state this for certain.
The other approach you can take, which will only be safe at runtime, is to use the canEqual
pattern as described here. This is already used by case classes and offers a nice way to selectively break the LSP when it's appropriate for equality.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With