Quand @uncheckedVariance nécessaire à Scala, et pourquoi est-il utilisé dans GenericTraversableTemplate?
-
20-09-2019 - |
Question
@uncheckedVariance
peut être utilisé pour combler l'écart entre le site de déclaration de Scala annotations de la variance et génériques invariantes de Java.
scala> import java.util.Comparator
import java.util.Comparator
scala> trait Foo[T] extends Comparator[T]
defined trait Foo
scala> trait Foo[-T] extends Comparator[T]
<console>:5: error: contravariant type T occurs in invariant position in type [-T]java.lang.Object with java.util.Comparator[T] of trait Foo
trait Foo[-T] extends Comparator[T]
^
scala> import annotation.unchecked._
import annotation.unchecked._
scala> trait Foo[-T] extends Comparator[T @uncheckedVariance]
defined trait Foo
Ce que dit java.util.Comparator est naturellement contre-variante, qui est le paramètre de type T
apparaît dans les paramètres et jamais dans un type de retour.
Cela pose la question: pourquoi est-il aussi utilisé dans la bibliothèque de collections Scala qui ne s'étend pas d'interfaces Java
trait GenericTraversableTemplate[+A, +CC[X] <: Traversable[X]] extends HasNewBuilder[A, CC[A] @uncheckedVariance]
Quelles sont les utilisations valides pour cette annotation?
La solution
Le problème est que GenericTraversableTemplate est utilisé deux fois: une fois pour les collections mutables (où son paramètre de type doit être invariante), et une fois pour les collections immuables (où covariance est toujours roi)
.Les typable de GenericTraversableTemplate en supposant que soit covariance ou invariance pour le paramètre de type. Cependant, quand nous héritons dans un trait muable, nous devons prendre invariance. A l'inverse, nous aimerions covariance dans une sous-classe immuable.
Puisque nous ne pouvons pas abstraite sur l'annotation de la variance (encore ;-)) en GenericTraversableTemplate, de sorte que nous aurions pu instancié à l'une en fonction de la sous-classe, nous devons recourir à la coulée (@uncheckVariance est essentiellement une sorte -jeter). Pour en savoir plus, je vous recommande ma thèse (désolé ;-)) ou notre récent
Les « attributs sont des types » idée est expliquée bien par Edsko de Vries dans le contexte des types d'unicité. Unicité Saisie simplifiée ,
Edsko de Vries, Rinus Plasmeijer, et David Abrahamson.
Dans Olaf Chitil, Zoltán Horváth et Viktória Zsók (Eds.):
IFL 2007, LNCS 5083, pp. 201-218, 2008. Résumé: Nous présentons un type unique
système qui est plus simple que les deux
Propre et le système unique de
système que nous avons proposé précédemment. Le nouveau
système de type est facile à
mettre en œuvre et ajouter aux éléments existants
compilateurs, et peuvent facilement être étendues
avec des fonctionnalités avancées telles que plus
types rang et imprédicativité. nous
décrire notre mise en œuvre à Morrow,
un langage fonctionnel expérimental
avec ces deux caractéristiques. Enfin nous
prouver la solidité du type à noyau
système par rapport à la
appel par besoin lambda-calcul.
I trouvé un autre moment où @uncheckedVariance est utilisé - la méthode de synthèse qui retourne la valeur par défaut pour un paramètre d'un type abstrait:
M:\>scala -Xprint:typer -e "class C { def p[T >: Null](t: T = null) = t }"
[[syntax trees at end of typer]]// Scala source: (virtual file)
package <empty> {
final object Main extends java.lang.Object with ScalaObject {
def this(): object Main = {
Main.super.this();
()
};
def main(argv: Array[String]): Unit = {
val args: Array[String] = argv;
{
final class $anon extends scala.AnyRef {
def this(): anonymous class $anon = {
$anon.super.this();
()
};
class C extends java.lang.Object with ScalaObject {
<synthetic> def p$default$1[T >: Null <: Any]: Null @scala.annotation.unchecked.uncheckedVariance = null;
def this(): this.C = {
C.super.this();
()
};
def p[T >: Null <: Any](t: T = null): T = t
}
};
{
new $anon();
()
}
}
}
}