I am confused by the generic subtyping.
In Java, if type A is a subtype of B, generic type C<A> and C<B> are invariant. For instance, ArrayList<Base> is not a subtype of ArrayList<Derived>.
However, in Scala, generic type C<A> and C<B> are covariant if type A is a subtype of B. So what’s the property of generic class in Scala has but not in Java?
Firstly note that variance is a property of generic type parameters, not of the parameterized types themselves.
Secondly: you are wrong about scala – type parameters are invariant by default. Let us investigate!
Java
Java has use-site variance annotations. That is, you can declare methods like this:
There is, however, one form of “parameterized type” (I use the term loosely) in which the type parameters are covariant: Java Arrays! (This is actually insane because Arrays are mutable and hence it is easy to circumvent the type system). Consider the following:
And then:
A good interview question this one: what happens?
Scala
In Scala, you have declaration-site variance. That is, the variance of a type parameter is declared alongside the parameter (using the annotations
+and-):This says that the trait
Function1has two type parameters,IandOwhich are contra- and co-variant respectively. If no+/-annotation is declared, then the type parameter is invariant. For example, Set is invariant in its type parameter:List is however, declared as being covariant:
Why not ask the compiler?
Another way of demonstrating this is to ask the compiler directly for subtype-evidence:
But with an invariant type parameter
Lastly, contravariance:
See also identifier
<:<