The following code does not compile (in Scala 2.11):
case class CovariantClass[+R](value: R) {
type T = R
def get: R = value
}
object Main {
def main(args: Array[String]): Unit ={
println(CovariantClass[String]("hello").get)
}
}
The error message is:
Error:(4, 8) covariant type R occurs in invariant position in type R of type T
type T = R
^
Why can't I alias a covariant type parameter? If I remove the line type T = R
, the code compiles and prints hello
, so the alias seems to be the problem. Unfortunately, this means that I cannot create an alias for more complex types, e.g., type T = List[R]
does not compile either, although List
is covariant.
From the scala spec:
The right-hand side of a type alias is always in invariant position.
This means that you cannot create the alias T
and specify a variant type R
on the right-hand side. The same applies to List[R]
, because it is also covariant.
You can, however provide a type alias with a type parameter:
case class CovariantClass[+R](value: R) {
type T[+R] = List[R]
def get: R = value
}
If you find yourself wanting to alias the type parameter R
, you should probably just name it something else in the first place.
It's forbidden because it would allow a program that isn't correct, that's always the rule. You could rewrite it like this:
case class CovariantClass[+R](value: R) {
type T <: R
def get: R = value
}
As for an example of how it breaks, consider this:
case class CovariantClass[+R](value: R) {
type T = Int
def get: R = value
def put(x: T) {}
def put2(x: R) {}
}
Because of how T
is defined, it is invariant. That means it can be used in places where covariant types cannot, such as seen above. Notice that put
compiles but put2
does not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With