I am trying to create a type class that will allow me to increment an Int field called "counter" on any case class, as long as that class has such a field.
I have tried to do this with Shapeless but am hitting walls (after first trying to digest "The Type Astronaut's Guide to Shapeless", the "Feature overview" of Shapeless 2.0.0 and numerous threads on Stack Overflow).
What I want is to be able to do something like
case class MyModel(name:String, counter:Int) {}
val instance = MyModel("Joe", 4)
val incremented = instance.increment()
assert(incremented == MyModel("Joe", 5))
And it should work for any case class with a suitable counter field.
I thought that this would be possible using a type class and Shapeless' record abstraction (and an implicit conversion to get the increment functionality added as a method). The bare bones would be something like this:
trait Incrementer[T] {
def inc(t:T): T
}
object Incrementer {
import shapeless._ ; import syntax.singleton._ ; import record._
implicit def getIncrementer[T](implicit generator: LabelledGeneric[T]): Incrementer[T] = new Incrementer[T] {
def inc(t:T) = {
val repr = generator.to(t)
generator.from(repr.replace('counter, repr.get('counter) + 1))
}
}
}
However, this does not compile. The error being value replace is not a member of generator.Repr
. I guess this is because the compiler does not have any guarantee as to T having a field called counter
and it being of type Int
. But how could I tell it so? Is there better/more documentation on Shapeless' record? Or is this a completely wrong way to go?