3

What's the best way to inherit some properties from a case class?

Let's say there's a case class with some properties

case class aggregations (aggregation1: Int, aggregation2: Int)

Two other case classes (case class A & case class B) will have the above parameters plus some extra fields. I'm trying to avoid code duplication and wondering what's the best strategy.

Found a thread discussing the same Scala case class inheritance but not sure whether composition/inheritance is the most suitable option here.

Loom
  • 9,768
  • 22
  • 60
  • 112
Nithin Chandy
  • 686
  • 1
  • 10
  • 28

1 Answers1

4

1) I tend to define trait when properties are shared in scala, though I would define interface and then abstract class in java.

parent class with shared members m1, m2

scala> trait Parent { def m1: Int, def m2: Int}

child classes with their own members

scala> case class Child1(val m1: Int, val m2: Int, val m3: Int) extends Parent
defined class Child1

scala> case class Child2(val m1: Int, val m2: Int, val m4: String) extends Parent
defined class Child2

using child classes

scala> Child1(1, 2, 3) == Child1(1, 2, 3)
res2: Boolean = true

scala> Child2(1, 2, "urayagppd") == Child2(1, 2, "prayagupd")
res4: Boolean = false

Also described in the post you mentioned.

NOTE : case-to-case inheritance is prohibited in scala.

scala> case class A(m1: Int)
defined class A

scala> case class B(m1: Int, m2: Int) extends A(m1)
<console>:13: error: case class B has case ancestor A, but case-to-case inheritance is prohibited. To overcome this limitation, use extractors to pattern match on non-leaf nodes.
       case class B(m1: Int, m2: Int) extends A(m1)

2) If you don't like explicit overriding parent properties in child classes, use composition.

parent class

scala> trait Parent
defined trait Parent

scala> case class ParentClass(val m1: Int, val m2: Int) extends Parent
defined class ParentClass

Child classes

scala> case class Child1(parent: ParentClass, val newMember: Int) extends Parent
defined class Child1

scala> Child1(ParentClass(100, 200), 400)
res0: Child1 = Child1(ParentClass(100,200),400)

scala> case class Child2(parent: ParentClass, val newMember2: String) extends Parent
defined class Child2

scala> Child2(ParentClass(100, 200), "inheritence sucks")
res2: Child2 = Child2(ParentClass(100,200),inheritence sucks)
prayagupa
  • 30,204
  • 14
  • 155
  • 192
  • Thanks. Here we'r e basically redefining those params in the child classes which is what i'm trying to avoid because it is code duplication. Is there a way to not define m1, m2 again for each child class. I know it is possible with composition. – Nithin Chandy Jun 05 '17 at 00:19
  • Agree, you have to override those properties in child classes as well, meaning there would be code duplication with this approach. But the idea is all child classes will follow the contract. – prayagupa Jun 05 '17 at 00:29
  • yes, thanks for the clarification. Just learned something new :) – Nithin Chandy Jun 05 '17 at 00:30
  • I added composition example as well, personally it does not feel natural to me, it depends though :) – prayagupa Jun 05 '17 at 00:45
  • Thanks. Do we need a trait in this case? – Nithin Chandy Jun 05 '17 at 00:49
  • 2
    @NithinChandy not necessarily but just to mark that `Child1` and `Child2` both inherit something same. **Simply a marker interface** in above example, but you can have trait with some behaviors as well that are common among its child classes, which is actual purpose of `trait`. eg. `trait Parent { def doSomething() }` which makes `Child1` to have same trait, `case class Child1(parent: ParentClass, val newMember: Int) extends Parent { def doSomething() = println("child 1") }` – prayagupa Jun 05 '17 at 03:51