I read the section of Programming in Scala where abstract override is introduced, but I'm still confused by what exactly is signified by the joining of these modifiers. The snippet of code in which these modifiers is used is pasted below:
trait Doubling extends IntQueue {
abstract override def put(x: Int) { super.put(2 * x) }
}
In particular, I am confused by the purpose of abstract in this case, and why we cannot achieve the expected results simply with the override keyword. If we did not include a call to super, would we need the keyword abstract? Why or why not? I'm looking for a detailed explanation of this keyword combo as it pertains to stackable traits.
The reason is that the base class method is abstract
abstract class IntQueue {
def get(): Int
def put(x: Int)
}
If you were to not put abstract on the trait you end up with the explanation you were seeking:
trait Doubling extends IntQueue {
override def put(x: Int) { super.put(2 * x) }
}
<console>:9: error: method put in class IntQueue is accessed from
super. It may not be abstract unless it is overridden by a member
declared `abstract' and `override'
override def put(x: Int) { super.put(2 * x) }
So - you would need to mark the method as abstract.
Here is the "other side" of the equation: if the methods do have implementations then it is not necessary to mark the trait's method as abstract:
abstract class IntQueue {
import collection.mutable._
val q = Queue[Int]()
def get(): Int = { q.dequeue() }
def put(x: Int) = { q.enqueue(x) }
}
It is now unnecessary to include abstract
trait Doubling extends IntQueue {
/* Look Ma! no abstract here ! */ override def put(x: Int) { super.put(2 * x) }
}
defined trait Doubling
The idea is that it's an incomplete override -- you still want to require the eventually concrete implementation of the trait to provide that method, even though you're modifying that hypothetical method's behavior. In other words, the method you're overriding isn't a full standalone implementation. It gives a similar effect as a method decorator might in Python.
As far as I can reason, a method on a trait is abstract override if and only if it calls super, but it breaks encapsulation to expect the client of the code to inspect the implementation of the method to know it needs a concrete implementation. Therefore, you must mark it abstract override to fully define the interface.
A part of late binding in scala traits posts; provides a very clear explanation; provided verbatim bellow (read the full post for more info):
The abstract base class provided an implementation of the requestApproval method. This is good since the leftmost trait calls this method. What happens if the base class’s method is abstract?
abstract class ApprovalRequest {
def requestApproval()
}
If we change this, we get a rather odd message from the compiler:
error: method requestApproval in class ApprovalRequest is accessed
from super. It may not be abstract unless it is overridden by a member
declared abstract and override
The combination of abstract and override tells the compiler that the final implementation of the method will be provided by the class mixing-in the trait. If we add the abstract keyword to the methods, we can no longer use our anonymous implementation of ApprovalRequest. That object can’t be created since the abstract override methods will be looking for an implementation of requestApproval and there isn’t one. Instead we have to create a new class that extends ApprovalRequest and implements requestApproval. We then mix the traits into an instance of that class.
class ApprovalDelegate extends ApprovalRequest {
override def requestApproval() {
println("and now we play the waiting game")
}
}
val adCampaign = new ApprovalDelegate with MarketingApprovalRequest
with FinanceApprovalRequest with ExecutiveApprovalRequest
Which will now give the output:
requesting approaval from executives
requesting approval from Finance
requesting approval from Marketing
and now we play the waiting game
Related
I am practicing the chapter about trait in the online book Programming In Scala 1ed.
http://www.artima.com/pins1ed/traits.html
There are two examples to show the power of traits, which are enrich thin interface and stackable modification. Here is the snippet of implementation
// example 1
trait Relation[T]
{
def compare(that: T): Int
def <(that: T) = compare(that) < 0
def >(that: T) = compare(that) > 0
def <=(that: T) = compare(that) <= 0
def >=(that: T) = compare(that) >= 0
}
// example 2
trait Doubling extends IntQueue
{
abstract override def put(a: Int) { super.put(a*2) }
}
The above code is fine to compile.
I am curious the existence of abstract modifier, so first I added the a abstract modifier in front of Relation::compare() in example 1. Maybe it's reasonable to mark abstract to compare which is going to be override by subclass.
// case 1
abstract def compare(that: T): Int
Then compiler complains
Error:(19, 16) `abstract' modifier can be used only for classes; it should be omitted for abstract members
abstract def compare(that: T): Int
^
I think this message says it should not put abstract modifier in trait. So I try to remove the abstract modifier from Doubling::put in the example 2 just like this
// case 2
override def put(a: Int) { super.put(a*2) }
But the compiler also complains
Error:(35, 36) method put in class IntQueue is accessed from super. It may not be abstract unless it is overridden by a member declared `abstract' and `override'
override def put(a: Int) { super.put(a*2) }
^
I know the reason the override modifier here, but I don't know why compiler complains I should add the abstract modifier with it. Does the compiler in previous case just complains I should only put abstract in classes?
You say "I think this message says it should not put abstract modifier in trait." No, it means that in Scala you mark a class abstract if it has abstract methods, but don't use the abstract keyword on the methods themselves. The compiler knows that a method is abstract simply because you haven't provided an implementation.
As for the second question, the reason you need the abstract keyword on your override of put is that IntQueue's put is abstract. You are telling the compiler that super.put(a*2) is not really an attempt to call an abstract method, which of course would not work -- you expect a trait to be mixed in which provides the implementation.
More info here.
What I would like to do is this:
trait Addable[T]{
def plus(x: T): T
}
trait AddableWithBounds[T] extends Addable[T] {
abstract override def plus(x: T): T = limitToBounds(super.plus(x))
def limitToBounds(x: T): T = ... //Some bounds checking
}
class Impl(num: Int) extends AddableWithBounds[Impl] {
override def plus(x: Impl) = new Impl(num + x.num)
}
Reading through various posts it would seem that the reason this is not possible is that after class linearization the stacked trait is only looking in classes to its right for implementations of super.plus(x: T)
That is a technical argument though and I'm interested in the question: Is there a fundamental reason why the implementation could not be taken from the base class? Because as you can see in this example it is not possible to implement the plus method before knowing the actual data type that needs to be added but afaic implementing bounds checking in a trait seems reasonable.
Just as an idea: If the problem is that in this case it is unclear which plus is being overridden in the base class maybe a scope identifier like
def Addable[Impl].plus(x: Impl) = new Impl(num + x.num)
would help.
I would avoid overriding and reliance on some super/sub-type invocation. Why not just implement plus and ask sub-types to provide an auxiliary abstract method:
trait Addable[T] {
def plus(x: T): T
}
trait AddableWithBounds[T] extends Addable[T] {
final def plus(x: T): T = limitToBounds(plusImpl(x))
protected def plusImpl(x: T): T
def limitToBounds(x: T): T = ??? //Some bounds checking
}
class Impl(num: Int) extends AnyRef with AddableWithBounds[Impl] {
protected def plusImpl(x: Impl): Impl = ???
}
You're asking: if super.f is abstract (or "incomplete") after mixin, please just pick a concrete f to serve. Maybe you're saying, only if there's exactly one such f, and it's defined in the current template.
One problem is that if the abstract f is called during initialization, and calls the concrete f in the subclass, the initializer for the subclass hasn't run yet.
This is common gotcha for template methods. I think the Josh Bloch book says don't do that.
But the person writing the stackable trait has no way of knowing that a super was transformed in this way.
I would like to implement a trait with a self-type like the following:
trait HasEquipment {
this: {def loadEquipment: List[Equipment]} =>
//more methods
}
Now i can mix this trait into classes and these classes have to define a "loadEquipment" Method:
case class Course(id: Long) extends HasEquipment {
def loadEquipment: List[Equipment] = {
//implementation
}
}
However I don't want to expose to loadEquipment Method to everyone but only to the trait. So what i would like to do is make loadEquipment private in the Course class so that only the trait has access to it. Making it private prevents the trait from accessing the method.
Is there another way to make loadEquipment only accessible from within the trait?
Not sure why you want a self-type here. An abstract, protected member works just as well:
trait HasEquipment {
protected def loadEquipment: List[Equipment]
}
case class Course(id: Long) extends HasEquipment {
override protected def loadEquipment: List[Equipment] = ???
}
As a side note, structural types in Scala make use of reflection, which is the reason why they're usually avoided.
Consider the following:
trait TestTrait {
def doStuff()
}
final class TestClass {
// ...
}
I would like to instantiate an instance of TestClass that implements the method in the trait. The following does not compile:
// Illegal inheritance from final class TestClass
val t = new TestClass with TestTrait {
def doStuff() {
println("doing stuff")
}
}
This makes sense, since the anonymous class created would extend the final class. What I'm really after is an anonymous implementation of the trait mixed in to an instance of the final class.
The following works, but seems a bit roundabout. Is there a way to do this directly without the declared trait implementation?
trait TestTraitImpl extends TestTrait {
def doStuff() {
println("doing stuff")
}
}
val t = new TestClass with TestTraitImpl
As it turns out, you can't do the latter either.
final class TestClass
trait TestTrait
val t = new TestClass with TestTrait
Apparently, any Foo with Bar is creation of a new anonymous type, and thus final classes cannot have traits as mixins. This adds a great deal of theoretical significance to making a class final, as it prevents not just the concept of inheritance, but also stackable modification.
Method resolution rules are different in the two cases. In the first case an anonymous class is constructed first by whatever happens to be the methods/attributes of the type:
final class TestClass with TestTrait
and then you are trying to override a method of that, which conflicts with the final qualifier of TestClass.
In the second case you explicitly specify that you are overriding TestTrait behavior, and then the overriden behavior is mixed into TestClass.
I think it's perfectly fine to use the second method, and that it conveys more clearly what the intention is.
I'm not sure what the purpose of override keyword is, in scala. If I have
trait Shape { def foo(v: Int) }
class Triangle extends Shape { override def foo(v: Int) {} }
it behaves (apparently at least) exactly the same as it does without override.
In the case you are implementing an abstract method as in your example, it is not strictly necessary to add the override modifier.
However, in case you want to override a concrete method from the superclass, the override modifier is necessary. This is to avoid accidental overrides which could happen with mixing composition -- mixing-in traits during some refactoring could easily introduce a method definition that could be overridden by the method defined in the body of the class, hence the need for explicitly stating that a method is an override.
In your particular case, you got a comprehensive answer from axel22. I just want to add, that there is at least one more case where you may encounter override modifier. The keyword can also be used with trait methods.
Imagine that you have an abstract class:
abstract class Writer {
def print(str: String)
}
and its concrete implementation that prints on a console
class ConsoleWriter extends Writer {
def print(str: String) = println(str)
}
Now, you want to create a trait that will modify its behaviour. Look at the following implementation:
trait Uppercase extends Writer {
abstract override def print(str: String) =
super.print(str.toUpperCase())
}
Notice that a method has two modifiers: abstract and override. This is only allowed for traits and it means that the trait must be mixed into some class that has a concrete definition of the method in question
With the definition above, you can do:
val writer = new ConsoleWriter with Uppercase
writer.print("abc")
which will yield the result
ABC
Much in the same vain, you can add more traits:
trait WithSpaces extends Writer {
abstract override def print(str: String) =
super.print(str.split("").mkString(" ").tail)
}
Now when you call
val writer = new ConsoleWriter with Uppercase with WithSpaces
writer.print("abc")
you will see:
A B C
The above usage of an override modifier in traits is a distinguishing feature in scala and you won't see it in java.
It's for error checking.
Suppose you have
trait Shape { def foo(v: Int) = 1 }
class Triangle extends Shape { override def foo(v: Int) = 2 }
and then you change Shape to
trait Shape { def bar(v: Int) = 1 }
In that case the "override" will tell you that the foo in Triangle overrides nothing.
See also:
http://docs.oracle.com/javase/7/docs/api/java/lang/Override.html
http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final