Почему все инвариантные позиции родового класса инвариантны в списках параметров типа в Scala?
Я немного озадачен строгостью проверки типов ниже - кажется, что инвариант T
положение Inv[T]
также инвариантен внутри Variantish
Список параметров:
scala> class Inv[T]
defined class Inv
scala> class Variantish[+T, +TVar <: Inv[T]]
<console>:12: error: covariant type T occurs in invariant position in type <: Inv[T] of type TVar
class Variantish[+T, +TVar <: Inv[T]]
^
Типы вариантов обычно могут встречаться в том, что юридически выглядит как инвариантные позиции списка аргументов, например, с видимостью, защищенной объектом:
class Variantish[+T](protected[this] var v: Inv[T])
и кажется, что следующее будет столь же безопасно:
class Variantish[+T, +TVar <: Inv[T]](protected[this] var v: TVar)
Нужно ли, чтобы упомянутая выше проверка была такой строгой?
2 ответа
Из спецификации языка (выделено мое), о соответствии (т.е. T'
это супер-тип T
):
Тип конструкторы
T
а такжеT′
следовать аналогичной дисциплине. Мы характеризуемT
а такжеT′
по их пунктам параметров типа[a1,…,an]
а также[a′1,…,a′n]
гдеai
или жеa′i
может включать аннотацию дисперсии, предложение параметра типа более высокого порядка и границы. Затем,T
соответствуетT′
если какой-либо список[t1,…,tn]
- с объявленными отклонениями, границами и предложениями параметров типа более высокого порядка - допустимых аргументов типа дляT′
также является допустимым списком аргументов типа дляT
а такжеT[t1,…,tn]<:T′[t1,…,tn]
,
Это действительно трудно понять (ИМХО), но я считаю, что это означает, что для Variantish
быть ковариантным в T
, вы должны быть в состоянии написать
Variantish[Dog, TVar] <: Variantish[Animal, TVar]
для любого TVar
для которого Variantish[Animal, TVar]
имеет смысл. Но это даже не имеет смысла (не говоря уже о значении истины) для некоторых из этих TVar
, такие как Inv[Animal]
, Вот почему это запрещено в этом месте.
Я не совсем понял ответ @cyrille-corpet, поэтому расширил его несколькими примерами.
class Inv[T]
class Variantish[+T, +TVar <: Inv[T]]
trait Animal
class Dog extends Animal
class AnimalInv extends Inv[Animal]
class DogInv extends Inv[Dog]
val a: Variantish[Animal, Inv[Animal]] = new Variantish[Animal, AnimalInv]
val b: Variantish[Animal, Inv[Animal]] = new Variantish[Animal, DogInv]
val c: Variantish[Animal, Inv[Animal]] = new Variantish[Dog, AnimalInv]
val d: Variantish[Animal, Inv[Animal]] = new Variantish[Dog, DogInv]
a
действует с Animal
<: Animal
а также AnimalInv
<: AnimalInv
оба правда.
b
недействителен с DogInv
<: AnimalInv
ложно
c
действует с Dog
<: Animal
а также AnimalInv
<: AnimalInv
оба правда.
d
недействителен с DogInv
<: AnimalInv
ложно
Так как эти шоу TVar
не может быть ковариантным.
Даже в случае d
где динамический тип является допустимым, он не является подтипом статического типа.
Я подозреваю, если бы мы посмотрели на все места, где мы можем использовать TVar
в Variantish
тогда это не должно быть параметром типа. Как отметил @concat, любые ошибки, которые вы можете заметить, могут быть устранены с помощью модификатора доступа, защищенного с помощью объекта.