Consider the perversion taking place in the following tale.
trait A {
private[this] val bippy = 5
def dingus = bippy * bippy
}
class B extends A
trait A has a single public method and a private[this] immutable field
which does not escape and which the language prohibits anything outside
of A from accessing. Nevertheless, we generate not only a public getter,
but a public setter, thus making the name of the private[this] field a
central piece of A's binary compatibility story. May as well be a public
var for all the insulation A has from its implementation.
Now class B comes along and extends A. It receives the private field and
the public getter and setter. To populate the field, B's constructor
calls into A$class, which turns around and calls the public setter on
B, the need for which is now apparent. To implement the one interface
method which A intentionally exposed, we again send B packing to A$class
to perform the actual operation. Having left the warm confines of B
where we could have accessed the field directly, we must resort to using
the public getter which also is trying to justify its existence.
I understand why this machinery is in place and that (at least given the
current encoding) it's necessary to support access which is scala-legal
but jvm-illegal. But I can't see why it can't be done more selectively,
with the especially interesting case being the private field which never
hurt a fly. Separate compilation can hardly be banking on the presence
of private fields which can't be separately accessed.
Optimally:
interface A {
def dingus(): Int
}
class B extends A {
private int bippy = 5
def dingus = bippy * bippy
}
In actual fact:
interface A {
def dingus(): Int
def A$$bippy(): Int
def A$_setter_$A$$bippy_$eq(x: Int): Unit
}
class B extends A {
private int A$$bippy = 5
def A$$bippy(): Int = A$$bippy
def A$_setter_$A$$bippy_$eq(x: Int): Unit = A$$bippy = x
def dingus(): Int = A$class.dingus(this)
}
class A$class {
def dingus(x: A) = x.A$$bippy() * x.A$$bippy()
}
Bytecode:
// interface A
public abstract int A$$bippy();
public abstract void A$_setter_$A$$bippy_$eq(int);
public abstract int dingus();
// class B
private final int A$$bippy;
public int A$$bippy();
0: aload_0
1: getfield #11; //Field A$$bippy:I
4: ireturn
public void A$_setter_$A$$bippy_$eq(int);
0: aload_0
1: iload_1
2: putfield #11; //Field A$$bippy:I
5: return
public int dingus();
0: aload_0
1: invokestatic #19; //Method A$class.dingus:(LA;)I
4: ireturn
// Implementation class A$class:
public static int dingus(A);
0: aload_0
1: invokeinterface #12, 1; //InterfaceMethod A.A$$bippy:()I
6: aload_0
7: invokeinterface #12, 1; //InterfaceMethod A.A$$bippy:()I
12: imul
13: ireturn
public static void $init$(A);
0: aload_0
1: iconst_5
2: invokeinterface #26, 2; //InterfaceMethod A.A$_setter_$A$$bippy_$eq:(I)V
7: return