It's not much of a question, it's rather my excitement that it's possible at all! I wrote this little example just to prove the opposite - I expected either a compiler error or one of the values (111 or 222, I wasn't sure).
scala> trait T1 { private val v = 111; def getValueT1 = v }
scala> trait T2 { private val v = 222; def getValueT2 = v }
scala> class T12 extends T1 with T2
scala> val t = new T12
scala> t.getValueT1
res9: Int = 111
scala> t.getValueT2
res10: Int = 222
Why doesn't the v
get overridden? Off course this works only as long as v
s are private, but still.
Since traits are not just interfaces, they need some way to store their internal state. But they have to be compatible with interfaces--so what do they do? They create accessors for what looks like a field (as you can see (among other things) with javap -l -s -c -private
on the class files):
public interface T1 extends java.lang.Object {
public abstract int T1$$v();
Signature: ()I
public abstract int getValueT1();
Signature: ()I
}
and then create an implementation class that has static methods to implement the functionality:
public abstract class T1$class extends java.lang.Object {
public static int getValueT1(T1);
Signature: (LT1;)I
Code:
0: aload_0
1: invokeinterface #12, 1; //InterfaceMethod T1.T1$$v:()I
6: ireturn
}
Now, hopefully, it's clear that these would be separate by default since these internally-generated methods have the name of the trait in the name of the method. And when we look in the implementation in T12
:
public class T12 extends java.lang.Object implements T1,T2,scala.ScalaObject {
private final int Overridden$T1$$v;
Signature: I
public final int T1$$v();
Signature: ()I
Code:
0: aload_0
1: getfield #22; //Field T1$$v:I
4: ireturn
public int getValueT1();
Signature: ()I
Code:
0: aload_0
1: invokestatic #29; //Method T1$class.getValueT1:(LT1;)I
4: ireturn
}
you can see that it just fills in what's needed for each specific trait. Now the question is--how do traits ever overwrite each other? They seem to be completely separate! That's the compiler's job. If something is private
it's hidden and can't be overridden, so it doesn't matter that another (private) thing has the same name. But if it's not, the compiler complains of a collision:
error: overriding value v in trait T1 of type Int;
value v in trait T2 of type Int needs `override' modifier
class T12 extends T1 with T2
because now it's not using the secret mangled names with the trait name embedded. (Observe that getValueT1
is not mangled in this example.)
This is not a property particular to traits. For instance:
scala> class X {
| private val v = 111
| def getX = v
| }
defined class X
scala> class Y extends X {
| private val v = 222
| def getY = v
| }
defined class Y
scala> new Y
res0: Y = Y@5ca801b0
scala> res0.getX
res1: Int = 111
scala> res0.getY
res2: Int = 222
And the same holds true in Java. Private members are private. They belong solely to where they were defined, and have no effect outside. If there was a conflict through inheritance, they would be visible, which would defeat the purpose of being private.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With