scalatype-projection

Confusion with path projections


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.


Solution

  • When you invoke fooX(bar.x, bar), the compiler sees only:

    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:

    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 }