Confusion over the actual type of a referenced abstract type

40 views Asked by At

Below I have a purposefully complicated Hello World applictaion in which I cannot figure out for the life of me why the buildAndRun2 method just doesn't compile.

abstract class BaseFactoryOf[A]{
    type TheType
    def make: TheType
}

abstract class FactoryOf[A] extends BaseFactoryOf[A]{
    final type TheType = A
}

class HelloWorld {
    def execute: String = "Hello World!"
}

class HelloWorldFactory extends FactoryOf[HelloWorld] {
    def make: TheType = new HelloWorld
}

def buildAndRun1[T <: BaseFactoryOf[_],B](factory: T)(f: T#TheType => B): B ={
    f(factory.make)
}

def buildAndRun2[T <: FactoryOf[_],B](factory: T)(f: T#TheType => B): B ={
    f(factory.make)
} //This doesn't compile due to a type mismatch error. But Why?!

//Client Code
buildAndRun1(new HelloWorldFactory)(i => i.execute) // This Works!
buildAndRun2(new HelloWorldFactory)(i => i.execute) // Epic Fail!

The useless Intermediate FactoryOf[A] was actually written to introduce the issue. I'm pretty sure it's got something to do with the type TheType but what is it?! If anything, It's the useless intermediate FactoryOf class that allows me to verify that the type TheType is the same as A so by this logic I should be more confident using buildAndRun2 method.

1

There are 1 answers

1
Arseniy Zhizhelev On

Try

def buildAndRun3[T <: FactoryOf[_],B](factory: T)(f: factory.TheType => B): B = {
    f(factory.make)
}

I suspect that TheType is defined in type FactoryOf to depend on the argument. That's why the actual type depends on the actual instance given (path-dependent type) and not just the type.

On the other hand, buildAndRun1 compiles because TheType is not defined in the type BaseFactoryOf and it should be defined in another type T that is a descendant. It could have been defined as something persistent, like Int.