I am trying to understand why the following piece of code won't compile when I use a higher kinded type parameter for T in MyModel
abstract class Model[M <: Model[M]]
class MyModel[T] extends Model[MyModel[T]]
class Bar[TModel <: Model[TModel]]
object Foo extends App {
new Bar[MyModel[_]]
}
But if i change it to new Bar[MyModel[Any]] it will compile. Why is this ?
Bar[MyModel[_]]isBar[MyModel[X] forSome {type X}].(It should not be confused neither with
Bar[MyModel[X]] forSome {type X}nor withBar[MyModel[X forSome {type X}]], the latter is justBar[MyModel[Any]]. These are three different types.)Bar[MyModel[X] forSome {type X}](akaBar[MyModel[_]]) doesn't compile becauseMyModel[X] forSome {type X}(akaMyModel[_]) doesn't satisfyBar's conditionTModel <: Model[TModel]. Indeed you can check thatdoesn't compile (
Xto the left from<:<andXto the right from<:<are not related). The thing is that skolemization of existential type on the leftMyModel[X] forSome {type X}, namelyMyModel[X1]is not connected toModel[MyModel[X] forSome {type X}]on the right, for invariantModel(fromclass MyModel[T] extends Model[MyModel[T]]it follows thatMyModel[X1] <: Model[MyModel[X1]](1), alsoMyModel[X1] <: (MyModel[X] forSome {type X})(2), but for invariantModelwe can't applyModelto the latter "inequality").But if you make
Modelcovariantabstract class Model[+M <: Model[M]]then we can applyModelto "inequality" (2), soModel[MyModel[X1]] <: Model[MyModel[X] forSome {type X}]and this along with (1) givesMyModel[X1] <: Model[MyModel[X] forSome {type X}]by transitivity. SoBar's condition is satisfied andnew Bar[MyModel[_]]compiles.Bar[MyModel[Any]]compiles becauseMyModel[Any]satisfiesBar's conditionTModel <: Model[TModel]. IndeedMyModel[Any] <: Model[MyModel[Any]]becauseclass MyModel[T] extends Model[MyModel[T]](you can check thatcompiles).