【问题标题】:When is @uncheckedVariance needed in Scala, and why is it used in GenericTraversableTemplate?Scala 什么时候需要@uncheckedVariance,为什么在 GenericTraversableTemplate 中使用它?
【发布时间】:2011-01-28 02:20:41
【问题描述】:

@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 出现在参数中,从不出现在返回类型中。

这提出了一个问题:为什么它还用于不从 Java 接口扩展的 Scala 集合库中?

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

此注解的有效用途是什么?

【问题讨论】:

    标签: scala scala-2.8 annotations unchecked variance


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      在我的论文中,我描述了一种微积分 Scalina,它具有边界和方差注释作为类语言的一部分(早期版本也可作为 workshop paper 获得)。与此讨论相关的是我想在开发此微积分时采取的下一步:在此之上构建另一个层,以便您可以抽象出边界(简单)和方差注释(让我头晕目眩)。实际上,您不会只是在其中添加 1 个额外的层,而是将您的多态性构造泛化,以便它们在所有级别上工作,并将您的“属性”(边界、方差注释、所需的隐式参数......)变成常规类型有特殊的种类,它们都是抽象的。

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

      Uniqueness Typing Simplified, Edsko de Vries、Rinus Plasmeijer 和 David Abrahamson。 在 Olaf Chitil、Zoltán Horváth 和 Viktória Zsók(编辑)中: IFL 2007,LNCS 5083,第 201-218 页,2008。

      摘要:我们提出了一种唯一性类型 比两者都简单的系统 Clean的唯一性系统和 我们之前提出的系统。新的 类型系统很简单 实施并添加到现有的 编译器,并且可以很容易地扩展 具有高级功能,例如更高 等级类型和不可预测性。我们 描述我们在 Morrow 的实现, 一种实验性的功能语言 具有这两个功能。最后,我们 证明核心类型的健全性 系统相对于 按需调用 lambda 演算。

      【讨论】:

        【解决方案3】:

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

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

        由于我们不能抽象 GenericTraversableTemplate 中的方差注释(还 ;-)),因此我们可以根据子类将其实例化为任何一个,我们必须求助于强制转换(@uncheckVariance 本质上是一种-投掷)。为了进一步阅读,我推荐我的论文(对不起;-))或我们最近的bitrot paper

        【讨论】:

        • 谢谢!上周我很喜欢阅读 bitrot 论文,但它并没有专门处理在一个共同的父项下集成同变体和同变体集合的问题。我想我会看看你的论文有什么:)
        • 嗯,这主要是一个无耻的插件——我的论文并没有真正直接处理这个确切的问题。不过,它应该对这种更强大的多态性有更多的思考。我将在下面添加更多想法。
        • “永远的王者”……哈哈
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-05
        • 1970-01-01
        • 1970-01-01
        • 2012-09-16
        • 2010-10-15
        • 1970-01-01
        相关资源
        最近更新 更多