Scala: Blending Objects with Private Fields

This is not a question, it is rather my excitement that this is possible at all! I wrote this small example to prove the opposite - I was expecting either a compiler error or one of the values ​​(111 or 222, I was not 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 is v not canceled? Of course, this only works as long as v are private, but still.

+6
scala multiple-inheritance traits
source share
3 answers

Since traits are not just interfaces, they need some kind of storage for their internal state. But they must be compatible with the 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 in 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 for implementing 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 they will be separate by default, because these built-in methods have a tag name in the method name. And when we look at 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 simply fills in what is needed for each particular attribute. Now the question is: how do features ever rewrite each other? They seem completely separate! This is the work of the compiler. If something is private , it is hidden and cannot be redefined, so it does not matter that another (private) thing has the same name. But if it is not, the compiler complains about 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 doesn’t use secret misrepresented names with an embedded feature name. (Note that getValueT1 not distorted in this example.)

+15
source share

This is not a trait characteristic. 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 is true in Java. Private members are private. They belong exclusively to where they were defined, and have no effect on the outside. If there was a conflict through inheritance, they would be visible, which could exceed the goal of being closed.

+6
source share

Private members and methods cannot be overridden. It should prevent changes in the class of behavior introduced by descendants. The concept here is very similar to C ++: each ancestor has its own copy of the members until special methods (for example, virtual inheritance) are involved.

+1
source share

All Articles