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.
Try
I suspect that
TheType
is defined in typeFactoryOf
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 becauseTheType
is not defined in the typeBaseFactoryOf
and it should be defined in another typeT
that is a descendant. It could have been defined as something persistent, likeInt
.