Pergunta

@uncheckedVariance pode ser usado para preencher a lacuna entre as anotações de variação do site de declaração do Scala e os genéricos invariantes do 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

Isso diz que java.util.Comparator é naturalmente contra-variante, que é o parâmetro de tipo T aparece em parâmetros e nunca em um tipo de retorno.

Isso levanta a questão:por que também é usado na biblioteca de coleções Scala que não se estende das interfaces Java?

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

Quais são os usos válidos para esta anotação?

Foi útil?

Solução

O problema é que GenericTraversableTemplate é usado duas vezes:uma vez para coleções mutáveis ​​(onde seu parâmetro de tipo deve ser invariável) e uma vez para coleções imutáveis ​​(onde a covariância é invariavelmente rei).

As verificações de tipo de GenericTraversableTemplate assumem covariância ou invariância para o parâmetro de tipo A.No entanto, quando herdamos uma característica mutável, temos que escolher a invariância.Por outro lado, gostaríamos de covariância em uma subclasse imutável.

Como não podemos abstrair a anotação de variação (ainda ;-)) em GenericTraversableTemplate, para que pudéssemos instanciá-la para qualquer uma delas dependendo da subclasse, temos que recorrer à conversão (@uncheckVariance é essencialmente uma conversão de tipo) .Para leitura adicional, recomendo minha dissertação (desculpe ;-)) ou nosso recente papel bitrot

Outras dicas

Na minha tese, descrevo um cálculo, Scalina, que possui anotações de limites e variância como parte da linguagem tipo (uma versão anterior também está disponível como um papel de oficina). A relevância para esta discussão é a próxima etapa que quero dar ao desenvolver este cálculo: construir outra camada sobre isso para que você possa abstrair sobre os limites (fácil) e anotações de variância (faz minha cabeça girar). Na verdade, você não apenas prenderia 1 camada extra lá, mas generalizaria suas construções de polimorfismo para que elas funcionem em todos os níveis e faça seus "atributos" (limites, anotações de variação, discussões implícitas, ...) em tipos regulares com tipos especiais, todos sujeitos a abstração.

A idéia "atributos são tipos" é explicada bem por Edsko de Vries no contexto dos tipos de singularidade.

A digitação de singularidade simplificada, Edsko de Vries, Rinus Plasmeijer e David Abrahamson. Em Olaf Chitil, Zoltán Horváth e Viktória Zsók (Eds.): IFL 2007, LNCS 5083, pp. 201-218, 2008.

Resumo: Apresentamos um sistema de tipo exclusivo que é mais simples que o sistema de singularidade da Clean e o sistema que propusemos anteriormente. O novo sistema de tipos é direto para implementar e adicionar aos compiladores existentes e pode ser facilmente estendido com recursos avançados, como tipos de classificação mais altos e imedicatividade. Descrevemos nossa implementação em Morrow, uma linguagem funcional experimental com esses dois recursos. Finalmente, provamos a solidez do sistema de tipo de núcleo em relação ao cálculo lambda de chamada por necessidade.

Encontrei outra época em que o @uncheckedVariance é usado - o método sintético que retorna o valor padrão para um parâmetro de um tipo de abstração:

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();
          ()
        }
      }
    }
  }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top