Considérons les deux codes ci-dessous. Ils accomplissent le même objectif: que ces A[T]
-s peuvent être stockés dans le Container
où T
étend C
Existentials vs Covariance dans Scala
Cependant, ils utilisent deux approches différentes pour atteindre cet objectif:
1) existentiaux
2) covariance Je préfère la première solution car A
reste plus simple. Y a-t-il une raison pour laquelle je voudrais utiliser la seconde solution (covariance)?
Mon problème avec la deuxième solution est qu'il est pas naturel dans le sens où il ne devrait pas être la responsabilité de A
pour décrire ce que je peux stocker dans un conteneur et ce pas, qui devrait être la responsabilité du conteneur. La deuxième solution est également plus compliqué une fois que je veux commencer à fonctionner sur A
et ensuite je dois faire face à tout ce qui vient avec la covariance.
Quel avantage obtiendrais-je en utilisant la deuxième solution (plus compliquée, moins naturelle)?
object Existentials extends App {
class A[T](var t:T)
class C
class C1 extends C
class C2 extends C
class Z
class Container[T]{
var t:T = _
}
val c=new Container[A[_<:C]]()
c.t=new A(new C)
// c.t=new Z // not compile
val r: A[_ <: C] = c.t
println(r)
}
object Cov extends App{
class A[+T](val t:T)
class C
class C1 extends C
class C2 extends C
class Z
class Container[T]{
var t:T = _
}
val c: Container[A[C]] =new Container[A[C]]()
c.t=new A(new C)
//c.t=new A(new Z) // not compile
val r: A[C] = c.t
println(r)
}
EDIT (en réponse à la réponse de Alexey):
Commentant: « Mon problème avec la deuxième solution est qu'il est pas naturel dans le sens où il ne devrait pas être aussi la responsabilité pour décrire ce que je peux stocker dans un conteneur et quoi que ce soit, cela devrait être la responsabilité du conteneur. "
Si je class A[T](var t:T)
cela signifie que je peux stocker seulement A[T]
-s et non (A[S]
où S<:T
) dans un récipient, dans un conteneur.
Cependant si j'ai class A[+T](var t:T)
puis je peux stocker A[S]
où S<:T
ainsi dans n'importe quel récipient. Donc, lorsque je déclare A
soit invariant soit covariant, je décide quel type de A [S] peut être stocké dans un conteneur (comme indiqué ci-dessus), cette décision a lieu à la déclaration A
.
Cependant, je pense, cette décision devrait avoir lieu, au contraire, à la déclaration du conteneur, car il est conteneur spécifique ce qui sera autorisé à entrer dans ce conteneur, seulement A[T]
-s ou aussi A[S]
où S<:T
-s.
En d'autres termes, changer la variance A[T]
a des effets globalement, tout en changeant le paramètre de type d'un conteneur A[T]
-A[_<:S]
a un effet local bien défini sur le conteneur lui-même. Ainsi, le principe des «changements devraient avoir des effets locaux» favorise ici la solution existentielle.
Merci pour la réponse. "De plus, si vous oubliez d'utiliser l'existentiel correct dans une seule méthode, tout autre lieu qui l'appelle ne peut pas non plus utiliser le type existentiel (sans projections non sécurisées non sécurisées)." Pourriez-vous donner un exemple simple? Je ne comprends pas ce que tu veux dire. – jhegedus
"Dans le premier cas, A est plus simple, mais dans le second cas, ses clients le sont." En quoi est-ce plus simple pour les clients? Je ne comprends pas, pourriez-vous s'il vous plaît donner un exemple? – jhegedus
@jhegedus Voir les modifications. –