How to identify something that extends this trait

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 emphasize that only the same type of fruit can be compared, therefore, for example, Orange("red") == Apple("red") should give an error. Can we provide this in a == signature in the form of Fruit in an elegant way?

EDIT: I want the error to be detected at compile time, and not at run time.

+4
source share
4 answers

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 this 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 used like that

 // 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 
+10
source

Unfortunately, you cannot verify this statically ... At least not using == , which uses the Java Object#equals method, where everything is decidedly defined in terms of raw objects.

If you need type safety, then your only choice is to implement another operator, perhaps something like =|= , and then combine this with class types to ensure your safety.

I believe that scalaz also has something useful for the safe type, but I don't know that the library is good enough to say that for sure.

Another approach that you can take that will only be safe at runtime is to use the canEqual template as described here . This is already used by case classes and offers a good way to selectively interrupt LSPs when it is suitable for equality.

+2
source

If you are happy to change the method name from == to something else, we can do this:

 trait Fruit { type FruitType <: Fruit val color:String def === (fruit:FruitType) = this.color == fruit.color } case class Orange(color:String) extends { type FruitType = Orange } with Fruit case class Apple(color:String) extends {type FruitType = Apple } with Fruit 

Then, if we compare Apples with oranges, we get:

 Apple("red") === Orange("red") <console>:11: error: type mismatch; found : Orange required: Apple Apple("red") === Orange("red") 

and apples with apples of the same color, we get:

 Apple("red") === Apple("red") res10: Boolean = true 

and Apples with Apples of a different color, we get:

 Apple("green") === Apple("red") res11: Boolean = false 
+2
source

Try:

  trait Fruit { val color: String def == (fruit: Fruit) = getClass == fruit.getClass && color == fruit.color } 
+1
source

Source: https://habr.com/ru/post/1342909/


All Articles