前天聚石找我问一个编译时期的问题,发现了一个编译器令人奇怪的行为,这个行为与java不一致,很怀疑是编译器的bug,但又担心是自己没有注意到某些细节或者scala里有意这样。把当时的问题场景简化后,大致是一个private
修饰的成员在子类中存在同名的抽象成员,编译器会报错。
对比java:
% cat /tmp/A.java
public class A{
public static class X1 {
private void foo() {}
}
abstract public static class X2 extends X1 {
abstract public void foo(); // it's ok
}
}
子类X2继承自X1,在X1中定义的私有方法foo对X2是不可见的,所以X2中定义一个抽象的foo也毫不影响。
但在scala(2.10.2)里,这样的情况却编译报错:
% cat A.scala
class A {
private def v = 1
}
abstract class B extends A {
def v: Int // make it abstract , compile error! why ?
}
报错内容是认为这里override了一个更弱访问级别的方法:
% scalac A.scala
A.scala:5: error: overriding method v in class B of type => Int;
method v in class A of type => Int has weaker access privileges; it should not be private;
(Note that method v in class B of type => Int is abstract,
and is therefore overridden by concrete method v in class A of type => Int)
abstract class B extends A {
^
one error found
实在难以理解,让人怀疑父类中的private
成员在子类中的抽象成员是可感知的。在scala-user邮件列表里询问了一下,得到编译器的维护者Jason Zaugg的确认,说这是编译器的一个bug,他已经修复。https://github.com/retronym/scala/commit/c1da44c0421b5924d3276a4b30dff8ac7ef3e377
从他的记录里看到有说:Refinement types are still able to inherit private members from
all direct parents
嗯,这已经超出了我的了解范围。