Inheritance in Scala
What Is Inheritance?
Inheritance allows one class to acquire the properties and methods of another class.
The class whose members are inherited is called the parent class or superclass.
The class that inherits those members is called the child class or subclass.
For example:
class Employee {
val company = "CS Techie"
def work(): Unit = {
println("Employee is working")
}
}
class Developer extends Employee {
def writeCode(): Unit = {
println("Developer is writing code")
}
}
object Main extends App {
val developer = new Developer()
println(developer.company)
developer.work()
developer.writeCode()
}Output:
CS Techie
Employee is working
Developer is writing code
The Developer class inherits company and work() from Employee.
It also defines its own method, writeCode().
The important keyword here is extends.
class Developer extends Employee
This tells Scala that Developer is a subclass of Employee.
Why Do We Need Inheritance?
Without inheritance, you might end up repeating common fields and methods across multiple classes.
For example, imagine separate classes for developers and managers:
class Developer {
val name = "Rahul"
val company = "CS Techie"
def login(): Unit = {
println("Employee logged in")
}
def writeCode(): Unit = {
println("Writing code")
}
}
class Manager {
val name = "Priya"
val company = "CS Techie"
def login(): Unit = {
println("Employee logged in")
}
def conductMeeting(): Unit = {
println("Conducting meeting")
}
}Both classes contain repeated employee information and login behavior.
We can move the common functionality into a parent class.
Now both subclasses reuse the common employee functionality.
class Employee(val name: String) {
val company = "CS Techie" def login(): Unit = {
println(s"$name logged in")
}
}
class Developer(name: String) extends Employee(name) {
def writeCode(): Unit = {
println(s"$name is writing code")
}
}
class Manager(name: String) extends Employee(name) {
def conductMeeting(): Unit = {
println(s"$name is conducting a meeting")
}
}This makes the code easier to maintain and reduces duplication.
Understanding Constructors in Inheritance
When a child class extends a parent class, it must initialize the parent class.
Let's understand this through an example.
class Employee(val name: String, val salary: Double) {
def displayDetails(): Unit = {
println(s"Name: $name")
println(s"Salary: $salary")
}
}
class Developer(name: String, salary: Double, val technology: String) extends Employee(name, salary) {
def displayTechnology(): Unit = {
println(s"Technology: $technology")
}
}
object Main extends App {
val developer = new Developer("Rahul", 80000, "Scala")
developer.displayDetails()
developer.displayTechnology()
}Output:
Name: Rahul
Salary: 80000.0
Technology: Scala
Notice this line:
extends Employee(name, salary)
The child class passes its constructor arguments to the parent class constructor.
In Scala, the parent constructor is initialized as part of creating the child object.
Method Overriding
Sometimes a child class needs to provide its own implementation of a method inherited from the parent class.
This is called method overriding.
Scala uses the override keyword to make this explicit.
class Employee {
def work(): Unit = {
println("Employee is performing general work")
}
}
class Developer extends Employee {
override def work(): Unit = {
println("Developer is writing code")
}
}
object Main extends App {
val employee = new Employee()
val developer = new Developer()
employee.work()
developer.work()
}Output:
Employee is performing general work
Developer is writing code
The Developer class replaces the inherited implementation of work() with its own behavior.
In Scala, when you override a concrete method, you must use the override keyword.
This makes the intention clear and helps the compiler catch accidental overrides.
Using super to Call Parent Methods
What if you want to reuse the parent's implementation and then add some additional behavior?
Scala provides the super keyword.
class Employee {
def work(): Unit = {
println("Employee is working")
}
}
class Developer extends Employee {
override def work(): Unit = {
super.work()
println("Developer is writing Scala code")
}
}
object Main extends App {
val developer = new Developer()
developer.work()
}Output:
Employee is working
Developer is writing Scala code
Here, super.work() calls the parent class implementation before executing the developer-specific logic.
This is useful when the child class should extend existing behavior rather than completely replace it.
The final Keyword in Inheritance
Sometimes you don't want a class to be inherited or a method to be overridden.
Scala provides the final keyword for this purpose.
Prevent method overriding
class Employee {
final def employeeId(): Unit = {
println("Employee ID is fixed")
}
}
class Developer extends Employee {
// Overriding employeeId() is not allowed.
}Prevent class inheritance
final class Employee {
def work(): Unit = {
println("Employee is working")
}
}// This is not allowed:// class Developer extends EmployeeThe final keyword helps protect behavior that should not be changed by subclasses.
Types of Inheritance in Scala
You may encounter different inheritance structures when designing applications.
Single inheritance
One child class inherits from one parent class.
class Employeeclass Developer extends Employee
Multilevel inheritance
A class inherits from another child class, creating a chain.
class Person {
def introduce(): Unit = {
println("I am a person")
}
}
class Employee extends Person {
def work(): Unit = {
println("I am an employee")
}
}
class Developer extends Employee {
def code(): Unit = {
println("I write code")
}
}A Developer object can access the methods defined in all three classes.
Hierarchical inheritance
Multiple child classes inherit from the same parent class.
class Employee {
def login(): Unit = {
println("Employee logged in")
}
}
class Developer extends Employeeclass Manager extends EmployeeBoth Developer and Manager inherit the common login behavior.
Multiple inheritance
Scala classes cannot directly extend multiple classes.
For example, this is not valid:
// Not valid Scala:// class Developer extends Employee with Person
However, Scala supports combining multiple traits using with.
We'll explore traits in a later chapter.
Runtime Behavior and Inheritance
Inheritance also plays an important role in runtime polymorphism.
Consider this example:
class Employee {
def role(): Unit = {
println("General employee")
}
}
class Developer extends Employee {
override def role(): Unit = {
println("Software developer")
}
}
class Manager extends Employee {
override def role(): Unit = {
println("Project manager")
}
}
object Main extends App {
val employees: List[Employee] = List( new Developer(), new Manager(), new Employee() ) employees.foreach(_.role())
}Output:
Software developer
Project managerGeneral employee
Even though the collection is declared as List[Employee], Scala executes the overridden method belonging to the actual object at runtime.
This behavior is called runtime polymorphism.
We will explore polymorphism in more detail in Chapter 5.
When Should You Use Inheritance?
Inheritance is useful when a child class genuinely represents a specialized version of its parent class.
For example:
A Developer is an Employee.
A Manager is an Employee.
A SavingsAccount is a BankAccount.
However, don't use inheritance just to reuse a few methods.
If two classes simply need the same functionality but do not share a meaningful parent-child relationship, composition or traits may be a better choice.
Remember: Inheritance should represent a genuine is-a relationship, not just an opportunity to reuse code.
