scala编译器的一个bug

前天聚石找我问一个编译时期的问题,发现了一个编译器令人奇怪的行为,这个行为与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

嗯,这已经超出了我的了解范围。

Leave a Reply

Your email address will not be published. Required fields are marked *