Quand @uncheckedVariance est-il nécessaire dans Scala, et pourquoi est-il utilisé dans GenericTraversableTemplate?

@uncheckedVariance peut être utilisé pour combler l'écart entre les annotations de variance du site de déclaration de Scala et les génériques invariants 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

Cela dit que java.util.Comparateur 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 également utilisé dans la bibliothèque de collections Scala qui ne s'étend pas des interfaces Java?

trait GenericTraversableTemplate[+A, +CC[X] <: Traversable[X]] extends HasNewBuilder[A, CC[A] @uncheckedVariance]

Quelles sont les utilisations valides de cette annotation?

37
demandé sur retronym 2010-03-16 15:33:26

3 réponses

Le problème est que GenericTraversableTemplate est utilisé deux fois: une fois pour les collections mutables (où son paramètre de type doit être invariant), et une fois pour les collections immuables (où la covariance est invariablement roi).

Typechecks de GenericTraversableTemplate en supposant soit une covariance ou une invariance pour le paramètre de type A. Cependant, lorsque nous l'héritons dans un trait mutable, nous devons choisir l'invariance. Inversement, nous aimerions covariance dans une sous-classe immuable.

Puisque nous ne pouvons pas résumé sur l'annotation de variance (encore ;-)) dans GenericTraversableTemplate, de sorte que nous aurions pu l'instancier à l'une ou l'autre en fonction de la sous-classe, nous devons recourir à la coulée (@uncheckVariance est essentiellement un genre-cast). Pour en savoir plus, je recommande ma thèse (désolé; -)) ou notre récent bitrot papier

28
répondu Adriaan Moors 2010-03-16 13:36:49

Dans ma thèse, je décris un calcul, Scalina, qui a des annotations de limites et de variance dans le cadre du langage kind (une version antérieure est également disponible en tant que workshop paper). La pertinence de cette discussion est la prochaine étape que je veux prendre dans le développement de ce calcul: construire une autre couche au-dessus de cela afin que vous puissiez abstraire sur les limites (faciles) et les annotations de variance (fait tourner la tête). En fait, vous ne voudriez pas simplement ajouter 1 couche supplémentaire là-bas, mais plutôt généraliser votre le polymorphisme construit de sorte qu'ils fonctionnent à tous les niveaux, et font vos "attributs" (limites, annotations de variance, arguments implicites requis,...) en types réguliers avec des types spéciaux, qui sont tous soumis à l'abstraction.

L'idée" les attributs sont des types " est bien expliquée par Edsko De Vries dans le contexte des types d'unicité.

Typage Unique Simplifié , Edsko De Vries, Rinus Plasmeijer et David Abrahamson. Dans Olaf Chitil, Zoltán Horváth et Viktória Zsók (Eds.): ILM 2007, LNCS 5083, pp. 201-218, 2008.

Résumé: nous présentons un type d'unicité système qui est plus simple que les deux Le système d'unicité de Clean et le système que nous avons proposé précédemment. Nouvelle système de type est simple à mettre en œuvre et ajouter à l'existant Compilateurs, et peut facilement être étendu avec des fonctionnalités avancées telles que supérieur types de rang et impredicativité. Nous décrivez notre mise en œuvre demain, un langage fonctionnel expérimental avec ces deux caractéristiques. Enfin, nous prouver la solidité du type de noyau système à l'égard de la appel par nécessité lambda calcul.

8
répondu Adriaan Moors 2010-03-17 09:47:40

J'ai trouvé une autre fois où @uncheckedVariance est utilisé - la méthode synthétique qui renvoie 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();
          ()
        }
      }
    }
  }
5
répondu retronym 2010-03-24 09:48:05