Is it possible to call an overridden method from self type? - scala

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.

I am not aware of any particular syntax to disentangle the base class and the mixed-in trait.
There is, however, an easy solution to achieve the result manually by distinguishing the overridden method from the default implementation in the base class:
class Foo { def foo = defaultFoo; def defaultFoo = "foo" }
trait Bar { self: Foo => override def foo = self.defaultFoo + "bar" }
As expected
new Foo with Bar foo == "foobar"
new Foo foo == "foo"

You make your trait extend Foo instead of using the self type:
class Foo {def foo = "foo"}
trait Bar extends Foo {
override def foo = super.foo + "bar"
}
new Foo with Bar foo // barfoo
See also this answer.

Related

how to use play format serialization/deserialization macro for nested case objects

So I have a sealed trait like such:
sealed trait Foo {
override def toString: String = {
...
}
}
and a companion object like:
object Foo {
case object Bar extends Foo {}
case object Bat extends Foo {}
case object Bah extends Foo {}
def parse(s: String): Foo = {
...
}
implicit val format: Format[Foo] = Json.format[Foo]
def apply(f: String): Foo = parse(f)
def unapply(f: Foo): String = f.toString
}
I would have expected the macro to work since it meets all of the requirements stated here:
https://www.playframework.com/documentation/2.8.x/ScalaJsonAutomated#Requirements
However, I get a compile time error that states that there are no subclasses for Foo (even though there are Bar, Bat and Bah) .
If I move Bar, Bat and Bah outside of Foo (to the base package level), the complaint goes away.
Just wondering if this is an oversight in the macro (where is cannot find nested subclasses), or if I am doing something incorrect here?

Overriding an abstract method while using the method

I want to do something like this
abstract class Foo {
def bar:String
def modifiedFoo:Foo = new Foo(){
override def bar = super.bar+"\n"
}
}
but this is not legitimate ("method bar in class Foo is accessed from super,
it may not be abstract unless it is overriden by a member declared abstract
and override" which inturn is only legal for Traits).
I could move the method modifiedFoo
into the companion object with signature modifiedFoo(foo:Foo) but this is
less elegant.
How do you handle this problem?
I think you can just use self in the following way:
abstract class Foo {
self: Foo =>
def bar: String
def modifiedFoo: Foo = new Foo() {
override def bar = self.bar + "\n"
}
}

In Scala is there a way to specify that the return type should match the type of the method caller?

For example, I have a class called Foo
abstract class Foo {
def f(): ??? = { ... }
}
class Bar extends Foo {
...
}
class Baz extends Foo {
...
}
What I'd like is a way for f to return a Bar when it's called by Bar, and a Baz when it's called by Baz. Both Bar and Baz would have the same constructor, so the code in f would be the same both times, except for whether I have to say new Bar(...) or new Baz(...). Is there any way to say new TypeOfWhateverClassIsCallingMe(...)?
Sounds like you want F-Bounded types. You'll still have to implement it for all subclasses however, as the parent class has no knowledge of the child constructors (A "Mammal" does not know how to make a "Cat").
abstract class Foo[T <: Foo[T]] {
def createMe(): T
}
class Bar extends Foo[Bar] {
override def createMe() = new Bar
}
class Baz extends Foo[Baz] {
override def createMe() = new Baz
}
This basically gives you compile-time safety, all children of Foo need to implement a method that creates something of its own class.
In-depth discussion here.
Assuming you want the type of the concrete subclass the method is called on (I would not call this the "type of the method caller", rather the "type of the invokee"), you can do
def f(): this.type = ???

Avoid type cast with type member and sub-typing

I am having trouble with path dependent types and pattern matching:
trait View[A]
trait Foo {
type Bar
def defaultBar: Bar
}
trait Baz extends Foo {
def view(init: Bar): View[Bar]
}
trait Test {
val foo: Foo
def bar: foo.Bar = foo.defaultBar
def test(): Option[View[foo.Bar]] =
foo match {
case b: Baz => Some(b.view(bar))
case _ => None
}
}
This fails because scalac doesn't identify foo with b. As a result, it only works with two casts:
case b: Baz => Some(b.view(bar.asInstanceOf[b.Bar]).asInstanceOf[View[foo.Bar]])
Surely there must be a clean way to avoid the casts?
Its not possible to do without using projections and restricting the type as defaultBar we can override it to unrelated data types
for eg
trait MyFoo extends Foo {
override def defaultBar: Int
}

structural type with upper bound?

consider this design of a library I need to use and cannot fix:
trait Foo
class IgnoreMe extends Foo
class A extends Foo { def bar: A = ...}
class B extends Foo { def bar: B = ...}
In my code:
object Stuff {
type Barred = { def bar: Foo }
def doStuff(b:Barred) = b.bar
}
Thats all well and good except that the Stuff.doStuff will accept anything conforming to the type Barred, not just the subtypes of Foo I want.
I would like to define Barred such that it is both a subtype of Foo and has a bar method, and I cannot :( Help appreciated.
Simply
type Barred = Foo {def bar: Foo }
Have you tried:
def doStuff(b: Barred with Foo) = b.bar
Another way to achieve what you want without reflection at runtime (but with more work if a new subtype of Foo with a bar method is added to the library), would be to define a trait Barred[T] typeclass, implicit instances of Barred[A] and Barred[B], and use a type bound:
def doStuff[T : Barred](b: T)
Given your examples, this may be more suitable:
type Barred[T <: Barred[T]] = Foo { def bar: T }
This allows you to define, e.g.
def double_bar[T <: Barred[T]](x: T) = x.bar.bar
which #didierd's answer doesn't.