2013-04-08 16 views
9


私が持っているコンパイラエラーとタイプをオーバーライドすることはできませんし、私はそれが参照するんかわからない:
は、これらの宣言を想定します。私はここで達成しようとしている何は、Scalaでは、不揮発性上限

trait Abstract { 
    type MyType 
} 
trait AInner 
trait A extends Abstract{ 
    type MyType <: AInner 
} 
trait BInner { 
    def bMethod : Int 
} 
trait B extends Abstract with A{ 
    override type MyType <: BInner with A#MyType 
} 
(特性 B)は MyTypeAbstractで宣言されていることをさらに制限するため、タイプ MyTypeの値はmixinツリーの MyTypeすべてを拡張する必要があります。

コンパイラが(タイトルのように)このメッセージを私に渡しています: タイプMyTypeは揮発性タイプです。非揮発性上限を持つ型をオーバーライドすることはできません。私はそのタイプのボラティリティがため、型接続詞with A#MyTypeのここで起こっている、理解して、エラーの一部:と型不揮発性上限おそらくAInnerは、このように非抽象型ではない型宣言type MyType <: AInnerを指し、揮発性。

どうしてできないのですか?私の目標を達成する方法はありますか?

答えて

10

コンパイラでこのチェックを外すと、無気力の可能性を照らし出すことができます。

diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala 
index 37a7e3c..78a8959 100644 
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala 
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala 
@@ -5128,8 +5128,7 @@ trait Typers extends Adaptations with Tags { 

     def typedSelectFromTypeTree(tree: SelectFromTypeTree) = { 
     val qual1 = typedType(tree.qualifier, mode) 
-  if (qual1.tpe.isVolatile) TypeSelectionFromVolatileTypeError(tree, qual1) 
-  else typedSelect(tree, qual1, tree.name) 
+  typedSelect(tree, qual1, tree.name) 
     } 

     def typedTypeBoundsTree(tree: TypeBoundsTree) = { 

その後、揮発性の種類の違法なタイプを選択するためのコンパイラのテストケースからコードを実行している:

scala> class A; class B extends A 
defined class A 
defined class B 

scala> trait C { 
    | type U 
    | trait D { type T >: B <: A } 
    | val y: (D with U)#T = new B 
    | } 
defined trait C 

scala> class D extends C { 
    | trait E 
    | trait F { type T = E } 
    | type U = F 
    | def frob(arg : E) : E = arg 
    | frob(y) 
    | } 
defined class D 

scala> new D 
java.lang.ClassCastException: B cannot be cast to D$E 

私の理解では、問題は、Scalaは真の持っていないという事実から生じます交差タイプ。

scala> type A = { type T = Int } 
defined type alias A 

scala> type B = { type T = String } 
defined type alias B 

scala> "": (A with B)#T 
res16: String = "" 

scala> 0: (A with B)#T 
<console>:37: error: type mismatch; 
found : Int(0) 
required: String 
       0: (A with B)#T 
      ^

Dependent Object Types (DOT)の研究が実を結ぶ場合、これは、将来的に変更される可能性があります。

+1

非揮発性タイプで抽象メソッドメンバが禁止されているのはなぜですか? – Blaisorblade

0

どうしたのですか? trait Bのいずれかの実現において

trait B extends Abstract with A { 
    override type MyType <: BInner with AInner 
} 

MyType常にそれ自体はそれほど上位バウンディング、trait Aから見たものと同じタイプになりますどんな意味がありません。

、それはあなたがtrait Aにバインド変更する場合は、使用をtrait Bを書き換える必要がありますことを気にするコードの上片での場合:

trait A extends Abstract{ 
    type ABound = AInner 
    type MyType <: AInner 
} 
trait B extends Abstract with A { 
    override type MyType <: BInner with ABound 
} 
+0

それは良い解決策に見えますが、まだ理解していないことがなぜ必要なのでしょうか。レオの答えに対する私のコメントはここで同じです...仕様は、揮発性タイプが使用される可能性があることについてはっきりしていますが、それが意味するものについては有益ではありません。唯一のヒントは、「型にnull以外の値がない可能性を近似している」ということですが、それはこの文脈で誤解を招く説明であると推測しています。何かご意見は? – mergeconflict

1

あなたについて、後に(それ以上とtrait Bを書き換えることができます目標は少し違うと思います)

trait B extends A { 
    type MyType <: BInner with AInner 
} 

これは完全に意味があります。タイプB#MyTypeの値は、BInnerまたはAInnerと見なすことができます。

AはすでにAbstractのサブクラスであるため、Abstractを繰り返す必要はありません。これは型宣言のために暗黙的であるため、overrideを書く必要はありません。ですから、A#MyTypeAInnerとして機能していないのはなぜですか?

ここでは、揮発性タイプについてのスカラー言語の仕様について説明します。仕様で言及

3.6 Volatile Types

Type volatility approximates the possibility that a type parameter or abstract type instance of a type does not have any non-null values. As explained in (§3.1), a value member of a volatile type cannot appear in a path. A type is volatile if it falls into one of four categories: A compound type T1 with ... with Tn {R } is volatile if one of the following two conditions hold. 1. One of T2, ..., Tn is a type parameter or abstract type, or 2. T1 is an abstract type and and either the refinement R or a type Tj for j > 1 contributes an abstract member to the compound type, or 3. one of T1, ..., Tn is a singleton type. Here, a type S contributes an abstract member to a type T if S contains an abstract member that is also a member of T . A refinement R contributes an abstract member to a type T if R contains an abstract declaration which is also a member of T . A type designator is volatile if it is an alias of a volatile type, or if it designates a type parameter or abstract type that has a volatile type as its upper bound. A singleton type p.type is volatile, if the underlying type of path p is volatile. An existential type T forSome {Q } is volatile if T is volatile.

その他の重要な項目は、抽象型のオーバーライドについてです:

Another restriction applies to abstract type members: An abstract type member with a volatile type (§3.6) as its upper bound may not override an abstract type member which does not have a volatile upper bound.

コンパイルエラーがある:

error: overriding type MyType in trait A with bounds <: AInner; 
type MyType is a volatile type; cannot override a type with non-volatile upper bound 

これは仕様と一致しています。 BInner with A#MyTypeは揮発性です。その前にMyTypeは不揮発性がAnyであった。

スカラ型システムの型は、固有の意味を持たなければならないということです。抽象型は、宣言がサブクラスに継承される型と考えることができます。したがって抽象型の値を宣言する際には抽象型のままであれば問題ありません。一方、BInner with A#MyTypeのようなタイプの場合、このタイプにはいくつかの意味があります。これはvolatileと呼ばれ、MyType抽象タイプをインスタンス化するサブクラスと同じ型を持つことができるので、この型の非null値を持つことは意味がありません。事態を単純化するために、揮発性タイプは、サブタイプではないタイプ(Any(かつ揮発性タイプはサブタイプAny)と考えることができます)。したがって、コンパイラには矛盾があります。

あなたはこのような内部の特徴には、このおかげで達成することができます

What I'm trying to achieve here(in trait B) is to further restrict the type MyType declared > in Abstract, so any value of type MyType must extend all the MyTypes in the mixin tree.

としてあなたが述べ、あなたの目標に戻って来ます。

trait Abstract { 
    type MyType 
} 
trait B extends Abstract { 
    trait MyType { 
    def bMethod : Int 
    } 
} 
trait A extends B { 
    trait MyType extends super.MyType { 
    } 
} 

これはあなたが探しているものです。

+0

私はあなたの解釈は「A#MyType」が抽象的であるため、「A#MyType'を持つBInnerは奇妙です」とは正しいとは思いません。それは全く同じように奇妙に見えるが、例えば、「Abstract#MyTypeを持つAInner」を書くことは完全に有効である。この仕様は、揮発性タイプが使用される可能性があることについてはっきりとしていますが、それらが意味するものについては有益ではありません(つまり、それらのルールが健全性のために必要な理由)。唯一のヒントは、「型にnull以外の値がない可能性を近似している」ということです。あなたの議論がそれをキャプチャするとは思いません。 – mergeconflict

+0

@mergeconflict私は議論を取り直し、今ははるかに明確になることを願っています。 – Leo

関連する問題