Consider this:
class Foo { def foo = "foo" }
trait Bar { self: Foo =>
override def foo = "bar"
}
I was pleasantly surprised to find out that this is possible, and works as expected:
new Foo with Bar foo
returns "bar". The question is whether it is possible for Bar.foo
to invoke Foo.foo
, like one would often do in the "ordinary" inheritance case. override def foo = super.foo + "bar"
does not work (says "foo is not a member of AnyRef), and neither does override def foo = self.foo + "bar"
(it ends up just calling itself, and results in infinite recursion).
I tried a few other combinations (like self.Foo.foo
, Foo.this.foo
etc.), but without any luck.
Is this just impossible?
No. It is impossible to call overridden method from a self type.
Firstly the trait Bar
is not a successor of class Foo
so it is not possible using super.foo
.
And secondly it is also not possible using self.foo
since self
is actually of type Bar with Foo
. It can be shown by printing the program after typer
:
$ scalac -Xprint:typer test.scala
[[syntax trees at end of typer]] // test.scala
package <empty> {
class Foo extends scala.AnyRef {
def <init>(): Foo = {
Foo.super.<init>();
()
};
def foo: String = "foo"
};
abstract trait Bar extends scala.AnyRef { self: Bar with Foo =>
def /*Bar*/$init$(): Unit = {
()
};
override def foo: String = "bar"
};
class FooBar extends Foo with Bar {
def <init>(): FooBar = {
FooBar.super.<init>();
()
}
};
object TestApp extends scala.AnyRef {
def <init>(): TestApp.type = {
TestApp.super.<init>();
()
};
def main(args: Array[String]): Unit = {
val a: FooBar = new FooBar();
scala.this.Predef.println(a.foo)
}
}
}
So with self.foo
you are trying to access the method foo
of the trait Bar
. Such behavior matches the Scala Specification (PDF):
The sequence of template statements may be prefixed with a formal parameter definition and an arrow, e.g. x =>, or x: T =>. If a formal parameter is given, it can be used as an alias for the reference this throughout the body of the template. If the formal parameter comes with a type T, this definition affects the self type S of the underlying class or object as follows: Let C be the type of the class or trait or object defining the template. If a type T is given for the formal self parameter, S is the greatest lower bound of T and C. If no type T is given, S is just C. Inside the template, the type of this is assumed to be S.
It is possible to access the method using reflection but I think that it is not what you are looking for.
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