是否添加了一个具有实现破坏向后兼容性的特征方法?

时间:2013-08-21 20:14:42

标签: scala binary-compatibility migration-manager

在将具有默认实现的方法添加到特征时,我对后向兼容性感到困惑。像:

以前的版本

trait Foo

新版本

trait Foo {
  def verifyConsistency: Option[String] = ??? // provide default implementation
}

Migration Manager将此添加报告为二进制不兼容。这是对的吗?

1 个答案:

答案 0 :(得分:13)

是的,这是正确的。

当您定义特征Foo时,它将在底层创建一个(JVM)接口Foo和一个(JVM)类Foo$class,其中所有方法实现都定义为静态方法。相应的java代码看起来像这样(对于Foo的新定义):

interface Foo {
  Option<String> verifyConsistency();
}

class Foo$class {
  static Option<String> verifyConsistency(Foo self) {
    Predef.???();
  }
}

当您将Foo混合到具体类Bar中时,JVM级别发生的事情是Bar扩展了接口Foo,并且它实现了方法{{1只需将调用转发给verifyConsistency

即可
Foo$class

这样做的原因是JVM对象模型不支持多重继承。 traits实现不能简单地放在你可以扩展的类中,因为你只能在JVM上扩展一个类。

这种情况的消除是,每当具体类混合一个特征时,该类为特征的每个成员定义“存根”方法(这些方法简单地转发到实际的实现,这是一个静态方法)。 / p>

一个结果是,如果向特征添加新方法,即使您定义了一个实现,也是不够的:需要重新编译混合特征的具体类(以便添加新方法的存根)班级)。如果你不重新编译这些类,你的程序将无法运行,因为你现在有一个应该具体的类(非抽象)并扩展相应的接口但实际上错过了新方法的实现。

在您的情况下,这意味着具有扩展接口class Bar implements Foo { Option<String> verifyConsistency() { return Foo$class.verifyConsistency(this); // simple forwarding } } 的具体类,但没有Foo的任何实现。

因此二进制不兼容。