Here is what I am trying to do
class Bar[P](val x: P) { type Foo = P }
class Baz[R <: Bar[_]](bar: R) { val x: R#Foo = bar.x }
The idea is to create Baz
with a single type parameter, and have access to both types inside of it.
But this does not work :(
found : Baz.this.x.type (with underlying type _$1)
required: _$1
It sounds like "underlying type _$1" is exactly what I want here, but that does not compile. Is there a way to do what I want here?
update
Perhaps, I oversimplified the use case.
Let's say, Bar
is actually something like this:
trait Foo[T] { def doStuff(t: T) = ??? }
class Bar[P] extends Foo[P](val x: P) { type Foo = P }
and somewhere else I have a
def fooX[T](x: T, foo: Foo[T]) = foo.doStuff(x)
and I want to call it from Baz
:
class Baz[R <: Bar[_]](bar: R) { fooX(bar.x, bar) }
It feels like it should work: fooX
parameters will always be of the correct type. But it does not compile, and I can't think of a better workaround than to have two type parameters to Baz
, which seems redundant.
When you invoke fooX(bar.x, bar)
, the compiler sees only:
bar: Bar[_]
which is the same as bar : Bar[X] forSome { type X }
bar.x : X forSome { type X }
, which reduces to bar.x: Any
and then it fails to prove that Any
is the same as X
in forSome { type X }
. However, if you bind the unknown type to a variable p
, then the compiler sees:
bar: Bar[p]
bar.x : p
fooX[p](bar.x, bar)
is applicable.Therefore, this works:
trait Foo[T] { def doStuff(t: T) = ??? }
class Bar[P](val x: P) extends Foo[P] { type Foo = P }
def fooX[T](x: T, foo: Foo[T]) = foo.doStuff(x)
class Baz[R <: Bar[_]](bar: R){
bar match {
case b: Bar[p] => fooX[p](b.x, b)
}
}
Outtakes (pre-update attempts)
Two snippets that attempted to solve the original question, maybe you find something helpful here:
class Bar[P](val x: P) { type Foo = P ; val y: Foo = x }
class Baz[R <: Bar[_]](val bar: R) { val x: bar.Foo = bar.y }
another way to tie x
to Foo
:
trait Br { type Foo ; val x: Foo }
class Bar[F](val x: F) extends Br { type Foo = F }
class Baz[R <: Br](val bar: R) {val x: bar.Foo = bar.x }