Given this code: (no matter whether it doesn't make much sense)
object Test {
def main(args: Array[String]) {
(new FooImpl2()).foo()
}
trait Foo {
def foo()
}
trait M extends Foo {
abstract override def foo() {println("M"); super.foo()}
}
abstract class FooImpl1 extends Foo {
}
class FooImpl2 extends FooImpl1 with M{
override def foo() {println("Impl2")}
}
}
At compile time, this error occurs:
error: overriding method foo in trait M of type ()Unit;
method foo needs `abstract override' modifiers
override def foo() {println("Impl2")}
So at this place:
class FooImpl2 extends FooImpl1 with M{
override def foo() {println("Impl2")}
}
Why doesn't override apply on FooImpl1 (in order to provide a concrete implementation for abstract trait method)? It seems like it matches the trait method's instead...and obviously there's a huge conflict with the pattern "abstract override"
M needs to be mixed-in after the concrete def (in linearization order).
Related
Assuming I have a simple abstract base class like so:
abstract class MyAbstractBaseClass {
def hello : Unit
}
and then I write a "stacking" trait like so:
trait MyTrait extends MyAbstractBaseClass {
abstract override def hello : Unit =
{
super.hello
println("How are you?");
}
}
then why won't Scala let me define a subclass as follows:
class MyClass extends MyAbstractBaseClass with MyTrait {
override def hello : Unit = println("Hello!")
}
error: overriding method hello in trait MyTrait of type => Unit;
method hello needs `abstract override' modifiers
If I try their suggestion of using 'abstract override':
class MyClass extends MyAbstractBaseClass with MyTrait {
abstract override def hello : Unit = println("Hello!")
}
error: `abstract override' modifier only allowed for members of traits
Can anyone help me understand this?
P.S. I know that the below does work:
class MyClass extends MyAbstractBaseClass {
override def hello : Unit = println("Hello!")
}
val x = new MyClass with MyTrait
x.hello
Hello!
How are you?
but am trying to understand why the former does not.
In summary: why can't I provide an implementation of the abstract base class - while also taking advantage of the trait's functionality?
The trick is that you can't have an "abstract" method in the flow of the linearization, that is called from a super call.
Try this, you will see it compiles:
abstract class MyAbstractBaseClass {
def hello : Unit
}
class SubClass extends MyAbstractBaseClass {
def hello {
println("toto")
}
}
trait MyTrait extends MyAbstractBaseClass {
abstract override def hello : Unit =
{
super.hello
println("How are you?")
}
}
class MyClass extends SubClass with MyTrait { //note the CONCRETE SubClass here
override def hello : Unit = println("Hello!")
}
new MyClass().hello
You got the error, because the compiler starts with MyTrait (at the top of the stack, so the first to be called) and that MyTrait calls through super an abstract method... (of MyAbstractBaseClass) => it crashes since your super call can't target immediately a concrete method.
In my code snippet, you will notice that MyTrait is "at the top" (during linearization) of a concrete Subclass class, that makes the trick.
I have this code:
trait base{
def msg: Unit= {
println{"base"}
}
}
trait foo extends base {
abstract override def msg: Unit ={
super.msg
println("foo")
}
}
class base2{
def msg:Unit = {
println{"base 2"}
}
}
class test extends base2 with foo{
override def msg: Unit ={
super.msg
println("done")
}
}
If I call (new test).msg, this prints out things like: base, foo, done
However, if I change the base trait to:
trait base{
def msg: Unit
}
it prints out things like: base 2, foo, done
I understand the order of with is from right to left (last one comes first) but how about extends? How come sometimes it prints base2, but sometimes base?
When you omit the implementation, base is a template of a trait and has different evaluation rules. See the Scala specification
Scala has something called type linearization. It defines initialization order. Read here http://eed3si9n.com/constraining-class-linearization-in-Scala
In Scala, suppose classes A and B that has a common method, but not inherited any common interface:
class A {
def foo() {
println("A.foo")
}
}
class B {
def foo() {
println("B.foo")
}
}
What I want to do is to define a trait that extends any classes that has foo() method. I tried this:
type Fooable = {
def foo()
}
trait Q extends Fooable {
override def foo() {
println("before super.foo")
super.foo()
println("after super.foo")
}
}
(new A with Q).foo()
(new B with Q).foo()
However, Scala compiler rejects this code with an error:
error: class type required but AnyRef{def foo(): Unit} found trait Q extends Fooable {
The best solution is to make an interface that contains common methods and modify classes A and B to inherit the interface. Unfortunately, we cannot modify these classes. This is common in Java libraries such as:
java.sql.Connection.close() and java.io.Closeable.close()
android.app.Activity.onDestroy() and android.app.Service.onDestroy()
You can't do it. Here's the fundamental problem with it, quoting you:
define a trait that extends any classes
Scala demands that the class hierarchy to be a tree, which means any element in it will have one, and just one, parent class. It can have many parent traits, and many ancestor classes, but what you ask for is strictly against the hierarchy demanded by Scala.
Now, you are mixing two concepts here: nominal typing, where the type of something is defined by its class or trait, and structural typing, where the type of something is defined by what methods it implements.
Nominal typing and structural typing are, however, rather incompatible. In fact, before Scala it was generally agreed on that the two could not cooexist and, in fact, Scala has a very limited version of structural typing. You could do something like this:
scala> def f(m: { def foo(): Unit }) = {
| println("before foo")
| m.foo()
| println("after foo")
| }
f: (m: AnyRef{def foo(): Unit})Unit
scala> f(new A)
before foo
A.foo
after foo
Or you could combine structural types with self types, like this:
scala> trait Q { self: { def foo(): Unit } =>
| def bar() {
| println("before foo")
| foo()
| println("after foo")
| }
| }
defined trait Q
scala> (new A with Q).bar()
before foo
A.foo
after foo
scala> (new B with Q).bar()
before foo
B.foo
after foo
But you cannot inherit from a structural type, as inheritance is a characteristic exclusive of nominal types. And, because you cannot inherit a structural type, you cannot override it, or call it on an ancestor, which means trait Q cannot declare an override on foo().
Self answer:
After I know that there are no exact solution to my question, I made an alternative way to overcome this.
It is not a perfect solution, but can be a reasonable workaround for some situation (in my case :-).
trait Fooable {
def beforeFoo() {}
def afterFoo() {}
}
trait Alice extends A with Fooable {
override def foo() {
beforeFoo()
super.foo()
afterFoo()
}
}
trait Bob extends B with Fooable {
override def foo() {
beforeFoo()
super.foo()
afterFoo()
}
}
trait Quest extends Fooable {
override def beforeFoo() {
println("before super.foo")
super.beforeFoo()
}
override def afterFoo() {
println("after super.foo")
super.afterFoo()
}
}
(new Alice with Quest).foo()
(new Bob with Quest).foo()
Yes, we should use Alice and Bob, instead of A and B. However, it can be compromised in my case.
I'm trying define a trait C which extends some traits A,B,... All traits,C and A,B,... implement a common trait T. Trait C is supposed to implement T by calling the implementations of T in A,B,..:
trait T{
def f()
}
trait A extends T{
def f(){
print("A")
}
}
trait B extends T{
def f(){
print("B")
}
}
The desired behavior of trait C is as follows:
val x=new A with B with C[A,B]{}
x.f()
// should produce output
A
B
Here my attempt to define trait C, which gave compilation errors:
trait C[A<:T,B<:T] extends T{
self:A with B =>
override def f(){
// error: A does not name a parent class of trait C
super[A].f()
// error: B does not name a parent class of trait C
super[B].f()
}
}
I need to call within C methods A.f() and B.f().
Is there any solution to this?
If you want to provide an implementation inside of a trait but also ensure that subclasses implement the definition, it is possible to tell this the compiler with the abstract override combination:
trait T {
def f()
}
trait A extends T {
abstract override def f() {
super.f()
print("A")
}
}
trait B extends T {
abstract override def f() {
super.f()
print("B")
}
}
trait C extends T {
override def f() {
// do your work here ...
}
}
val x = new C with A with B
x.f()
To call the next implementation in the mixin-hierarchy you must add a super.f() call inside of the abstract override method call. Because such a super call requires an existing implementation the first thing you need to create is an instance of C that mixins A and B. If you mixin C in A or B the compiler will complain because the mixin-hierarchy is executed from left to right, thus the implementation of C can not be seen.
I have a base abstract class (trait). It has an abstract method foo(). It is extended and implemented by several derived classes. I want to create a trait that can be mixed into the derived classes so that it implements foo() and then calls the derived class's foo().
Something like:
trait Foo {
def foo()
}
trait M extends Foo {
override def foo() {
println("M")
super.foo()
}
}
class FooImpl1 extends Foo {
override def foo() {
println("Impl")
}
}
class FooImpl2 extends FooImpl1 with M
I tried self types and structural types, but I can't get it to work.
You were very close. Add the abstract modifier to M.foo, and you have the 'Stackable Trait' pattern: http://www.artima.com/scalazine/articles/stackable_trait_pattern.html
trait Foo {
def foo()
}
trait M extends Foo {
abstract override def foo() {println("M"); super.foo()}
}
class FooImpl1 extends Foo {
override def foo() {println("Impl")}
}
class FooImpl2 extends FooImpl1 with M