Scala child class inherits parent class traits? - scala

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.

Related

How to get implicit and explicit identical value to align when both being mixed in

Assume the following situation
I have a trait A and a trait B that both declare a value that has the same name and type.
A defines the value explicitly, while B defines it implicitly
A and B are from external libraries and can not be changed. I don't want to fork.
I want to use both of them in a class C that is in my own code
How can I get them to align inside class C?
I want B.foo to be the value from A.foo
// External code, cant touch
trait A{
val foo = "boom"
}
trait B{
implicit val foo: String
}
// My class
class C extends A with B {
//uh oh??
}
Update (with help from Jasper-M)
// External code, cant touch
trait A{
val foo = "boom"
}
trait B{
implicit val foo: String
def implBang()(implicit s: String) = s
def doTheBang() = implBang()
}
// My class
class C extends B with A {}
new C().doTheBang; // Prints "boom"
Now only question remaining, how would I get foo to be in the implicit scope for class C?
Ideally you can select the implementation you want with super[Name]. But for vals that doesn't work for some reason.
class C extends A with B {
override implicit val foo = super[A].foo
// error: super may not be used on value foo
}
So if you really need some implicit String in C I would suggest just letting linearization do its thing and define another implicit val.
class C extends A with B {
implicit val bar = foo
}
You can just override the implicit variable, like:
// My class
class C extends A with B {
override implicit val foo = "My Value"
}

Scala: Return type of abstract method

I cannot figure out how to specify the return type of a method an abstract class A, if the same method of the concrete classes have different return (sub)types:
abstract class A {
def method: List[Common (?)] // I want to force all subclasses to define this method
}
class B1 extends A {
def method(a,b,c): List[Sub1] = {...}
}
class B2 extends A {
def method(a,b,c): List[Sub2] = {...}
}
I tried to define a common trait of Sub1 and Sub2:
abstract class Common // or abstract class
case class Sub1 extends Common
case class Sub2 extends Common
but I keep getting this:
Compilation error[class B1 needs to be abstract,
since method "method" in class A of type => List[Common] is not defined]
If I don't define the return type in class A, I get the same error with ... type => Unit ... instead.
How can I solve that?
def method: List[Common]
Is not the same as
// returns `List[Common]` to simplify things, but it would be the same if we returned a sub-type
def method(a: ?, b: ?, c: ?): List[Common] = {...}
The first is a parameterless method that returns a List[Common], and the second is a method with three parameters that returns a List[Common]. The compiler sees these as two completely different methods. The fact that they have the same name means nothing.
The compiler is complaining because def method: List[Common] is not defined in the subclasses of A.
This compiles:
abstract class Common // or abstract class
case class Sub1() extends Common
case class Sub2() extends Common
abstract class A {
def method(): List[Common]
}
class B1 extends A {
def method(): List[Sub1] = ???
}
class B2 extends A {
def method(): List[Sub2] = ???
}
All I have done is:
add the () to Sub1() and Sub2()
return List[Common] from A
EDIT
As #m-z mentioned, it works because every def method() has the same signature now.

Override method using superclass/trait implementation

Suppose I have next traits:
trait A {
val a: String = "a"
}
trait B {
def a: String = "b"
}
And I want to mix both of these traits into some class C
class C extends B with A
Compiler doesn't allow me to create such class because I have to override method a
I want to override it using for example only A's implementaion. How can I do this?
EDIT
scala> class C extends B with A {
| override val a = super.a
| }
<console>:10: error: super may be not be used on value a
override val a = super.a
^
The compiler can't possibly know which one you intend to use, therefore you must specify it like:
class C extends B with A {
override def a = super[A].a
}
This approach allows you to choose the parent directly, regardless the trait order.
However, the traits define a differently (val and def) thus you must choose only one. You should use either def or val in both traits (not mix them).
Provided you make a a def in the A trait, you can do
class C extends B with A {
override val a = super.a
}
val c = new C
c.a // "a"
This will work because A is extended after B, so super will be its implementation.

Trait A can only be extended by class that extends Trait B

Say I have two traits (A and B) and a class C which mixes them in and implements their methods:
trait A {
def foo
}
trait B {
def bar
}
class C extends A with B {
def foo = "Foo"
def bar = "Bar"
}
Is there any way in Scala to specify that the class that extends trait B must extend trait A and then use the implemented method of trait A's defined method in trait B?
So that B could call this.foo() and access the value that has been returned by C's implementation?
Just specify what you want this to be:
trait B { this: A =>
def bar = this.foo
}
This is so called self type and this here is an alias rather than keyword (so self: A, that: A and so on are perfectly legal).

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

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.