Search code examples
scalaclonecase-class

Define common copy for a class hierarchy with many case classes


I would like to define a class hierarchy with about 100 case classes deriving from common base. The types are describing nodes in the AST hierarchy, like this one. I would like to do something along the lines of:

trait Base {
  def doCopy: Base
}

trait CloneSelf[T <: CloneSelf[T]] extends Base {
  self: T =>

  def copy(): T
  override def doCopy: T = copy()
}


case class CaseA(a: String) extends Base with CloneSelf[CaseA]

case class CaseB(b: Int) extends Base with CloneSelf[CaseB]

This gives an error, because the existence of my copy prevents the case classes from defining the automatic copy. Is there some way how to implement the "clone" doCopy so that is uses the automatic copy of those case classes?


Solution

  • I have found out defining the doCopy in each case class is actually less work than defining each class to inherit from CloneSelf. The code looks like this:

    trait Base {
      def doCopy: Base
    }
    
    case class CaseA(a: String) extends Base {
      def doCopy = copy()
    }
    
    case class CaseB(b: Int) extends Base {
      def doCopy = copy()
    }
    

    I was surprised to learn that without explicit type on the overridden method the type is inferred by the compiler, therefore the static type of CaseA("a").doCopy is the same as of CaseA("a").copy(), i.e. CaseA, not Base. Adding explicit type for each case class would be probably more obvious, but this would require more work compared to just copy-pasting the same line into each of them. Not that it matters much - when I do copying via the case class type, I may use the copy() as well. It is only when I have the Base I need the doCopy, therefore declaring it like def doCopy: Base = copy() would do little harm.