Почему все инвариантные позиции родового класса инвариантны в списках параметров типа в 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, любые ошибки, которые вы можете заметить, могут быть устранены с помощью модификатора доступа, защищенного с помощью объекта.

Другие вопросы по тегам