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"
}
}
Related
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 = ???
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.
Is it possible to add method definition from macro call? Here is an example:
object Macros { def someMacro = ...}
trait Foo { def foo:Int }
class Bar extends Foo { someMacro() }
//calls to (new Bar).foo is possible and return value defined in someMacro
This is indeed possible with Scala macro annotations. One thing that macro annotations enable is adding members to class definitions. Since macros are compiled before other steps of type checking, you can use this functionality to satisfy a trait's constraints.
For example, the following macro annotation #foo adds a foo method to its annotated classes. Here, the method takes no arguments and returns an Int:
object Macros {
def fooImpl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
val fooMethod = DefDef(NoMods, newTermName("foo"), List(), List(List()), TypeTree(), Literal(Constant(5)))
c.Expr[Any](annottees.map(_.tree).toList match {
case List(ClassDef(mods, name, tdefs, Template(parents, self, body))) =>
ClassDef(mods, name, tdefs, Template(parents, self, body :+ fooMethod))
})
}
}
class foo extends StaticAnnotation {
def macroTransform(annottees: Any*) = macro Macros.fooImpl
}
Then you can use the #foo annotation to satisfy some Trait definition:
trait Foo { def foo: Int}
#foo
class Bar extends Foo //compiles
(new Bar).foo //5
You can read more about Macro annotations here.
You cannot override an abstract method with a macro. However, you can override a concrete method, even if that concrete method itself overrides an abstract method. So, if you introduce an intermediary trait with a default implementation, you can have the desired outcome. For example:
object Macros {
def someMacro(c: Context): c.Expr[Int] = {
import c.universe._
c.Expr[Int](Literal(Constant(5)))
}
}
trait Foo {
def foo: Int
}
trait FooWithDefault extends Foo {
override def foo: Int = 0
}
class Bar extends FooWithDefault {
override def foo: Int = macro Macros.someMacro
}
(new Bar).foo //5
This does lead to some unexpected behavior, so be careful:
val b: Foo = new Bar
b.foo //java.lang.AbstractMethodError
val b: FooWithDefault = new Bar
b.foo //java.lang.AbstractMethodError
This is explained in futher detail in the issue SI-7657, where it is explained:
Currently we allow macros to override non-abstract methods (in order
to provide performance enhancements such as foreach for
collections), and we also disallow macros to override abstract methods
(otherwise downcasting might lead to AbstractMethodErrors).
This patch fixes an oversight in the disallowing rule that prohibited
macros from overriding a concrete method if that concrete method
itself overrides an abstract method. RefCheck entertains all
overriding pairs, not only the immediate ones, so the disallowing rule
was triggered.
Now macros can override abstract methods if and only if
either the base type or the self type contain a matching non-abstract
method.
Suppose I have the following trait:
trait Foo[T] {
def returnMyself: T
}
Is there any way that would tell scala that any class that extends Foo does so with itself as the generic parameter?
Basically, what I want to achieve is being able to write
class Bar extends Foo {
override def returnMyself: Bar = this
}
without having to explicitly write
class Bar extends Foo[Bar]
I hope I've made myself clear
You should be able to do it using self types:
trait Foo { self =>
def returnMyself: self.type
}
class Bar extends Foo {
override def returnMyself = this
}
I have a class which source I cannot modify:
class Foo {
def bar() = println("bar")
}
And a trait I'd like to mix into it at runtime
trait Zee { this: Foo =>
abstract override def bar() = {
println("before bar")
super.bar()
}
}
This is throwing that bar is not a member of Object with ScalaObject
What am I doing wrong? Is it possible to achieve this without modifying Foo source?
The ultimate client code needs to look like this:
val foo = new Foo with Zee
foo.bar() // should print 'before bar' and then 'bar'
Your Zee trait has no super traits (except implicit inheritance from ScalaObject) thus super does not contain definition for bar and there is nothing to override or call (super.bar).
why don't you write this without self-reference?
class Foo {
def bar() = println("bar")
}
trait Zee extends Foo {
abstract override def bar() = {
println("before bar")
super.bar()
}
}
You can just extends the class Foo in your trait:
trait Zee extends Foo
And your code will work.
your trait needs to extend foo
trait Zee extends Foo {
abstract override def bar() = {
println("before bar")
super.bar()
}
}