What is * so * wrong with case class inheritance?

When looking for something else, out of sheer coincidence, I came across a few comments about how the devil inheritance of the class of cases is inherited. This thing was called ProductN , villains and kings, elves and wizards, and how some very desirable property with the inheritance of case classes is lost. So what happened to case class inheritance?

+53
inheritance scala case-class
Jun 22 '12 at 15:06
source share
2 answers

One word: equality

Classes

case have a supplied implementation of equals and hashCode . The equivalence relation, known as equals , works like this (i.e. it should have the following properties):

  • For all x ; x equals x true (reflective)
  • For x , y , z ; if x equals y and y equals z , then x equals z (transient)
  • For x , y ; if x equals y , then y equals x (symmetric)

Once you allow equality within the inheritance hierarchy, you can split 2 and 3. This is trivially demonstrated in the following example:

 case class Point(x: Int, y: Int) case class ColoredPoint(x: Int, y: Int, c: Color) extends Point(x, y) 

Then we have:

 Point(0, 0) equals ColoredPoint(0, 0, RED) 

But not

 ColoredPoint(0, 0, RED) equals Point(0, 0) 

You can argue that all class hierarchies can have this problem, and this is true. But classes of cases exist specifically to simplify equality from the point of view of the developer (among other reasons), so if they behave unintuitively, this will be the definition of their own goal!




There were other reasons; in particular, the fact that copy not working properly and interacting with the pattern matching .

+94
Jun 22 2018-12-18T00:
source share

This is not true. And it's worse than a lie.

As mentioned by aepurniet in any case, the successor of the class that narrows the scope should override this equality, since pattern matching should work just like equality (if you try to match Point as ColoredPoint , then it will not match, since color does not exist )

This provides an understanding of how you can implement case class hierarchy equality.

 case class Point(x: Int, y: Int) case class ColoredPoint(x: Int, y: Int, c: Color) extends Point(x, y) Point(0, 0) equals ColoredPoint(0, 0, RED) // false Point(0, 0) equals ColoredPoint(0, 0, null) // true ColoredPoint(0, 0, RED) equals Point(0, 0) // false ColoredPoint(0, 0, null) equals Point(0, 0) // true 

Ultimately, it is possible to satisfy the equality equality requirements even for the successor of the case class (without overriding equality).

 case class ColoredPoint(x: Int, y: Int, c: String) class RedPoint(x: Int, y: Int) extends ColoredPoint(x, y, "red") class GreenPoint(x: Int, y: Int) extends ColoredPoint(x, y, "green") val colored = ColoredPoint(0, 0, "red") val red1 = new RedPoint(0, 0) val red2 = new RedPoint(0, 0) val green = new GreenPoint(0, 0) red1 equals colored // true red2 equals colored // true red1 equals red2 // true colored equals green // false red1 equals green // false red2 equals green // false def foo(p: GreenPoint) = ??? 
-one
Apr 6 '16 at 16:30
source share



All Articles