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
Related
Given a superclass or trait, and assuming an open hierarchy, how can I enforce that all extending classes implement a particular type class?
For instance, assuming the type class Default
trait Default[T] { def default: T }
and some trait Super:
trait Super { }
I would like to enforce that the following (by itself) is not allowed:
class A(val i: Int) extends Super
...while the following is:
class B(val i: Int) extends Super
implicit val bHasDef = new Default[B] { def default = B(42) }
Assuming the above is possible, can I then access the type class evidence for the subtypes from a method within Super? I.e, something like:
trait Super {
def magic: Default[this.type] = ???
}
I hardly think you can enforce that, at least in a simple enough way, maybe it's possible with something more complex like shapeless.
What I would do is add some modifications to the super trait and make it take a self reference to Default
trait Default[T] { def default: T }
trait Super[T] {
self: Default[T] =>
}
class B(val i: Int) extends Super[Int] with Default[Int] {
override def default: Int = ???
}
class A(val i: Int) extends Super[Int] // doesn't compile, needs a Default
This should also solve the second part of your question, the disadvantage is that now one trait is bundled to the other.
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.
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
I'd like to "lock" a class, which is extended from a trait. Is it possible in Scala?
For example I have:
trait A {
val boris: String
val john: String
val number: Int
}
class B extends A {
// do something with these values
}
but can I ensure, that in class B no new values will be added if those aren't declared in trait A?
Thanks for your answers.
You cannot.
But if you simply mark the trait as sealed and provide a default implementation:
sealed trait A { val boris: String }
final class B(val boris: String) extends A {}
then people are free to create implicit value classes that make it look like new functionality has been added (except without actually creating the class):
implicit class MyB(val underlying: B) extends AnyVal {
def sirob = underlying.boris.reverse
}
(new B("fish")).sirob // "hsif"
You can also let the classes take a type parameter as a marker if you want to keep them straight at compile-time (though not runtime):
sealed trait A[T] { val boris: String }
final class B[T](val boris: String) extends A[T] {}
implicit class MyB(val underlying: B[Int]) extends AnyVal {
def sirob = underlying.boris.reverse
}
(new B[Int]("fish")).sirob // "hsif"
(new B[Char]("fish")).sirob // error: value sirob is not a member of B[Char]
So you could--especially with 2.10--simply lock everything and let users enrich the original interface this way.
I'm not sure if this covers your intended use case, though; it doesn't provide any inheritance.
Based on your example and my guess at what you are actually trying to do, you may want to consider just using case classes.
Extending a case class is generally avoided (I think it will spit out deprecation warnings if you try), so that will prevent people from wanting to extend your class in order to add functionality.
Translating your example into a case class:
case class A (boris: String, john: String, number: Int)
Then instead of extending A to change its values, you'd just make a new instance, e.g.
val a2 = someOtherA.copy(john="Doe")
I have two case classes that inherit from an abstract base class. I want to define some methods on the abstract base class that use the copy methods on the inheriting case classes (and so return an instance of the child class.) Is there a way to do this using self types?
Example code:
abstract class BaseClass(a: String, b: Int) {
this: case class => //not legal, but I'm looking for something similar
def doubleB(newB: Int) = this.copy(b = b * 2) //doesn't work because BaseClass has no copy
}
case class HasC(a: String, b: Int, c: Boolean) extends BaseClass(a, b) {
def doesStuffWithC(newC: Boolean) = {
...
}
}
case class HasD(a: String, b: Int, D: Double) extends BaseClass(a, b) {
def doesStuffWithD(newD: Double) = {
...
}
}
I've figured out how to get the result I want thanks to this question:
How to use Scala's this typing, abstract types, etc. to implement a Self type?
but it involves adding a makeCopy method to BaseClass and overriding it with a call to copy in each of the child case classes, and the syntax (especially for the Self type) is fairly confusing. Is there a way to do this with Scala's built in self typing?
You can't do what you want because copy needs to know about all the possible parameters. So even if case classes inherited from Copyable, it wouldn't be the copy you needed. Also, if you're going to keep the types straight, you'll be thwarted by Scala's lack of a "MyType". So you can't just extend a base class. However, you could add an abstract method and type annotation:
abstract class BaseClass[C <: BaseClass[_]](a: String, b: Int) {
def setB(b0: Int): C
def doubleB(b0: Int) = setB(b0*2)
}
case class HasC(a: String, b: Int, c: Boolean) extends BaseClass[HasC](a,b) {
def setB(b0: Int) = this.copy(b = b0)
def doesStuffWithC(c0: Boolean) = doubleB(if (c0) b else -b).copy(c = c0)
}
And then you can:
scala> HasC("fish",1,false).doesStuffWithC(true)
res47: HasC = HasC(fish,2,true)
This extra work will be worth it if you have a lot of shared functionality that depends on the ability to copy just b (either many methods, or a small number of complicated methods)--that is, this solves the DRY issue. If instead you want to abstract over HasC and other derived classes, you can either use BaseClass[_] or add yet another level that defines setB(b0: Int): BaseBase or simply forget the type parameterization and use BaseClass as the return type (but recognize that HasC cannot use BaseClass methods and still retain its type identity).
I think you're out of luck. The copy methods on HasC and HasD have different signatures. It's a bit hidden because of the default arguments, but basically the definition in BaseClass wouldn't know which copy method to call.
You could define a makeCopy in the abstract class that takes a copier function that takes Unit and returns a BaseClass, then, in your methods that use it (like doubleB) override them in the case class bodies and make use of makeCopy by passing it an anonymous function that does the work of creating a new copy with the props changed, like so:
package delegatedcopy
abstract class BaseClass(a: String, b:Int){
def aField = a
def bField = b
def doubleB:BaseClass
def makeCopy(copier: () => BaseClass):BaseClass = copier()
}
case class HasC(override val aField: String, override val bField: Int, cField: Boolean) extends BaseClass(aField, bField){
override def doubleB:BaseClass = makeCopy( ()=> HasC(aField, bField * 2, cField) )
}
case class HasD(override val aField: String, override val bField: Int, dField:Double) extends BaseClass(aField, bField){
override def doubleB:BaseClass = makeCopy( ()=> HasD(aField, bField * 2, dField) )
}
A test app that demonstrates it:
import delegatedcopy._
object TestApp extends Application{
val hasC = HasC( "A C object", 5, true)
val hasD = HasD( "A D object", 2, 3.55)
val hasCDoubleB = hasC.doubleB
val hasDDoubleB = hasD.doubleB
println(hasC) // prints HasC(A C object,5,true)
println(hasCDoubleB) //prints HasC(A C object,10,true)
println( hasD ) // prints HasD(A D object,2,3.55)
println( hasDDoubleB ) // prints HasD(A D object,4,3.55)
}
In this way, you are able to keep the makeCopy method the same for all children classes as in the base class, and can probably implement or mix in quite a bit of functionality in the base and case classes while keeping common code in a safe place and being able to pass clients a BaseClass and pattern match on the specific case classes.