什么时候Scala需要@uncheckedVariance,为什么在GenericTraversableTemplate中使用它?

时间:2010-03-16 12:33:26

标签: scala scala-2.8 annotations unchecked variance

@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 个答案:

答案 0 :(得分:28)

问题是GenericTraversableTemplate被使用了两次:一次用于可变集合(其类型参数应该是不变的),一次用于不可变集合(其中协方差总是为王)。

GenericTraversableTemplate的类型检查假定A类型参数的协方差或不变性。但是,当我们以可变特性继承它时,我们必须选择不变性。相反,我们喜欢不可变子类中的协方差。

因为我们无法在GenericTraversableTemplate中抽象出方差注释(但是;-)),所以我们可以根据子类将它实例化为任何一个,我们必须求助于转换(@uncheckVariance本质上是一种-投)。为了进一步阅读,我建议我的论文(对不起;-))或我们最近的bitrot paper

答案 1 :(得分:8)

在我的论文中,我描述了一个微积分,即斯卡利娜,它有一定的限制。方差注释作为种类语言的一部分(早期版本也可用作workshop paper)。与此讨论的相关性是我想要开发此微积分的下一步:在此基础上构建另一层,以便您可以抽象超出边界(简单)和方差注释(使我的头部旋转)。实际上,你不仅要在那里添加一个额外的层,而是概括你的多态构造,使它们在所有层次上工作,并将你的“属性”(边界,方差注释,必需的隐式参数......)变成常规类型特殊种类,都是抽象的。

Edsko de Vries在唯一性类型的背景下很好地解释了“属性是类型”的想法。

  

Uniqueness Typing Simplified,   Edsko de Vries,Rinus Plasmeijer和David Abrahamson。   在Olaf Chitil,ZoltánHorváth和ViktóriaZsók(编辑)中:   IFL 2007,LNCS 5083,pp.201-218,2008。

     

摘要:我们提出了一种唯一性类型   系统比两者都简单   清洁的独特性系统和   我们之前提出的系统。新的   类型系统很简单   实现并添加到现有的   编译器,可以很容易地扩展   具有更高的先进功能   等级类型和不可信度。我们   描述我们在Morrow中的实现,   实验性功能语言   具有这两个功能。最后,我们   证明核心类型的健全性   系统相对于   需要召唤的lambda演算。

答案 2 :(得分:5)

我发现了另一个使用@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();
          ()
        }
      }
    }
  }