* Ok, because `List[B] <: List[A]` * `List` is _covariant_ * If `B<:A` then `List[B]<:List[A]` * Generally, type constructor `T[-]` is _covariant_ if `B<:A` implies `T[B]<:T[A]`
# <span class="fa-stack"><i class="fa-solid fa-circle fa-stack-2x"></i><i class="fa-solid fa-book fa-stack-1x fa-inverse"></i></span> Java Arrays are Covariant ```java public static void main (String[] args) { B[] bs = new B[] { new B (), new B () }; A[] as = bs; // OK, because covariant as[0] = new A (); // ArrayStoreException bs[0].g(); } ``` ```sh $ javac Driver.java $ java Driver Exception in thread "main" java.lang.ArrayStoreException: A at Driver.main(Driver.java:5) ``` * Every assignment to object array dynamically checked! ---
# <span class="fa-stack"><i class="fa-solid fa-circle fa-stack-2x"></i><i class="fa-solid fa-book fa-stack-1x fa-inverse"></i></span> Why? - For example, to sort ```java static void sort(Object[] xs) { ... } String[] ss = ...; sort(ss); // requires covariance ``` * With Java Generics ```java static <X extends Comparable<? super X>> void sort(X[] xs) { ... } ``` * In Scala ```scala def sort[X <: Comparable[? >: X]] (Array[X] xs) = ... ``` * Use ```java class A implements Comparable<A>{} class B extends A {} B[] bs = ...; sort(bs); // B's are comparable as A's ``` ---
# <span class="fa-stack"><i class="fa-solid fa-circle fa-stack-2x"></i><i class="fa-solid fa-book fa-stack-1x fa-inverse"></i></span> Three Types ```scala class A // Animal class B extends A // Bird class D extends B // Duck ``` ---
# <span class="fa-stack"><i class="fa-solid fa-circle fa-stack-2x"></i><i class="fa-solid fa-book fa-stack-1x fa-inverse"></i></span> Variance Annotations ```scala trait Producer[+Y] { def apply () : Y } // Covariant trait Consumer[-X] { def apply (x:X) : Unit } // Contravariant trait Function[-X,+Y] { def apply (x:X) : Y } // Both trait Operator[X] { def apply (x:X) : X } // Invariant ``` ```scala trait Producer[-Y] { def apply () : Y } ^ error: contravariant type Y occurs in covariant position ``` ```scala trait Consumer[+X] { def apply (x:X) : Unit } ^ error: covariant type X occurs in contravariant position ``` ---
- Outside the scope of this course - Bounded polymorphism (Java, C#, Scala, Flow) - Java's use-site variance and wildcards - Adhoc polymorphism, typeclasses, implicit params - Check out Scala and Typescript