Extending scala case class without constantly duplicating constructors vals?

64,787

Solution 1

As the previous commenter mentioned: case class extension should be avoided but you could convert your Edge class into a trait.

If you want to avoid the private statements you can also mark the variables as override

trait Edge{
  def a:Strl
  def b:Strl
}

case class EdgeQA(override val a:Strl, override val b:Strl, right:Int, asked:Int ) extends Edge

Don't forget to prefer def over val in traits

Solution 2

This solution offers some advantages over the previous solutions:

trait BaseEdge {
  def a: Strl
  def b: Strl
}
case class Edge(a:Strl, b:Strl) extends BaseEdge
case class EdgeQA(a:Strl, b:Strl, right:Int, asked:Int ) extends BaseEdge

In this way:

  • you don't have redundant vals, and
  • you have 2 case classes.

Solution 3

Case classes can't be extended via subclassing. Or rather, the sub-class of a case class cannot be a case class itself.

Solution 4

Starting in Scala 3, traits can have parameters:

trait Edge(a: Strl, b: Strl)
case class EdgeQA(a: Strl, b: Strl, c: Int, d: Int) extends Edge(a, b)
Share:
64,787
LaloInDublin
Author by

LaloInDublin

Reporting and Project Consultant, telecom.

Updated on May 08, 2021

Comments

  • LaloInDublin
    LaloInDublin about 3 years

    Is there a way to extend a case class without constantly picking up new vals along the way?

    For example this doesn't work:

    case class Edge(a: Strl, b: Strl)
    case class EdgeQA(a: Strl, b: Strl, right: Int, asked: Int) extends Edge(a, b)
    

    "a" conflicts with "a", so I'm forced to rename to a1. But I don't want all kinds of extra public copies of "a" so I made it private.

    case class Edge(a: Strl, b: Strl)
    case class EdgeQA(private val a1: Strl, private val b1: Strl, right: Int, asked: Int) extends Edge(a, b)
    

    This just doesn't seem clean to me... Am I missing something?

  • WestCoastProjects
    WestCoastProjects over 10 years
    We lose the advantage of the Edge as a standalone class: before it could be instantiated and it had the object Factory methods
  • Jeffrey Aguilera
    Jeffrey Aguilera over 10 years
    So why are there final case classes? The final LocalModifier is what prevents the extension of a case class, not some other language prohibition. See §5.2, p.63 of the Scala Reference
  • jhegedus
    jhegedus over 10 years
    Final prevents extending a case class with anything ( i.e. case and not case classes), in addition to the built-in restriction to extend case classes with case classes.
  • Sohaib
    Sohaib about 9 years
    but I still need to redeclare a and b. What if the trait had some default value for a and be and I wish to use those values themselves.
  • Wolfsblvt
    Wolfsblvt almost 9 years
    Can you explain why def is preferred in traits?
  • BAR
    BAR almost 9 years
    Please do explain your last statement. Is it because the implementation can be either a function or a variable?
  • Kevin Meredith
    Kevin Meredith over 7 years
    "case class extension should be avoided". Can you please explain why, @bajohns?
  • salvob
    salvob over 6 years
    this is definitely better
  • Bill'o
    Bill'o over 6 years
    this is an explanation on why to use def vs val
  • 6infinity8
    6infinity8 about 6 years
    Good but not perfect, we can't perfom sanity check on the variables this way without duplicating the code. Fortunately, Scala 3 will allow trait values as shown in this example.