How to call a method on a superclass in Scala

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 {