Fundamentally, you cannot inherit a copy
because base class' copy
method wouldn't know how to copy subclass' fields.
What you are doing works, but, if you think about it, it is rather useless: case classes are (or, should be by design) immutable, so, if foo
is an instance of a case class, then foo
and foo.copy()
are pretty much the same object for all practical purposes, creating these copies instead of just using foo
everywhere is just pure waste of memory. (You can also just use clone
instead of copy, if that's what you are really looking for for some reason - just make Base
extend Cloneable
)
The reason copy
exists, if because it actually takes parameters (the actual definition of Derived.copy
is def copy(name: String = name)
) to facilitate creating instances of the class that are different from the original, i.e.: val foo = Derived("foo"); val bar = foo.copy("bar")
...
So, if you know what parameters your case classes will have, you can do something like this:
abstract class Base[T <: Base] {
def name: String;
def copy(name: String = name): T
}
case class Derived1(name: String) extends Base[Derived1]
case class Derived2(name: String) extends Base[Derived2]
val p: Base[_] = Derived1("foo")
val pCopy = p.copy()
val s: Base[_] = Derived2("bar")
val sCopy = s.copy
Note, that Derived1
and Derived2
are almost the same thing though (both are really just a "glorified String"). While this may still be useful in some cases (e.g., define different kinds of application-specific errors with a detailed message), the major limitation of this approach is that you cannot define subclasses with different set of parameters than you have defined in Base
:
// This won't compile:
class Derived3(name: String, code: Int) extends Base[Derived3]