Scalaで@uncheckedVarianceが必要なのはいつですか?なぜGenericTraversableTemplateで使用されるのですか?
-
20-09-2019 - |
質問
@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 Collectionsライブラリでも使用されるのですか?
trait GenericTraversableTemplate[+A, +CC[X] <: Traversable[X]] extends HasNewBuilder[A, CC[A] @uncheckedVariance]
この注釈の有効な用途は何ですか?
解決
問題は、GenericTraversableTemplateが2回使用されることです。1回は、1回の可変コレクション(そのタイプパラメーターが不変の必要がある場合)、1回は不変のコレクション(共分散が常に王)で使用されます。
A型パラメーターの共分散または不変のいずれかを想定しているGenericTraversableTemplateのTypeChecks。ただし、可変性で継承する場合、不変性を選択する必要があります。逆に、私たちは不変のサブクラスに共分散を望んでいます。
GenericTraversableTemplateでの分散アノテーション(まだ;-))を抽象化できないため、サブクラスに応じていずれかにインスタンス化できたため、キャストに頼る必要があります(@uncheckvarianceは本質的に親切なキャストです) 。さらに読むには、論文(ごめん;-))または最近のことをお勧めします ビットロットペーパー
他のヒント
私の論文では、種類の言語の一部として境界と分散の注釈があるCalculus、Scalinaについて説明しています(以前のバージョンも利用できます。 ワークショップペーパー)。この議論との関連性は、この計算を開発する際に取る次のステップです。その上に別のレイヤーを構築して、境界(簡単)と分散アノテーション(ヘッドスピン)を抽象化できるようにします。実際、そこに1つの余分なレイヤーをタックするだけでなく、あらゆるレベルで動作し、「属性」(境界、分散アノテーション、必要な暗黙の引数など)を通常のタイプにするように、多型構造を一般化することになります。すべて抽象化の対象となる特別な種類があります。
「属性はタイプです」アイデアは、ユニークネスタイプのコンテキストでエドスコデヴリーによってうまく説明されています。
ユニークさのタイピングが簡素化されました, 、Edsko de Vries、Rinus Plasmeijer、およびDavid Abrahamson。 Olaf Chitil、ZoltánHorváth、ViktóriaZsók(編):IFL 2007、LNCS 5083、pp。201-218、2008。
要約:Cleanの一意性システムと以前に提案したシステムの両方よりも単純な一意性タイプシステムを提示します。新しいタイプシステムは、既存のコンパイラに実装して追加するのに簡単であり、より高いランクタイプや印象的性質などの高度な機能で簡単に拡張できます。これらの両方の機能を備えた実験的な機能的言語であるMorrowでの実装について説明します。最後に、コールごとのラムダ計算に関して、コアタイプシステムの健全性を証明します。
@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();
()
}
}
}
}