¿Cuándo se necesita @uncheckedVariance en Scala y por qué se usa en GenericTraversableTemplate?


@uncheckedVariance se puede usar para cerrar la brecha entre las anotaciones de varianza del sitio de declaración de Scala y los genéricos 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

Esto dice que java.útil.Comparador es naturalmente contra-variante, es decir, el parámetro de tipo T aparece en los parámetros y nunca en un tipo de retorno.

Esto plantea la pregunta: ¿por qué también se usa en la biblioteca de colecciones de Scala que no se extiende desde las interfaces Java?

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

¿Cuáles son los usos válidos para esta anotación?

Author: retronym, 2010-03-16

3 answers

El problema es que GenericTraversableTemplate se usa dos veces: una para colecciones mutables (donde su parámetro de tipo debe ser invariante), y una para colecciones inmutables (donde la covarianza es invariablemente rey).

Las comprobaciones de tipo de GenericTraversableTemplate asumen covarianza o invariancia para el parámetro tipo A. Sin embargo, cuando lo heredamos en un rasgo mutable, tenemos que elegir invariancia. Por el contrario, nos gustaría covarianza en una subclase inmutable.

Ya que no podemos abstract sobre la anotación de varianza (yet ;-)) en GenericTraversableTemplate, de modo que podríamos haberlo instanciado a cualquiera dependiendo de la subclase, tenemos que recurrir al casting (@uncheckVariance es esencialmente un cast de tipo). Para leer más, recomiendo mi disertación (lo siento; -)) o nuestro reciente bitrot paper

 28
Author: Adriaan Moors,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-16 13:36:49

En mi tesis describo un cálculo, Scalina, que tiene anotaciones de límites y varianza como parte del lenguaje tipo (una versión anterior también está disponible como un documento de taller ). La relevancia de esta discusión es el siguiente paso que quiero dar en el desarrollo de este cálculo: construir otra capa encima de eso para que pueda abstraer sobre los límites (fácil) y anotaciones de varianza (hace que mi cabeza gire). En realidad, no solo agregaría 1 capa adicional allí, sino que generalizaría su construcciones de polimorfismo para que funcionen en todos los niveles, y hagan sus "atributos" (límites, anotaciones de varianza, argumentos implícitos requeridos,...) en tipos regulares con tipos especiales, que están sujetos a abstracción.

La idea de "los atributos son tipos" es explicada muy bien por Edsko de Vries en el contexto de los tipos de unicidad.

Uniqueness Typing Simplified, Edsko de Vries, Rinus Plasmeijer y David Abrahamson. En Olaf Chitil, Zoltán Horváth y Viktória Zsók (Eds.): IFL 2007, LNCS 5083, pp 201-218, 2008.

Resumen: Presentamos un tipo de unicidad sistema que es más simple que ambos Sistema de singularidad de Clean y sistema que propusimos anteriormente. El nuevo tipo de sistema es sencillo implementar y agregar a los existentes compiladores, y se puede extender fácilmente con características avanzadas tales como más alto tipos de rango e impredicatividad. Nos describir nuestra implementación en Morrow, un lenguaje funcional experimental con ambas características. Finalmente, probar la solidez del tipo de núcleo sistema con respecto a la call-by-need cálculo lambda.

 8
Author: Adriaan Moors,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-17 09:47:40

Encontré otra vez donde se usa @uncheckedVariance the el método sintético que devuelve el valor predeterminado para un parámetro de tipo abstracto:

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
Author: retronym,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-24 09:48:05