以下“非法继承”背后的原因是什么(Scala 2.9.2)?

时间:2012-06-28 22:24:10

标签: scala inheritance traits type-erasure type-parameter

更新:我用更小更精确的例子重述了我的问题。

假设我们有以下定义:

class A
trait TraitForA extends A

class D[T]
trait TraitForD extends D[A]

然后我们可以创建一个像这样的对象:

scala> new D[A] with TraitForD
res0: D[A] with TraitForD = $anon$1@145d424

但我们无法创建以下对象:

scala> new D[A with TraitForA] with TraitForD
<console>:12: error: illegal inheritance;
 anonymous class $anon inherits different type instances of class D:
D[A] and D[A with TraitForA]
             new D[A with TraitForA] with TraitForD
                 ^

当使用自我类型而不是extends时,会发生同样的事情:

scala> trait TraitForD2 { self: D[A] => }
defined trait TraitForD2

scala> new D[A with TraitForA] with TraitForD2
<console>:12: error: illegal inheritance;
 self-type D[A with TraitForA] with TraitForD2 does not conform to TraitForD2's
selftype TraitForD2 with D[A]
              new D[A with TraitForA] with TraitForD2
                                           ^

上面的创作有什么(确切)错误?

我的猜测是D[A with TraitForA]不被视为D[A]类型。在类+T中使用协变注释D时,两个示例都有效。

有人可以解释一下示例失败的原因以及他们与+T合作的原因吗?

加分问题:有没有办法让这些示例在没有+T的情况下运行?

2 个答案:

答案 0 :(得分:3)

考虑

class C[T]{ def f(t: T): T = t }

C[A with Y]表示它只会f A with Y,只会返回A with Y。满足此请求的函数无法满足C[A]。因此两者发生冲突。

由于类型声明成功不取决于所涉及的任何类的方法的详细信息,Z1 with Z2或任何其他组合C[A]C[A with Y]的方法必定是错误。

答案 1 :(得分:0)

要查看方差问题,让我们为'TraitForX'添加一些方法。为简单起见,我会将这些特征称为A1D1,并且为了简单起见,我还会制作AD特征。我不知道你是如何设法得出有趣的结构 - 我不知道trait甚至可以扩展class,这是奇怪的,它是允许的!

trait A
trait A1 extends A { def schoko = 33 }

trait D[T] { def result: T }
trait D1 extends D[A] {
   def result: A = new A {}
}

现在我们知道我们可以使用A1的实例执行某项​​操作,但A的实例无法实现。此外,D1具有result的具体实现。

仍然可以重现您的案例:

new D[A] with D1    // works.

new D[A with A1] {  // works.
   def result = new A with A1 {}
   def test = result.schoko
}

您可以看到test可以调用方法result,因为D使用A with A1进行参数化(顺便提一下A1 ),可随后致电schoko

以下内容永远不会起作用:

new D[A with A1] with D1 {
   def test = result.schoko
}

编译器会说value schoko is not a member of A,这意味着它拒绝接受D的参数化。 result中已实施D1以返回A的实例(不知道schoko),因此此处存在固有冲突。


现在D更改为

trait D[+T] { def result: T }

(所有其余的仍然如上),你只是'推迟'问题:

new D[A with A1] with D1

编译器现在抱怨error: overriding method result in trait D of type => A with A1(您认为这有效,因为您实际上没有实现result)。

因此,方差注释允许您执行之前无法做到的某些事情。如果您尚未实施result,则完全可以实现以下目标:

trait D2 extends D[A]

new D[A with A1] with D2 {
   def result = new A with A1 {}
}