I have the following situation/code;
trait Model {
def myField: String
}
case class MyModel(myField: String) extends Model
In the traditional model of creating DAOs for my model classes I want to create a DAO trait that contains some generic CRUD operations. NOTE...the persistence framework doesn't matter here...the question is around using case class methods within a trait that is using generics.
With that said I want to create the following trait;
trait DAO[M <: Model] {
def insert(model: M): M = {
... do work
m.copy(myField="someval")
}
}
In this case the code does not compile because generic M knows nothing about being a "case class". If there some easy solution here, can a generic be declared as needing to be a type of case? Or should the Model trait declare a copy method that any extending class has to implement and by being a case class it does so?
No.
Unfortunately, also no. An abstract
copy
method won't work for two reasons.First, if you declare an abstract
copy
method in your trait, it will actually prevent the case class that extends it from automatically generating it, and you're forced to implement it yourself.Second, it's hard to require such a generic method such as that. What I mean is, when you declare an abstract method, you need to specify the full signature. However, one would assume that all case classes that extend
Model
will not have the same signatures, so they cannot have the samecopy
method. It just can't work that way.Unfortunately that leaves you with needing to implement similar methods yourself for sub-classes. I do this sort of thing filling
id
s using F-bounded polymorphism:The bit of repeated code is ugly, but enough to live with. Perhaps it may be possible to do something like this with reflection or a macro, but that would likely be anything but simple.