Подтвердить что ты не робот

Когда @uncheckedVariance необходимо в Scala и почему он используется в GenericTraversableTemplate?

@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]

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

Идея "атрибуты типа" хорошо объясняется Эдско де Врисом в контексте уникальных типов.

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

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

Ответ 3

Я нашел еще раз, когда используется @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();
          ()
        }
      }
    }
  }