In your example the parent
identifier is simply another name for the this
object, a pointer to whatever this object is at runtime.
In Scala and Java (on the JVM in general), the rules of invoking a method on an object are that the overridden method of the runtime type of the object is called.
To do this, the JVM relies on virtual function tables that associate the object type and the name of a method with its specific implementation.
This is unlike C++, where calling a method on an object value (not pointer or reference) will resolve the method from the compile-time type of that object.
For example, in Scala you could do:
val compileTimeVar: myClass = new myClass { override def method(a: Int) = "substring" }
From the standpoint of the Scala compiler, compileTimeVar
has a type myClass
.
However, the runtime type is the unnamed type internally represented as something like xxx$anon$1
, and this unnamed type overrides method
.
Calling:
compileTimeVar.method
always calls the overridden method if it exists in that runtime type - it will return "substring"
.
The so-called self
pointer is no different from assigning the object to a variable with lost runtime type information - your code is equivalent to this:
class myClass {
def parent: myClass = this
def method(a: Int) = "test"
def run = println(parent.method(1))
}
If you really want run
to call the method
defined in myClass
and not whatever is overridden, do this:
class myClass {
private def privateMethod(a: Int) = "test"
def method(a: Int) = privateMethod(a)
def run = println(this.privateMethod(1))
}