在实现中添加特征方法会破坏向后兼容性吗? [英] Is adding a trait method with implementation breaking backward compatibility?

查看:79
本文介绍了在实现中添加特征方法会破坏向后兼容性吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对向特性添加默认实现的方法 的向后兼容性感到困惑.喜欢:

以前的版本

trait Foo

新版本

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

迁移管理器将此添加报告为二进制不兼容.正确吗?

解决方案

是的,它是正确的.

定义特征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,并且它通过简单地将调用转发到verifyConsistency >:

class Bar implements Foo {
  Option<String> verifyConsistency() {
    return Foo$class.verifyConsistency(this); // simple forwarding
  }
}

之所以这样做,是因为JVM对象模型不支持多重继承. traits实现不能简单地放在您要扩展的类中,因为您只能在JVM上扩展单个类.

这种情况的消除是,每当一个具体的类混合一个特征时,该类就为该特征的每个成员定义存根"方法(这些方法只是转发给实际的实现,这是一个静态方法)./p>

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

在您的情况下,这意味着拥有扩展接口Foo的具体类,但没有针对verifyConsistency的任何实现.

因此二进制不兼容.

I am confused regarding backward compatibility when adding a method with default implementation to a trait. Like:

Previous Version

trait Foo

New Version

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

The Migration Manager reports this addition as a binary incompatibility. Is that correct?

解决方案

Well yes it is correct.

When you define trait Foo, it will under the hood create both a (JVM) interface Foo and a (JVM) class Foo$class with all the method implementations defined as static methods. The corresponding java code would look like something like this (for your new defintion of Foo):

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

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

When you mix Foo into a concrete class Bar, what happens at the JVM level is that Bar extends the interface Foo, and it implements method verifyConsistency by simply forwarding the call to Foo$class:

class Bar implements Foo {
  Option<String> verifyConsistency() {
    return Foo$class.verifyConsistency(this); // simple forwarding
  }
}

The reason why it is done this way is that the JVM object model does not support multiple inheritance. The traits implementations cannot be simply put in classes that you would extend from, because you can only ever extend a single class on the JVM.

The take away of this situation is that everytime a concrete class mixes a trait, the class defines "stub" methods for each member of the trait (those methods simply forward to the actual implementation, which is a static method).

One consequence is that if you add a new method to a trait, even if you define an implementation it is not enough: concrete classes that mix the trait need to be recompiled (so that a stub for the new method is added to the class). If you don't recompile those classes, your program will fail to run, as you would now have a class that is supposedly concrete (non abstract) AND extend the corresponding interface but actually miss the implementation for the new method.

In your case this means having concrete classes that extend interface Foo but do not have any implementation for verifyConsistency.

Hence the binary incompatibility.

这篇关于在实现中添加特征方法会破坏向后兼容性吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆