3

パス依存型をリフレクションで使用すると、「基底型」と一致する場合でも型の不一致エラーが発生します。これらの「非基底型」とは何か、「基礎型」の代わりにそれらをチェックするのはなぜですか?パス依存タイプと「基礎タイプ」のどちらがチェックされていますか?

以下のコードでは、compareメソッドは、引数として同じタイプのサブクラスAのみを受け入れるようにします。エラーは最後の行にあります。私はこのエラーを取得する最後の行に

abstract class A(val a:Int) { 
    type Impl <: A 
    def compare(other:Impl) { 
    if(a==other.a) println("equal") else println("diff") 
    } 
} 
class B(a:Int) extends A(a) {type Impl = B} 

object Test { 
    def newInst(a: Int, className: String) = { 
    val constr = Class.forName(className).getConstructors()(0) 
    constr.newInstance(a.asInstanceOf[AnyRef]).asInstanceOf[A] 
    } 

    def main(args: Array[String]) { 
    val b1 = newInst(4, "B") 
    val b2 = newInst(5, "B") 
    b1.compare(b2) // type mismatch error here 
    } 
} 

error: type mismatch; 
found : b2.type (with underlying type A) 
required: b1.Impl 

B2のタイプ(A)とB1のタイプと同じであるので、私はこのエラーを生成しないことが期待。何らかの理由で、これらのパス依存型は、リフレクションを使用するときの「基底型」とは異なります。どうして?

私はリフレクションを使用しない場合、それは動作します:

val b1 = new B(4) 
val b2 = new B(5) 
b1.compare(b2) // no errors 

(私は私の場合にはリフレクションを使用する必要があります)。 newInst()は反射を使ってオブジェクトをクラス "B"として返すことができますか?これは役に立ちますか?抽象タイプを使用しているときにタイプ消去がありますか?

これは唯一のエラーであることがわかりましたが(on this forum)、関連していない可能性があります。

+0

ありがとうございました!それは本当に奇妙で、回避策を見つけるために私を1日かかって、ついにあなたのポストを見ました。 –

答えて

5

これは反射とは関係ありません。 b1b2のタイプはAです(戻りタイプはです)。 b1.compare(b2)のコールをコンパイルするには、b2のタイプがb1.Implである必要があります。コンパイラは、Aのサブタイプであることだけを知っていますが、どのサブタイプであるかはわかりません。サブタイプがAの場合はAを渡すことができないため、エラーが発生します。例では

val b1 = new B(4) 
val b2 = new B(5) 
b1.compare(b2) // no errors 

両方の変数は、型Bを持っている、とB#ImplBなので、すべてのtypechecks。

+0

私はそれも分かりました。 "根本的なタイプ"という表現は少し誤解を招きますが、実際には "親のタイプ"を意味します。理想的には、newInstの戻り値の型を "className"のクラスにキャストしたいが、それはScalaでは不可能であるように見える。 – Adrian

5

I just figured that out too. The expression "underlying type" is a bit misleading, while it actually means "parent type". Ideally I would like to cast the return type of newInst to the class of "className" but that looks like it is not possible in Scala. "

「親タイプ」という意味ではありません。そのタイプは親であることになります。基本的な型は、シングルトン型の拡張を指します。番号5のタイプはシングルトンです。その基礎となる型はIntです。ほとんどの人はIntを "親の型"と呼んでいません。 (たとえそれがあっても)

質問には、ただキャストするだけです。あなたの方法で立つものはありません。スカラはありませんし、javaはできません。

def main(args: Array[String]) { 
    val b1 = newInst(4, "B") 
    val b2 = newInst(5, "B") 
    b1.compare(b2.asInstanceOf[b1.Impl]) 
} 
% scala Test 
diff 
+0

私が意図したことは、newInst()の内部で戻り値が返される前にそれをキャストすることです。私は利用可能な型を持っていないので(私はクラスしか持っていない)、私はそれを行う方法を見ません。可能であれば、型チェッカーは実行時の値(className)に基づいてコンパイル時にnewInst()の型を推論することができますが、もちろん不可能です。私はこれがまた、 "基礎をなすタイプ"の意味を明確にしていると思います。実行時の型はobject.typeとしてしか知られていませんが、コンパイル時には最も具体的な型です。「シングルトンを拡張する」という意味がわかりません。 b2はシングルトンではありません。 – Adrian

+1

b2は絶対にシングルトンです。 "b2.type"とはどういう意味ですか?それはb2のタイプです。世界のb1、b3、またはそれ以外のものではありません。 – extempore

+0

b2はAにキャストされたBのインスタンスです。これは私の本(PinS)の 'object'キーワードで定義されたオブジェクトであるシングルトンではありません。私はここで何が欠けていますか? – Adrian