Here is a simple setup with two traits, a class with a covariant type parameter bounded by the previous traits, and a second class with a type parameter bounded by the other cla
0__'s answer (use the implicit evidence argument to turn bar
into the right type) is the answer I'd give to the specific question you asked (although I'd suggest not using implicitly
if you've got the implicit argument sitting right there).
It's worth noting that the situation you're describing sounds like it might be a good use case for ad-hoc polymorphism via type classes, however. Say for example that we've got the following setup:
trait Foo
case class Bar[F <: Foo](foo: F)
case class Grill[B <: Bar[_]](bar: B)
And a type class, along with some convenience methods for creating new instances and for pimping a readField
method onto any type that has an instance in scope:
trait Readable[A] { def field(a: A): Int }
object Readable {
def apply[A, B: Readable](f: A => B) = new Readable[A] {
def field(a: A) = implicitly[Readable[B]].field(f(a))
}
implicit def enrich[A: Readable](a: A) = new {
def readField = implicitly[Readable[A]].field(a)
}
}
import Readable.enrich
And a couple of instances:
implicit def barInstance[F <: Foo: Readable] = Readable((_: Bar[F]).foo)
implicit def grillInstance[B <: Bar[_]: Readable] = Readable((_: Grill[B]).bar)
And finally a readable Foo
:
case class MyFoo(x: Int) extends Foo
implicit object MyFooInstance extends Readable[MyFoo] {
def field(foo: MyFoo) = foo.x
}
This allows us to do the following, for example:
scala> val readableGrill = Grill(Bar(MyFoo(11)))
readableGrill: Grill[Bar[MyFoo]] = Grill(Bar(MyFoo(11)))
scala> val anyOldGrill = Grill(Bar(new Foo {}))
anyOldGrill: Grill[Bar[java.lang.Object with Foo]] = Grill(Bar($anon$1@483457f1))
scala> readableGrill.readField
res0: Int = 11
scala> anyOldGrill.readField
:22: error: could not find implicit value for evidence parameter of
type Readable[Grill[Bar[java.lang.Object with Foo]]]
anyOldGrill.readField
^
Which is what we want.