Inheritance and Polymorphism in Scala

Introduction

Greetings! Today, we're going to demystify the crucial terms of Object-oriented programming (OOP): Inheritance and Polymorphism. These concepts form the backbone of efficient OOP. Our journey will unfold as follows: we'll start with an intuitive grasp of Inheritance and its implementation in Scala, and then we'll delve into Polymorphism, with a clear emphasis on method overriding.

Understanding Inheritance

Inheritance is similar to repurposing an old blueprint to create something new. In OOP, it lets one class inherit attributes and methods from another.

In Scala, we have the Parent Class, which offers features, and the Child Class, which receives these features. When implementing, we use the extends keyword for the Child class to indicate from which Parent class the features are coming.

Scala
// Defining an 'Animal' class (Parent Class)
class Animal:
    def eat(): Unit =
        println("This animal eats food.") // Prints: "This animal eats food."

// 'Cat' class inherits from 'Animal' (Child Class)
class Cat extends Animal:
    // Inherits all features from 'Animal'
    println("Creating an instance of cat...")

@main def run: Unit =
    val myCat = Cat()
    myCat.eat() // Prints: "This animal eats food."

Handling Constructors in Inheritance

Inheritance in Scala involves subclasses inheriting features from their superclass. A significant part of this process is ensuring that constructors in the superclass are adequately invoked by the subclass. Constructors are special methods used to initialize new objects. When a class inherits from another, the subclass must initialize the superclass as well.

When a subclass inherits from a superclass and both have primary constructors, the superclass's constructor automatically gets called when creating an instance of the subclass:

Scala
class Animal(name: String):
    println(s"$name is an Animal.")

class Cat(name: String) extends Animal(name):
    println(s"$name is also a Cat.")

@main def run: Unit =
    val myCat = Cat("Whiskers")
// Output:
// Whiskers is an Animal.
// Whiskers is also a Cat.

In the above example, the Cat class inherits from Animal, and both classes have primary constructors that accept a name parameter.

For classes with auxiliary constructors, Scala allows calling another constructor in the same class using the this keyword, which indirectly ensures the superclass's constructor is called:

Scala
class Animal(val name: String)

class Cat(name: String, lives: Int) extends Animal(name):
    def this(name: String) =
        this(name, 9)
        println(s"$name has $lives lives.")

@main def run: Unit =
    val myCat = Cat("Felix")
// Output: Felix has 9 lives.

The power and flexibility of Scala's inheritance mechanism are observable here, where a Cat class indirectly calls the superclass Animal constructor through its primary constructor to ensure proper initialization.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal