How to utilize Scala case class copy() functionality in a generic class

Viewed 854

My domain classes are case classes and I have general engine/transformer classes that operate on them. I make use of case class functionality such as copy() and would like to do that while treating the classes generically, here is a simple example:

trait Fruit { val color: String }

case class Apple (color: String = "red") extends Fruit

case class Banana (color: String = "yellow") extends Fruit

case class Orange (color: String = "orange") extends Fruit

val apple = new Apple
val newApple1 = apple.copy(color = "green") // compiles fine

object Transformer {
  def apply(fruit: Fruit): Fruit = {
    fruit.copy(color = "green") // does not compile, "Cannot resolve symbol copy"
  }
}

val newApple2 = Transformer(apple)

newApple2

In this example the first call to copy() works fine, but trying to do the same kind of operation within the apply() method of the Transformer class does not, I am assuming because Scala does not know that Fruit is a case class and thus has the runtime-generated copy() method.

I've tried various typecasts, for example making Fruit an abstract class or having it extend scala.Product (which internally is the closest ancestor to the case class) but this doesn't make the copy() method available.

I would rather not implement the copy method myself if I can avoid it, though with reflection or shapeless it can probably be done in a generic way that would work.

There are a few other similar questions here on StackOverflow but I have not see an answer that addresses this, thanks for any info.

EDIT: My question is similar to this recent question however the answers there did not satisfy me for these reasons:

  • The accepted solution suggested implementing a copyWithId() method, or, in other words, a special-purpose copy() method that takes one or more specific parameters, whereas I want to use the very versatile case class copy() method which accepts variable parameters.
  • The solutions proposed there use shapeless or lenses and a lot of Scala "magic" which it seems to me should not be necessary since, as my example shows, the copy() implementation that I'm after is already in scope, but is just not available because the correct data type can't be inferred. I'm hoping instead to gain access to the copy() with the right kind of typecast.
0 Answers
Related