Когда @uncheckedVariance требуется в Scala и почему он используется в GenericTraversableTemplate? - PullRequest
38 голосов
/ 16 марта 2010

@uncheckedVariance может использоваться для устранения разрыва между аннотациями на сайте объявлений Scala и инвариантными обобщениями 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

Это говорит о том, что java.util.Comparator, естественно, противоречит варианту, то есть параметр типа T появляется в параметрах, а не в возвращаемом типе.

Возникает вопрос: почему он также используется в библиотеке коллекций Scala, которая не распространяется на интерфейсы Java?

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

Как правильно использовать эту аннотацию?

Ответы [ 3 ]

28 голосов
/ 16 марта 2010

Проблема в том, что GenericTraversableTemplate используется дважды: один раз для изменяемых коллекций (где его параметр типа должен быть инвариантным), и один раз для неизменяемых коллекций (где ковариация всегда является королем).

Проверки типов GenericTraversableTemplate, предполагающие ковариацию или инвариантность для параметра типа A. Однако, когда мы наследуем это в изменчивой черте, мы должны выбрать инвариантность. И наоборот, мы хотели бы ковариации в неизменяемом подклассе.

Так как мы не можем абстрагироваться от аннотации дисперсии (пока ;-)) в GenericTraversableTemplate, так что мы могли бы создать ее экземпляр в зависимости от подкласса, мы должны прибегнуть к приведению (@uncheckVariance по сути является -бросать). Для дальнейшего чтения я рекомендую свою диссертацию (извините ;-)) или нашу недавнюю бумагу с битрейтом

8 голосов
/ 17 марта 2010

В моей дипломной работе я описываю исчисление Scalina, которое имеет границы и аннотации отклонений как часть доброго языка (более ранняя версия также доступна в виде мастерской ). Актуальность этой дискуссии - следующий шаг, который я хочу предпринять при разработке этого исчисления: создайте еще один слой поверх него, чтобы вы могли абстрагироваться от границ (легко) и аннотаций отклонений (у меня кружится голова). На самом деле, вы не просто добавили бы 1 дополнительный слой, а просто обобщили бы свои конструкции полиморфизма, чтобы они работали на всех уровнях, и превратили ваши «атрибуты» (границы, аннотации отклонений, требуемые неявные аргументы, ...) в обычные типы со специальными видами, которые все подлежат абстракции.

Идея «атрибуты - это типы» хорошо объясняется Эдско де Фрисом в контексте типов уникальности.

Уникальность набора номера упрощена , Эдско де Врис, Ринус Плазмейер и Дэвид Абрахамсон. В Олаф Читил, Золтан Хорват и Виктория Жок (ред.): IFL 2007, LNCS 5083, pp. 201-218, 2008.

Аннотация: Мы представляем тип уникальности система, которая проще, чем оба Система уникальности Clean и Система, которую мы предложили ранее. Новый Система типов проста в внедрить и добавить к существующим компиляторы, и могут быть легко расширены с расширенными функциями, такими как высшее ранговые типы и непредсказуемость. Мы опишите нашу реализацию в Морроу, экспериментальный функциональный язык с обеими этими функциями. Наконец, мы доказать обоснованность основного типа система по отношению к лямбда-исчисление по требованию.

5 голосов
/ 24 марта 2010

Я нашел другой случай, когда используется @uncheckedVariance - синтетический метод, который возвращает значение по умолчанию для параметра абстрактного типа:

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();
          ()
        }
      }
    }
  }
...