Variance annotations in type aliases

alias, scala, variance

Solution

So, I don't know for sure, but I'm going to offer a possible explanation.

Type aliases in Scala are fairly "weak"; they do not completely create new types, just new ways of writing the old types (and new path dependent types); this means that if you define

type InvList[T] = List[T]

and write `InvList[T]`, it is exactly as if you wrote `List[T]`; that's why `InvList[Int] <: InvList[Any]`, because, rewritten, this is just `List[Int] <: List[Any]`. I'm not actually sure exactly how "weak" Scala type aliases are... they are a little stronger than Haskell's because of path-dependent types, but are weaker than class declarations. Maybe someone else can explain further.

So, why does Scala allow you to put variance annotations in there, if it's just going to ignore them and rewrite the type anyway? It's for type members. It's so that you can say

trait A { type F[+T] }

and require that implementations conform to the `+T` variance, so that you allow

trait B extends A { type F[+T] = List[T] }

but not

trait C extends A { type F[T] = Function[T,T] }

Or, as from this sentence from the Scala Language Spec S4.3.

A type constructor declaration imposes additional restrictions on the concrete types for which t may stand. Besides the bounds L and U , the type parameter clause may impose higher-order bounds and variances, as governed by the conformance of type constructors (§3.5.2).

Problem

Recently I've noticed that variance annotations can be used in type aliases. Here is example from `Predef`: ``` type Function[-A, +B] = Function1[A, B] ``` And I started to think, where it could be used. Obviously, you can't change variance to opposite, or make an invariant type to behave as co- or contravariant. Compiler will throw an error, like this ``` scala> type BrokenFunc[+T, -R] = Function1[T, R] <console>:7: error: covariant type T occurs in contravariant position in type [+T, -R]T => R of type BrokenFunc ``` But, you can make some variant type to behave like invariant (at least, compiler wouldn't argue with that). So, I tried to make an invariant version of `List` ``` scala> type InvList[T] = List[T] defined type alias InvList ``` But this new invariant `List` still behaves just like it's original covariant version: ``` scala> val l: InvList[String] = List("foo") l: InvList[String] = List(foo) scala> val anyList: InvList[Any] = l anyList: InvList[Any] = List(foo) ``` So, what I am missing? What's the purpose of variance annotations in type aliases? Can you give an example of type alias with variance annotations, that will differ from original type.

Original source