Why are all invariant generic class positions invariant in type parameter lists in Scala?

I'm a little puzzled by the rigor of the typechecker element below - it seems that the invariant position of T Inv[T] also invariant in the Variantish parameter 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]] ^ 

Variant types can usually arise in what looks like the invariant positions of argument arguments are legal, for example. with object protected visibility:

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

and it seems the following will be the same as typeafe:

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

Is such a check mentioned above so necessary?

+5
source share
2 answers

From the language specification (emphasis mine), on compliance (i.e., T' is a supertype of T ):

Constructors of types T and T′ follow a similar discipline. We characterize T and T′ by their parameters parameters [a1,…,an] and [a′1,…,a′n] , where ai or a′i may include dispersion annotation, suggestion of a higher-order constraint parameter and restrictions. Then T corresponds to T′ if any list [t1,…,tn] - with declared deviations, restrictions and sentences of a higher order type parameter - valid type arguments for T′ also a valid list of type arguments for T and T[t1,…,tn]<:T′[t1,…,tn] .

This is very hard to understand (IMHO), but I believe that this means that for Variantish , which will be covariant in T , you should be able to write

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

for any TVar for which Variantish[Animal, TVar] makes sense. But that doesn't even make sense (not to mention any truth value) for some of these TVar , such as Inv[Animal] . That is why it is forbidden in this place.

+1
source

I did not quite understand @ cyrille-corpet's answer, so I expanded it with a few examples.

 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 true since Animal <: Animal and AnimalInv <: AnimalInv are true.

b invalid because DogInv <: AnimalInv is false.

c true since Dog <: Animal and AnimalInv <: AnimalInv are true.

d invalid because DogInv <: AnimalInv is false.

Since they show that TVar cannot be covariant.

Even in case d , where the dynamic type is valid, it is not a subtype of the static type.

I suspect that if we look at all the places where we can use TVar in Variantish , then it should not be a type parameter. As @concat noted, any error errors that you can detect can be resolved using an object-safe access modifier.

0
source

Source: https://habr.com/ru/post/1266426/


All Articles