Start learning free

LESSON 404 OF 414 · OBJECT-ORIENTED PROGRAMMING

Method Overriding in Scala: override and super

Lesson Read the full explanation

TL ; DR:

When a child class defines a method with the same name as the parent's, the child's version overrides the parent's. Different objects can give the same method name different behavior.


class Dog {
    def bark(): Unit = { println("Woof!") }
}
class Puppy extends Dog {
    override def bark(): Unit = { println("Yip!") }
}


Full lesson:

You've seen that a child class inherits the parent's methods. Overriding is what happens when the child wants to change one of those inherited methods.

Why override?

Subclasses are usually special cases of the parent. A Puppy is a Dog, but it sounds different — "Yip!" instead of "Woof!". Instead of inventing a new method name, you redefine bark() on the Puppy. Callers don't need to know which subclass they're holding — they just call bark() and the right version runs.

How it works in Scala

  • Every method can be overridden by default, unless it is marked final. The parent needs no special keyword.
  • The child must mark its replacement with the override keyword. Leaving it out is a compile error.

Your task

The Dog class already defines bark. Inside the Puppy subclass, override bark with override def so it prints "Yip! I am " followed by the puppy's name. The harness creates a Puppy named "Buddy" and calls bark() on it.

Expected output:

Yip! I am Buddy
STEP 1 OF 2
    Ctrl + Enter to check

    SCALA · OBJECT-ORIENTED PROGRAMMING

    Method Overriding in Scala, explained

    What overriding is

    A child class inherits its parent's methods, but sometimes one of them doesn't fit. A Puppy is a Dog, yet it says "Yip!" instead of "Woof!". Overriding means defining a method in the child class with the same name and parameters as one in the parent, so the child's version replaces the inherited one for objects of the child class.

    Callers don't need to know which kind of dog they hold. They call bark() and the right version runs.

    The syntax

    Scala requires the override keyword when a method replaces a concrete method of the parent:

    class Dog(val name: String) {
        def bark(): Unit = {
            println(s"Woof! I am $name")
        }
    }
    
    class Puppy(name: String) extends Dog(name) {
        override def bark(): Unit = {
            println(s"Yip! I am $name")
        }
    }
    

    The parent's method needs no special marking: Scala methods can be overridden unless they are declared final. The child's method repeats the name, the parameter list and the return type.

    What the compiler checks

    The override keyword is a safety net, and Scala enforces it from both sides:

    • Forgetting it is an error. A def bark() in Puppy without override fails with method bark of type (): Unit needs `override` modifier. This stops an accidental replacement of an inherited method.
    • Using it on nothing is an error. A typo such as override def bork() fails with method bork overrides nothing. The compiler catches the misspelled name.
    • The signature must match. Changing the return type to Int while the parent returns Unit is rejected as an incompatible type.
    • final blocks it. If the parent declares final def sleep(), no child can override it, and trying gives cannot override final member.

    Note that Scala doesn't use the @Override annotation of other languages. Writing it doesn't count as the keyword, and the compiler still asks for override.

    Which version runs

    The method that runs depends on the real object, not on the type of the variable:

    val buddy = Puppy("Buddy")
    buddy.bark()
    val d: Dog = buddy
    d.bark()
    val dogs = List[Dog](Dog("Rex"), buddy)
    dogs.foreach(_.bark())
    

    The output is:

    Yip! I am Buddy
    Yip! I am Buddy
    Woof! I am Rex
    Yip! I am Buddy
    

    The variable d has type Dog, but the object is a Puppy, so the puppy's bark runs. In the list, each element behaves according to what it is. This is called polymorphism: one call, different behavior.

    Calling the parent's version

    An override can still use the parent's code through super:

    class Puppy(name: String) extends Dog(name) {
        override def bark(): Unit = {
            super.bark()
            println(s"Yip! I am $name")
        }
    }
    

    Now Puppy("b").bark() prints the dog's line first and then the puppy's: Woof! I am b followed by Yip! I am b. This is useful when the child extends the parent's behavior instead of replacing it.

    Fields and parameterless methods can be overridden as well, with the same keyword, for example override def legs: Int = 3 in a child of a class that defines def legs: Int = 4.

    The exercise

    The starter code has Dog and an empty Puppy. Add the override so that the puppy prints Yip! I am followed by its name:

    class Puppy(name: String) extends Dog(name) {
        override def bark(): Unit = {
            println(s"Yip! I am $name")
        }
    }
    

    Inside the string, $name inserts the constructor parameter that Puppy passed on to Dog. With the name "Buddy", the output is:

    Yip! I am Buddy
    

    Common mistakes

    • Leaving out override. The compiler rejects the method.
    • Changing the signature. With a different parameter list, override is rejected because the method has a different signature than the overridden declaration.
    • Expecting the parent's output. Once Puppy overrides bark, a Puppy never prints the "Woof!" line unless the override calls super.bark().
    • Trying to override a final method. It is rejected.

    Key takeaways

    • Overriding replaces an inherited method in the child class.
    • Scala requires override def, and the compiler checks that something is really overridden.
    • The real object decides which version runs.
    • super.method() reaches the parent's version.
    Keep going with ScalaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free