Ответ 1
Во-первых, обратите внимание, что дисперсия является свойством параметров типового типа, а не самих параметризованных типов.
Во-вторых: вы ошибаетесь в отношении параметров scala - по умолчанию инвариантны. Исследуем!
Java
Java имеет аннотации вариаций на сайте. То есть вы можете объявить методы следующим образом:
boolean addAll(Collection<? extends T> c);
Существует, однако, одна форма "параметризованного типа" (я использую термин "свободно" ), в котором параметры типа ковариантны: массивы Java! (Это на самом деле безумное, потому что массивы изменяемы и, следовательно, легко обойти систему типов). Рассмотрим следующее:
public static void subvert(Object[] arr) { arr[0] = "Oh Noes!"; }
И затем:
Integer[] arr = new Integer[1];
subvert(arr); //this call is allowed as arrays are covariant
Integer i = arr[0];
Хороший вопрос для интервью: что происходит?
Scala
В Scala у вас есть отклонение объявления-сайта. То есть дисперсия параметра типа объявляется рядом с параметром (используя аннотации +
и -
):
trait Function1[-I, +O]
Это говорит о том, что признак Function1
имеет два типа параметров, I
и O
, которые являются соответственно и со-вариантами. Если объявлена аннотация +/-
, то параметр типа является инвариантным. Например, Set является инвариантным в своем параметре типа:
scala> def foo(set: Set[Any]) = ()
foo: (set: Set[Any])Unit
scala> Set(1)
res4: scala.collection.immutable.Set[Int] = Set(1)
scala> foo(res4)
<console>:10: error: type mismatch;
found : scala.collection.immutable.Set[Int]
required: Set[Any]
Note: Int <: Any, but trait Set is invariant in type A.
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
foo(res4)
^
Список, однако, объявлен как ковариантный:
scala> def bar(list: List[Any]) = ()
bar: (list: List[Any])Unit
scala> List(1)
res6: List[Int] = List(1)
scala> bar(res6)
Почему бы не спросить компилятор?
Другой способ продемонстрировать это - запросить компилятор непосредственно для подтипов:
scala> class Cov[+A]
defined class Cov
scala> implicitly[Cov[Int] <:< Cov[Any]]
res8: <:<[Cov[Int],Cov[Any]] = <function1>
Но с параметром инвариантного типа
scala> class Inv[A]
defined class Inv
scala> implicitly[Inv[Int] <:< Inv[Any]]
<console>:9: error: Cannot prove that Inv[Int] <:< Inv[Any].
implicitly[Inv[Int] <:< Inv[Any]]
^
Наконец, контравариантность:
scala> class Con[-A]
defined class Con
scala> implicitly[Con[Any] <:< Con[Int]]
res10: <:<[Con[Any],Con[Int]] = <function1>