Start learning free

LESSON 403 OF 414 · OBJECT-ORIENTED PROGRAMMING

Inheritance in Scala: extends and Parent Constructors

Lesson Read the full explanation

TL ; DR:

A child class can inherit from a parent class — it gets all the parent's fields and methods for free, and can add its own. This lets you reuse code instead of copy-pasting it.


class Puppy(name: String) extends Dog(name) {
    def whine(): Unit = { println("whimper") }
}


Full lesson:

Inheritance is one of the four classic OOP pillars (along with encapsulation, polymorphism, and abstraction). The idea is simple: most real-world things are kinds of other things — a Puppy is a Dog, a Car is a Vehicle, a Manager is an Employee. When you model that "is-a" relationship in code, the child class gets the parent's data and behavior automatically.

What gets inherited?

  • Fields — the Puppy has a name field even though we only declared it on Dog.
  • Methods — the Puppy can call bark() even though we only defined it on Dog.
  • The contract — anywhere code expects a Dog, you can pass a Puppy (we'll see this when we cover polymorphism).

What you still write

  • The constructor usually has to forward arguments up to the parent's constructor (because the parent's fields need initializing). In Scala you do that in the class header: extends Dog(name).
  • Any new methods or new fields specific to the child.

Your task

Below the Dog class, create a Puppy class that inherits from Dog and adds one new method, whine(), that prints "whimper". The harness creates a Puppy named "Buddy", calls its inherited bark(), and then its new whine().

Expected output:

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

    SCALA · OBJECT-ORIENTED PROGRAMMING

    Inheritance in Scala, explained

    What inheritance is

    Inheritance models an "is-a" relationship. A puppy is a dog, a car is a vehicle, a manager is an employee. When a child class (also called a subclass) inherits from a parent class (a superclass), it gets the parent's fields and methods without repeating them, and it can add its own. This is how code is reused instead of copied.

    What is inherited

    • Fields. A Puppy has a name although only Dog declares it.
    • Methods. A Puppy can call bark() although only Dog defines it.
    • The type. Anywhere the code expects a Dog, a Puppy can be used.

    The syntax

    A child class names its parent with extends in the class header. In Scala, the same header also passes the arguments for the parent's constructor:

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

    The header class Puppy(name: String) extends Dog(name) says three things at once. A Puppy is created from one String. It is a kind of Dog. And that string is handed to Dog's constructor, so the parent's name field gets set. There is no separate constructor body to write and no super(...) call, as in some other languages.

    Inside the braces, Puppy adds whine. It doesn't redefine bark, because it is inherited.

    Using the child class

    val buddy = Puppy("Buddy")
    buddy.bark()
    buddy.whine()
    println(buddy.name)
    

    This prints:

    Woof! I am Buddy
    whimper
    Buddy
    

    The call buddy.bark() runs the version declared in Dog, and buddy.name reads the field that Dog declared.

    Details that matter

    • The parameter is not repeated as a field. In class Puppy(name: String) extends Dog(name), name is only a constructor parameter of Puppy. Writing val name there would try to define a second field with the same name as the one Dog already has, and the compiler rejects it: value name of type String needs `override` modifier.
    • The parent's arguments are required. class Puppy(name: String) extends Dog, with no (name), doesn't compile, because Dog cannot be created without a name. The error is missing argument for parameter name of constructor Dog.
    • A child can take more parameters than its parent. class Tagged(name: String, val tag: Int) extends Dog(name) accepts two values, passes one up, and keeps the second as its own field.
    • A parent variable can hold a child object. val d: Dog = buddy is valid and d.bark() works. But d.whine() doesn't compile, because the type Dog has no whine. What a variable's type promises is what you can call on it.
    • A class extends one class. Scala has single inheritance for classes. Sharing behavior across several types is done with traits, which come later.

    The exercise

    The starter code gives Dog and a mainFunction that creates a Puppy named "Buddy", calls bark() and then whine(). Write Puppy between Dog and Solution:

    class Puppy(name: String) extends Dog(name) {
        def whine(): Unit = {
            println("whimper")
        }
    }
    

    The expected output is:

    Woof! I am Buddy
    whimper
    

    If Puppy is missing, the call Puppy("Buddy") fails to compile. If whine is missing, the compiler reports that whine is not a member of Puppy.

    Key takeaways

    • Use extends in the class header to inherit from a parent class.
    • Pass the parent's constructor arguments right after the parent's name: extends Dog(name).
    • The child gets the parent's members and only adds what is new.
    • A child object can be used wherever the parent type is expected.
    Keep going with ScalaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free