2017-04-06 10 views
5

jestem trochę zakłopotany przez surowość typechecker poniżej — wydaje się, że niezmienna T pozycja Inv[T] jest niezmienna w ciągu Variantish „s liście parametrów:Dlaczego wszystkie niezmienne pozycje klas ogólnych są niezmienne w listach parametrów typów w Scali?

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]] 
          ^

rodzaje wariant może normalnie występować w co patrzeć jak niezmienne pozycje list argumentów ustawowo, np z obiektu chronionego widoczności:

class Variantish[+T](protected[this] var v: Inv[T]) 

i wydaje się, że dodaje byłaby równie typesafe:

class Variantish[+T, +TVar <: Inv[T]](protected[this] var v: TVar) 

Need które sprawdzają wspomniano powyżej jest tak ścisły?

Odpowiedz

1

z języka specification kopalni (nacisk), o zgodności (tj T' jest super typ T):

Rodzaj konstruktorzy T i T′ podążać podobną dyscyplinę. Charakteryzujemy T i T′ według ich klauzul parametrów typu: [a1,…,an] i [a′1,…,a′n], gdzie ai lub a′i może zawierać adnotację wariancji, klauzulę parametru typu wyższego rzędu oraz ograniczenia. Następnie T zgodny T′ jeśli dowolny lista [t1,…,tn] - z deklarowanych różnic, granic i klauzule wyższego rzędu parametrów typ - z ważnych argumentów typu dla T′ jest również ważna lista argumentów typu dla T i T[t1,…,tn]<:T′[t1,…,tn].

To jest naprawdę trudne do zrozumienia (IMHO), ale uważam, że to oznacza, że ​​dla Variantish być kowariantna w T, trzeba by móc napisać

Variantish[Dog, TVar] <: Variantish[Animal, TVar] 

dla dowolnyTVar dla których Variantish[Animal, TVar] ma sens. Ale to nie ma nawet sensu (nie mówiąc już o żadnej wartości prawdy) dla niektórych z tych TVar, takich jak Inv[Animal]. Dlatego jest zabronione w tym miejscu.

0

Nie bardzo zrozumiałem odpowiedź @ cyrille-corpet, więc rozszerzyłem ją o kilka przykładów.

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 jest ważna od Animal <: Animal i AnimalInv <: AnimalInv są zarówno prawdziwe.

b jest nieprawidłowy od DogInv <: AnimalInv jest fałszywy.

c jest ważna od Dog <: Animal i AnimalInv <: AnimalInv są zarówno prawdziwe.

d jest nieprawidłowy od DogInv <: AnimalInv jest fałszywy.

Tak jak te pokazują TVar nie mogą być kowariantne.

Nawet w przypadku, gdy typ dynamiczny jest ważny, nie jest podtypem typu statycznego.

Podejrzewam, że jeśli spojrzymy na wszystkie miejsca, w których możemy używać TVar w Variantish, to nie musi to być parametr typu. Ponieważ @concat zwrócił uwagę, że wszelkie błędy wariancji, które możesz napotkać, można rozwiązać, używając modyfikatora dostępu chronionego przez obiekt.

Powiązane problemy