Implementing an abstract method with a trait, inconsistent compiler behaviour? - scala

I have a base class that comes from a Java library, whose code I cannot modify. This class (A) has an empty method (b) which should have been declared as abstract instead:
class A {
def b { }
}
I extend this class in Scala and override the method to make it abstract:
abstract class AA extends A {
override def b
}
Now I implement this method in a trait:
trait B {
def b { println("B") }
}
If I extend AA with trait B, I get a error: overriding method b in class A of type => Unit;
method b in trait B of type => Unit needs `override' modifier:
class C extends AA with B {}
Instead, if the code had been like this, everything is compiled without errors, which seems a bit contradictory to me:
abstract class AA {
def b
}
trait B {
def b { println("B") }
}
class C extends AA with B {}
I'm running Scala 2.8.0RC3, and completely new to the language (3 days). Another weird and related behaviour is that the override label is not necessary when making b abstract:
abstract class AA extends A {
def b
}

To try to see what's going on, I tried this:
scala> class A{
| def b{ }
| }
defined class A
scala> abstract class AA extends A{
| override def b
| }
defined class AA
scala> class AAA extends AA{
| def b = println("AAA")
| }
<console>:8: error: overriding method b in class A of type => Unit;
method b needs `override' modifier
def b = println("AAA")
^
Apparently, the source of the problem is that abstract classes can't "free up" methods in their superclass from the need for the abstract class's subclasses to include the 'override' modifier.

Not sure if this is the right solution, but if your trait B extends A (and override b), then everything compile fine:
First let's define A and AA like you present them in your question:
C:\Users\VonC>scala
Welcome to Scala version 2.8.0.RC5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_18).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class A {
| def b { println("A b") }
| }
defined class A
scala> new A
res5: A = A#153bedc4
scala> res5.b
A b
scala> abstract class AA extends A {
| override def b
| }
defined class AA
What you did:
scala> trait B {
| override def b { println("B b") }
| }
<console>:6: error: method b overrides nothing
override def b { println("B b") }
^
What I tried with trait B (in order to be able to add the 'override'):
scala> trait B extends A {
| override def b { println("B b") }
| }
defined trait B
So now:
scala> class C extends AA with B {}
defined class C
scala> new C
res7: C = C#1497b7b1
scala> res7.b
B b
The right b overriden method is called with C.b
As for your apparent "inconsistency", see Scala for Java Refugees Part 5: Traits and Types:
To start with, there’s that ever-annoying override keyword. I mentioned back in the article on basic OOP that any method which overrides a method in a superclass must be declared with the override modifier. At the time, I likened it to the language mandating the use of the #Override annotation, with its primary purpose being to enforce the good practice.
The real key to the power of traits is the way in which the compiler treats them in an inheriting class.
Traits are actually mixins, not true parent classes.
Any non-abstract trait members are actually included in the inheriting class, as in physically part of the class. Well, not physically, but you get the picture.
It’s as if the compiler performs a cut-and-paste with the non-abstract members and inserts them into the inheriting class. This means that there’s no ambiguity in the inheritance path, meaning no diamond problem.
So no need for override keyword in your second example.

The problem is very subtle. As a rule of thumb, your class AA, which extends A, should be mixed with traits that also extend A.
You did:
class A {
def b { }
}
abstract class AA extends A {
override def b
}
trait B {
def b { println("B") }
}
Hence when you mix AA and B method b is DEFINED twice. Once by A (Not overrided because the definition in B replaced the override in AA) and the second by B, the compiler can't chose one over the other because there is no hierarchy between the two (equaly named but unrelated) methods. If you want, think about it like this: The compiler "mixes" the bodies of AA and B; if he choses the method from AA it will be abstract, if he choses the method from B (What should happend), since it's not an override, your stuck with two methods b.
To solve this, you want to make sure that both methods override the same method, in which case the the compiler will understand you are talking about the SAME method and will give priority to the last trait mixed.
Now, to override the method b in B, that class has also to inherit from A. So the canonical way to do this would be:
class A {
def b { }
}
abstract class AA extends A {
override def b
}
trait B extends A{
def b { println("B") }
}
class C extends AA with B {}
Which compiles just fine.
Now, when you do:
abstract class AA {
def b
}
trait B {
def b { println("B") }
}
class C extends AA with B {}
it's clear that both methods are the same so the compiler knows he has to use the method from the trait.
Other solutions include:
Make B override AA
Make b in A abstract (But you didn't want that)
Again, the problem is very subtle but I hope I made it a little clearer. To get a better understandig read Scala's Stackable Trait Pattern.

Related

Stackable Traits Pattern : method's implementation "needs `abstract override' modifiers"

Recently, I've find out about the stackable trait pattern and followed the example described here. Everything works, but there is a case I cannot understand :
trait A {
def test : String
}
trait B extends A {
// 'abstract override' modifier required as
// the test() method is not yet implemented
abstract override def test = {
s"B${super.test}"
}
}
class C extends A with B {
// test method concrete implementation
override def test = { "C" }
}
<console>:10: error: overriding method test in trait B of type => String;
method test needs `abstract override' modifiers
class C extends A with B { override def test = { "C" } }
I cannot understand why this does not compile, and why the C::test method needs the mentioned modifier.
I've noticed that there is two modifications I can do in order to make this compile, either by composing the C class at runtime :
class C extends A { override def test = { "C" } }
new C with B // works as expected
or by adding an extra class (which is kind of the same but at compile time):
class C extends A {
override def test = { "C" }
}
class D extends C with B
new D().test
res5: String = BC
Why do I need an extra class (which BTW plays the role of the Basic class) ?
The reason for this behaviour is Scala's class linearization which is used to resolve ambiguities and the semantics of abstract override. But first things first.
Class Linearization
Whenever you have an instance a of type A and you call a method on it a.foobar(), the compiler has to figure out where to find the definition of foobar. Since A can extend any other class and a set of traits, there might be multiple definitions for the function foobar. In order to resolve these ambiguities, Scala will linearize your class A with all its superclasses and traits. The linearization will produce an order in which the different types are checked for a definition of foobar. The first match will be the function which is executed.
The Scala specification defines the linearization as following
Definition 5.1.2 Let C be a class with template C1 with ... with Cn { stats }.
The linearization of C, L(C) is defined as follows:
L(C) = C , L(Cn)+: ... +: L(C1)
Here +: denotes concatenation where elements of the right operand replace identical elements of the left operand.
Since all theory is grey, let's take a look at an example:
trait T1 {
def foobar() = 1
}
trait T2 {
def foobar() = 2
}
class B extends T2 {
override def foobar() = 42
}
class A extends B with T1 with T2 {
override def foobar() = super.foobar()
}
First of all, we have to override the foobar method in the class A, because we have multiple competing definitions for it. However, now is the question, which method definition is called by super.foobar. In order to find this out, we have to calculate the linearization of A.
L(A) = A, L(T2) +: L(T1) +: L(B)
L(B) = B, L(T2)
L(T2) = T2
L(T1) = T1
L(A) = A, T2 +: (T1, B, T2)
L(A) = A, T1, B, T2
Thus, super.foobar will call the definition in T1 which returns 1.
Abstract override
The abstract override modifier for a method basically says that there has to be a class/trait I implementing this method which appears after the trait with the abstract override modifier in the class linearization of your instantiated class. That is necessary in order to execute super.foobar(), because super.foobar() entails that the linearization is further searched for a definition of foobar.
When you now look at your definition of class C then you'll see that it has the following linearization
C, B, A
Consequently, it cannot compile, because beginning from B you don't find an implementation of test.
When we now look at the examples which work, then we'll why they actually work. In the case of C extends A with new C with B, you basically create an anonymous class Z extends C with B. The linearization of Z is
Z, B, C, A
There you see, that B can find in C an implementation of test. Thus, the code can compile. The same holds true for the example with class D.
According to the article you provided:
The base trait (or abstract class) defines an abstract interface that all the cores and stackables extend, as shown in Figure 1. The core traits (or classes) implement the abstract methods defined in the base trait, and provide basic, core functionality. Each stackable overrides one or more of the abstract methods defined in the base trait, using Scala's abstract override modifiers, and provides some behavior and at some point invokes the super implementation of the same method. In this manner, the stackables modify the behavior of whatever core they are mixed into.
In you case:
class C extends A with B { override def test = { "C" } }
you don't have core trait. A is base, as it defines the interface, B is stackable (as it calls super, expecting it to be implemented in core), C is also stackable, as the test declaration in the body of the class is the most concrete (it overrides one from all of the traits).
In your "fixed" examples you just introduced correct core implementation:
class C extends A { override def test = { "C" } }
new C with B // works as expected
class C extends A {
override def test = { "C" }
}
class D extends C with B
Here C defines test before it is overridden by B, so it serves as core.

Understanding use of "this: SomeClassOrTrait =>" in Scala [duplicate]

A self-type for a trait A:
trait B
trait A { this: B => }
says that "A cannot be mixed into a concrete class that does not also extend B".
On the other hand, the following:
trait B
trait A extends B
says that "any (concrete or abstract) class mixing in A will also be mixing in B".
Don't these two statements mean the same thing? The self-type seems to serve only to create the possibility of a simple compile-time error.
What am I missing?
It is predominately used for Dependency Injection, such as in the Cake Pattern. There exists a great article covering many different forms of dependency injection in Scala, including the Cake Pattern. If you Google "Cake Pattern and Scala", you'll get many links, including presentations and videos. For now, here is a link to another question.
Now, as to what is the difference between a self type and extending a trait, that is simple. If you say B extends A, then B is an A. When you use self-types, B requires an A. There are two specific requirements that are created with self-types:
If B is extended, then you're required to mix-in an A.
When a concrete class finally extends/mixes-in these traits, some class/trait must implement A.
Consider the following examples:
scala> trait User { def name: String }
defined trait User
scala> trait Tweeter {
| user: User =>
| def tweet(msg: String) = println(s"$name: $msg")
| }
defined trait Tweeter
scala> trait Wrong extends Tweeter {
| def noCanDo = name
| }
<console>:9: error: illegal inheritance;
self-type Wrong does not conform to Tweeter's selftype Tweeter with User
trait Wrong extends Tweeter {
^
<console>:10: error: not found: value name
def noCanDo = name
^
If Tweeter was a subclass of User, there would be no error. In the code above, we required a User whenever Tweeter is used, however a User wasn't provided to Wrong, so we got an error. Now, with the code above still in scope, consider:
scala> trait DummyUser extends User {
| override def name: String = "foo"
| }
defined trait DummyUser
scala> trait Right extends Tweeter with User {
| val canDo = name
| }
defined trait Right
scala> trait RightAgain extends Tweeter with DummyUser {
| val canDo = name
| }
defined trait RightAgain
With Right, the requirement to mix-in a User is satisfied. However, the second requirement mentioned above is not satisfied: the burden of implementing User still remains for classes/traits which extend Right.
With RightAgain both requirements are satisfied. A User and an implementation of User are provided.
For more practical use cases, please see the links at the start of this answer! But, hopefully now you get it.
Self types allow you to define cyclical dependencies. For example, you can achieve this:
trait A { self: B => }
trait B { self: A => }
Inheritance using extends does not allow that. Try:
trait A extends B
trait B extends A
error: illegal cyclic reference involving trait A
In the Odersky book, look at section 33.5 (Creating spreadsheet UI chapter) where it mentions:
In the spreadsheet example, class Model inherits from Evaluator and
thus gains access to its evaluation method. To go the other way, class
Evaluator defines its self type to be Model, like this:
package org.stairwaybook.scells
trait Evaluator { this: Model => ...
One additional difference is that self-types can specify non-class types. For instance
trait Foo{
this: { def close:Unit} =>
...
}
The self type here is a structural type. The effect is to say that anything that mixes in Foo must implement a no-arg "close" method returning unit. This allows for safe mixins for duck-typing.
Another thing that has not been mentioned: because self-types aren't part of the hierarchy of the required class they can be excluded from pattern matching, especially when you are exhaustively matching against a sealed hierarchy. This is convenient when you want to model orthogonal behaviors such as:
sealed trait Person
trait Student extends Person
trait Teacher extends Person
trait Adult { this : Person => } // orthogonal to its condition
val p : Person = new Student {}
p match {
case s : Student => println("a student")
case t : Teacher => println("a teacher")
} // that's it we're exhaustive
Section 2.3 "Selftype Annotations" of Martin Odersky's original Scala paper Scalable Component Abstractions actually explains the purpose of selftype beyond mixin composition very well: provide an alternative way of associating a class with an abstract type.
The example given in the paper was like the following, and it doesn't seem to have an elegant subclass correspondent:
abstract class Graph {
type Node <: BaseNode;
class BaseNode {
self: Node =>
def connectWith(n: Node): Edge =
new Edge(self, n);
}
class Edge(from: Node, to: Node) {
def source() = from;
def target() = to;
}
}
class LabeledGraph extends Graph {
class Node(label: String) extends BaseNode {
def getLabel: String = label;
def self: Node = this;
}
}
TL;DR summary of the other answers:
Types you extend are exposed to inherited types, but self-types are not
eg: class Cow { this: FourStomachs } allows you to use methods only available to ruminants, such as digestGrass. Traits that extend Cow however will have no such privileges. On the other hand, class Cow extends FourStomachs will expose digestGrass to anyone who extends Cow .
self-types allow cyclical dependencies, extending other types does not
Let's start with the cyclical dependency.
trait A {
selfA: B =>
def fa: Int }
trait B {
selfB: A =>
def fb: String }
However, the modularity of this solution is not as great as it might first appear, because you can override self types as so:
trait A1 extends A {
selfA1: B =>
override def fb = "B's String" }
trait B1 extends B {
selfB1: A =>
override def fa = "A's String" }
val myObj = new A1 with B1
Although, if you override a member of a self type, you lose access to the original member, which can still be accessed through super using inheritance. So what is really gained over using inheritance is:
trait AB {
def fa: String
def fb: String }
trait A1 extends AB
{ override def fa = "A's String" }
trait B1 extends AB
{ override def fb = "B's String" }
val myObj = new A1 with B1
Now I can't claim to understand all the subtleties of the cake pattern, but it strikes me that the main method of enforcing modularity is through composition rather than inheritance or self types.
The inheritance version is shorter, but the main reason I prefer inheritance over self types is that I find it much more tricky to get the initialisation order correct with self types. However, there are some things you can do with self types that you can't do with inheritance. Self types can use a type while inheritance requires a trait or a class as in:
trait Outer
{ type T1 }
trait S1
{ selfS1: Outer#T1 => } //Not possible with inheritance.
You can even do:
trait TypeBuster
{ this: Int with String => }
Although you'll never be able to instantiate it. I don't see any absolute reason for not being be able to inherit from a type, but I certainly feel it would be useful to have path constructor classes and traits as we have type constructor traits / classes. As unfortunately
trait InnerA extends Outer#Inner //Doesn't compile
We have this:
trait Outer
{ trait Inner }
trait OuterA extends Outer
{ trait InnerA extends Inner }
trait OuterB extends Outer
{ trait InnerB extends Inner }
trait OuterFinal extends OuterA with OuterB
{ val myV = new InnerA with InnerB }
Or this:
trait Outer
{ trait Inner }
trait InnerA
{this: Outer#Inner =>}
trait InnerB
{this: Outer#Inner =>}
trait OuterFinal extends Outer
{ val myVal = new InnerA with InnerB with Inner }
One point that should be empathised more is that traits can extends classes. Thanks to David Maclver for pointing this out. Here's an example from my own code:
class ScnBase extends Frame
abstract class ScnVista[GT <: GeomBase[_ <: TypesD]](geomRI: GT) extends ScnBase with DescripHolder[GT] )
{ val geomR = geomRI }
trait EditScn[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
trait ScnVistaCyl[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
ScnBase inherits from the Swing Frame class, so it could be used as a self type and then mixed in at the end (at instantiation). However, val geomR needs to be initialised before it's used by inheriting traits. So we need a class to enforce prior initialisation of geomR. The class ScnVista can then be inherited from by multiple orthogonal traits which can themselves be inherited from. Using multiple type parameters (generics) offers an alternative form of modularity.
trait A { def x = 1 }
trait B extends A { override def x = super.x * 5 }
trait C1 extends B { override def x = 2 }
trait C2 extends A { this: B => override def x = 2}
// 1.
println((new C1 with B).x) // 2
println((new C2 with B).x) // 10
// 2.
trait X {
type SomeA <: A
trait Inner1 { this: SomeA => } // compiles ok
trait Inner2 extends SomeA {} // doesn't compile
}
A self type lets you specify what types are allowed to mixin a trait. For example, if you have a trait with a self type Closeable, then that trait knows that the only things that are allowed to mix it in, must implement the Closeable interface.
Update: A principal difference is that self-types can depend on multiple classes (I admit that's a bit corner case). For example, you can have
class Person {
//...
def name: String = "...";
}
class Expense {
def cost: Int = 123;
}
trait Employee {
this: Person with Expense =>
// ...
def roomNo: Int;
def officeLabel: String = name + "/" + roomNo;
}
This allows to add the Employee mixin just to anything that is a subclass of Person and Expense. Of course, this is only meaningful if Expense extends Person or vice versa. The point is that using self-types Employee can be independent of the hierarchy of the classes it depends on. It doesn't care of what extends what - If you switch the hierarchy of Expense vs Person, you don't have to modify Employee.
in the first case, a sub-trait or sub-class of B can be mixed in to whatever uses A. So B can be an abstract trait.

In what scenario does self-type annotation provide behavior not possible with extends

I've tried to come up with a composition scenario in which self-type and extends behave differently and so far have not found one. The basic example always talks about a self-type not requiring the class/trait not having to be a sub-type of the dependent type, but even in that scenario, the behavior between self-type and extends seems to be identical.
trait Fooable { def X: String }
trait Bar1 { self: Fooable =>
def Y = X + "-bar"
}
trait Bar2 extends Fooable {
def Y = X + "-bar"
}
trait Foo extends Fooable {
def X = "foo"
}
val b1 = new Bar1 with Foo
val b2 = new Bar2 with Foo
Is there a scenario where some form of composition or functionality of composed object is different when using one vs. the other?
Update 1: Thanks for the examples of things that are not possible without self-typing, I appreciate the information, but I am really looking for compositions where self and extends are possible, but are not interchangeable.
Update 2: I suppose the particular question I have is why the various Cake Pattern examples generally talk about having to use self-type instead of extends. I've yet to find a Cake Pattern scenario that doesn't work just as well with extends
Cyclic references can be done with self-types but not with extends:
// Legal
trait A { self: B => }
trait B { self: A => }
// Illegal
trait C extends D
trait D extends C
I use this sometimes to split up implementations across multiple files, when there are cyclic dependencies.
Also,
scala> trait A { def a: String ; def s = "A" }
defined trait A
scala> trait B { _: A => def s = "B" + a }
defined trait B
scala> trait C extends A { def a = "c" ; override def s = "C" }
defined trait C
scala> new C {}.s
res0: String = C
scala> new A with B { def a = "ab" }.s
<console>:10: error: <$anon: A with B> inherits conflicting members:
method s in trait A of type => String and
method s in trait B of type => String
(Note: this can be resolved by declaring an override in <$anon: A with B>.)
new A with B { def a = "ab" }.s
^
scala> new A with B { def a = "ab" ; override def s = super[B].s }.s
res2: String = Bab
The point, if there is one, is that B.s doesn't override A.s.
That's not as motivational as the other answer.
The generic parameter must be the type itself:
trait Gen[T] {self : T => ...}
I don't see how you can get this constraint in say java or C#. It may however be approximated with
trait Gen[T] {
def asT : T // abstract
}
Also,
as for self type, it needs a trait to mix in. It cannot use class or object. The weird thing is it allows to define a class can mix in with class, but it only fails compilation when you try to instantiate it. see this question:
why self-type class can declare class
The biggest difference is in the public interface that you end up with. Let's take the example you give (slightly simplified):
trait Fooable { def foo: String = "foo" }
trait Bar1 { self: Fooable =>
def Y = foo + "-bar"
}
trait Bar2 extends Fooable {
def Y = foo + "-bar"
}
// If we let type inference do its thing we would also have foo() in the public interface of b1, but we can choose to hide it
def b1:Bar1 = new Bar1 with Fooable
// b2 will always have the type members from Bar2 and Fooable
def b2:Bar2 = new Bar2{}
// Doesn't compile - 'foo' definition is only visible inside the definition of Bar1
println(b1.foo)
// Compiles - 'foo' definition is visible outside the definition of Bar2
println(b2.foo)
So if you want to use the capabilities of a trait without necessarily letting your clients know that you are mixing the trait in, then you should use the self-type annotation.
Self-type annotation does not expose the public interface of the underlying type.
Extending another type always exposes the public interface of the parent type.

Force Scala trait to implement a certain method

Is there a way to specify that a trait has to provide a concrete implementation of a method?
Given some mixin
class A extends B with C {
foo()
}
The program will compile if either of A, B, or C implements foo(). But how can we force, for example, B to contain foo's implementation?
You can do the following:
class A extends B with C {
super[B].foo()
}
This will only compile if B implements foo. Use with caution though as it (potentially) introduces some unintuitive coupling. Further, if A overrides foo, still B's foo will be called.
One IMHO valid use case is conflict resolution:
trait B { def foo() = println("B") }
trait C { def foo() = println("C") }
class A extends B with C {
override def foo() = super[B].foo()
}
If you want to make sure B declares foo, you can use type ascription:
class A extends B with C {
(this:B).foo()
}
This will only compile if B declares foo (but it might be implemented in C or A).

Scala child class inherits parent class traits?

Why if I have:
trait T {
def method(a: Int)
}
class A extends T {
//...
}
class B extends A {
//...
}
then when I do this:
//...
val b = new B
b.method(15)
//...
the method() is said to be undefined for B? Why do I have to explicitly say that
class B extends A with T
in order to obtain what I want? Are not traits of parent classes inherited? How can it be so if they may realize a big part of parent's own methods which are inherited by definition? If it is so, what is the argument?
I think you just did not implement the method method because I tested it on my computer and the following code works:
scala> trait T {
| def method(a:Int) =a
| }
defined trait T
scala> class A extends T
defined class A
scala> class B extends A
defined class B
scala> val b = new B
b: B = B#164a40a0
scala> b.method(11)
res25: Int = 11
Your code does not compile, because the method is never implemented. B cannot be instantiated because the classes are all abstract.
Add the method body like this, inside Trait A:
def method(a: Int)={
//do something useful here
}
It then compiles, and there are no errors, and indeed, the instance of B may use the method.