This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 5.2, “How to call a method on a superclass in Scala.”
Problem
To keep your Scala code DRY (“Don’t Repeat Yourself ”), you want to invoke a method that’s already defined in a parent class or trait.
Solution
In the basic use case, the syntax to invoke a method in an immediate parent class is the same as Java: Use super
to refer to the parent class, and then provide the method name.
The following Android method (written in Scala) demonstrates how to call a method named onCreate
that’s defined in the Activity
parent class:
class WelcomeActivity extends Activity { override def onCreate(bundle: Bundle) { super.onCreate(bundle) // more code here ... } }
As with Java, you can call multiple superclass methods if necessary:
class FourLeggedAnimal { def walk { println("I'm walking") } def run { println("I'm running") } } class Dog extends FourLeggedAnimal { def walkThenRun { super.walk super.run } }
Running this code in the Scala REPL yields:
scala> val suka = new Dog suka: Dog = Dog@239bf795 scala> suka.walkThenRun I'm walking I'm running
Controlling which trait you call a method from
If your class inherits from multiple traits, and those traits implement the same method, you can select not only a method name, but also a trait name when invoking a method using super
. For instance, given this class hierarchy:
trait Human { def hello = "the Human trait" } trait Mother extends Human { override def hello = "Mother" } trait Father extends Human { override def hello = "Father" }
The following code shows different ways to invoke the hello
method from the traits the Child
class inherits from. This example shows that by mixing in the Human
, Mother
, and Father
traits, you can call super.hello
, or be more specific by calling super[Mother].hello
, super[Father].hello
, or super[Human].hello
:
class Child extends Human with Mother with Father { def printSuper = super.hello def printMother = super[Mother].hello def printFather = super[Father].hello def printHuman = super[Human].hello }
If you construct a test object to run this code:
object Test extends App { val c = new Child println(s"c.printSuper = ${c.printSuper}") println(s"c.printMother = ${c.printMother}") println(s"c.printFather = ${c.printFather}") println(s"c.printHuman = ${c.printHuman}") }
you can see the output:
c.printSuper = Father c.printMother = Mother c.printFather = Father c.printHuman = the Human trait
As shown, when a class inherits from multiple traits, and those traits have a common method name, you can choose which trait to run the method from with the super[traitName].methodName
syntax.
Note that when using this technique, you can’t continue to reach up through the parent class hierarchy unless you directly extend the target class or trait using the extends
or with
keywords. For instance, the following code won’t compile because Dog
doesn’t directly extend the Animal
trait:
trait Animal { def walk { println("Animal is walking") } } class FourLeggedAnimal extends Animal { override def walk { println("I'm walking on all fours") } } class Dog extends FourLeggedAnimal { def walkThenRun { super.walk // works super[FourLeggedAnimal].walk // works super[Animal].walk // error: won't compile } }
If you attempt to compile the code, you’ll get the error, “Animal does not name a parent class of class Dog.” You can get around that error by adding with Animal
to your class declaration (but whether or not that’s really a good idea is another story):
class Dog extends FourLeggedAnimal with Animal {
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |