Let's say I have a class with a type parameter and a method that should return a copy of the instance only if the class is parameterized with a particular trait that has a representation type. I can get that to happen pretty easily. What I can't do is put a sensible return type that method:
case class Foo[+A](a: A) {
// Compiles
def gotFooBar(implicit evidence: A <:< Bar[_]) = copy(a = a.Copy())
// Does not compile
def gotFooBar(implicit evidence: A <:< Bar[_]): Foo[A] = copy(a = a.Copy())
}
trait Bar[+B <: Bar[B]] {
def Copy(): B // Return underlying type
}
case class Grill() extends Bar[Grill] {
def Copy() = Grill()
}
What is the return type of that function, or perhaps more importantly, how would I set up the types so that that was the return type? Could someone also point out how the real return type could be a supertype of Foo[A]
?
Well, since you only require Bar[_]
you get Any
as result of calling a.Copy
. You need a type parameter for the gotFooBar
method:
case class Foo[+A](a: A) {
def gotFooBar[B <: Bar[B]](implicit evidence: A <:< B): Foo[B] = {
val bar = a: B
copy(a = bar.Copy())
}
}
The second question is, how to enforce that Foo[B]
is a supertype of Foo[A]
. You just need to add A
as a lower bound for B
:
def gotFooBar[B >: A <: Bar[B]](implicit evidence: A <:< B): Foo[B]