AbstractMethodError 混入嵌套在对象中的特征时 - 仅在编译和导入时
AbstractMethodError when mixing in trait nested in object - only when compiled and imported
考虑以下代码:
object Impls {
trait ConcreteImpl {
type Foo = Int
def foo = 1
}
}
trait Base {
type Foo
def foo: Foo
}
我对表达式感兴趣
(new Base with Impls.ConcreteImpl).foo
当我将上面的代码粘贴到 REPL 中,或将其 运行 粘贴到工作表中,然后尝试表达式时——没问题,它会按预期打印 res0: Int = 1
。
当我把代码放在一个文件中,用 scalac
编译它,然后在同一目录中使用 REPL 中编译的 class 文件时,我得到了相同的结果。
但是,当我使用编译文件的时候,再说从REPL
import Impls._
(new Base with ConcreteImpl).foo
它抛出
java.lang.AbstractMethodError: $anon.foo()I
如果我将所有代码粘贴到 REPL 中,并使用导入变体,不会 发生这种情况。
这里发生了什么?这甚至是预期的行为吗?如果相关,我正在使用
Scala version 2.11.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45)
这显然是一个错误。
如果你:
java.lang.AbstractMethodError: $line13.$read$$iw$$iw$$iw$$iw$$iw$$iw$$anon.foo()I
... 33 elided
scala> :javap -p $line13.$read$$iw$$iw$$iw$$iw$$iw$$iw$$anon
Compiled from "<console>"
public final class $line13.$read$$iw$$iw$$iw$$iw$$iw$$iw$$anon implements p.Base,p.Impls$ConcreteImpl {
public java.lang.Object foo();
public $line13.$read$$iw$$iw$$iw$$iw$$iw$$iw$$anon();
}
它没有结果类型为 Int 的 foo。
顺便说一句,我无法想象 REPL 中的差异,但我们正要看电影...不过,您可以在 Ammonite 中尝试一下。
大多数此类错误是由于 REPL 是常驻编译器这一事实造成的,但这对现有 class 文件的编译有何影响并不明显。
编辑:
它第一次使用完全限定名称时有效,但在显示失败后,完全限定名称再次失败。
scala> (new p.Base with p.Impls.ConcreteImpl).foo // show
//works
res0: Int = 1
scala> import p._
import p._
scala> import Impls._
import Impls._
scala> (new Base with ConcreteImpl).foo // show
// fails
java.lang.AbstractMethodError: $anon.foo()I
... 33 elided
scala> (new p.Base with p.Impls.ConcreteImpl).foo // show
// also fails
java.lang.AbstractMethodError: $anon.foo()I
... 33 elided
这显然是一个常驻编译器错误。 (classes 在此处的包 p 中。)
编辑:实际上 SI-9689。
考虑以下代码:
object Impls {
trait ConcreteImpl {
type Foo = Int
def foo = 1
}
}
trait Base {
type Foo
def foo: Foo
}
我对表达式感兴趣
(new Base with Impls.ConcreteImpl).foo
当我将上面的代码粘贴到 REPL 中,或将其 运行 粘贴到工作表中,然后尝试表达式时——没问题,它会按预期打印 res0: Int = 1
。
当我把代码放在一个文件中,用 scalac
编译它,然后在同一目录中使用 REPL 中编译的 class 文件时,我得到了相同的结果。
但是,当我使用编译文件的时候,再说从REPL
import Impls._
(new Base with ConcreteImpl).foo
它抛出
java.lang.AbstractMethodError: $anon.foo()I
如果我将所有代码粘贴到 REPL 中,并使用导入变体,不会 发生这种情况。
这里发生了什么?这甚至是预期的行为吗?如果相关,我正在使用
Scala version 2.11.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45)
这显然是一个错误。
如果你:
java.lang.AbstractMethodError: $line13.$read$$iw$$iw$$iw$$iw$$iw$$iw$$anon.foo()I
... 33 elided
scala> :javap -p $line13.$read$$iw$$iw$$iw$$iw$$iw$$iw$$anon
Compiled from "<console>"
public final class $line13.$read$$iw$$iw$$iw$$iw$$iw$$iw$$anon implements p.Base,p.Impls$ConcreteImpl {
public java.lang.Object foo();
public $line13.$read$$iw$$iw$$iw$$iw$$iw$$iw$$anon();
}
它没有结果类型为 Int 的 foo。
顺便说一句,我无法想象 REPL 中的差异,但我们正要看电影...不过,您可以在 Ammonite 中尝试一下。
大多数此类错误是由于 REPL 是常驻编译器这一事实造成的,但这对现有 class 文件的编译有何影响并不明显。
编辑:
它第一次使用完全限定名称时有效,但在显示失败后,完全限定名称再次失败。
scala> (new p.Base with p.Impls.ConcreteImpl).foo // show
//works
res0: Int = 1
scala> import p._
import p._
scala> import Impls._
import Impls._
scala> (new Base with ConcreteImpl).foo // show
// fails
java.lang.AbstractMethodError: $anon.foo()I
... 33 elided
scala> (new p.Base with p.Impls.ConcreteImpl).foo // show
// also fails
java.lang.AbstractMethodError: $anon.foo()I
... 33 elided
这显然是一个常驻编译器错误。 (classes 在此处的包 p 中。)
编辑:实际上 SI-9689。