Inheritance in Scala is quite similar to the way it is in Java. The overriding aspects are a bit more detailed because in Scala there are not just methods to override but also vals, vars. There are a few restrictions added in Scala like:
- Overriding classes must use the “override” modifier. In Java one can use the @Override annotation to enforce correct overriding
- Auxiliary constructors cannot directly invoke the super class constructors. They only can invoke the primary constructor which in turn would invoke the Super class constructor. Read here to know more about Primary and Auxiliary constructors in Scala
also read:
In this article we will have a look at Inheritance concepts in Scala along with the restrictions related to overriding members of the class. First lets look at plain Inheritance.
Inheritance in Scala
Just like in Java, classes in Scala can extend other classes using the extends keyword. And Scala also doesn’t support Multiple Inheritance, but just like in Java we have Interfaces, in Scala we have Traits. We would learn about Traits in future posts. But for now they are kind-of equivalent to Interfaces in Java (not completely similar to Interfaces).
Suppose we have a Item class which has two fields- price and description:
class Item(var price:Double, var description:String){ override def toString():String = { description+" Cost: "+price } }
Every class in Scala are subclasses of AnyRef, just like we have Object in Java. But values like Int, Double, Byte, Char, Float, Short, Boolean, Unit (void) and similar others are subclasses of AnyVal. The toString() method is defined in AnyRef class and hence we use the override modifier when we override that method.
Lets have a SpecialItem class which extends Item.
class SpecialItem(price:Double, description:String) extends Item(price,description){ }
As I said before the constructor of the super class can be invoked only from the Primary Constructor of the sub class. From here we know that the Primary Constructor spans complete class declaration. So there is no best place to invoke the superclass constructor than in along with the extends clause.
Lets create an instance of both these types and print their contents:
object Main extends App{ val item = new Item(45.6,"Book") println(item) //Book Cost: 45.6 val specialItem = new SpecialItem(56.8,"Sepcial Book") println(specialItem) //Sepcial Book Cost: 56.8 }
Now that we have seen how classes can be extended in Scala, lets have a look at the restrictions related to overriding.
Overriding def’s
In Scala methods are declared by using “def” keyword. Suppose we need to calculate discounted price which can vary across items. For a simple Item there is no discounted price, but for a SpecialItem there would be a discount percentage value that would be taken and discounted price calculated based on that. Lets see how we can modify the above classes to add this functionality.
class Item(var price:Double, var description:String){ //No discount for Item def discountedPrice():Double = price override def toString():String = { description+" Cost: "+discountedPrice() } } class SpecialItem(price:Double, description:String, var discountPercent:Double) extends Item(price,description){ //Discounted price override def discountedPrice():Double = { price - ((discountPercent/100) * price) } }
In the constructor of SpecialItem we take an extra parameter for discount percentage. We declare it as var so discount percentage becomes a filed in the SpecialItem class and there would be getters/setters generated for discount percentage. Lets pass the discount percentage while constructing the SpecialItem instance:
object Main extends App{ val item = new Item(45.6,"Book") println(item) //Book Cost: 45.6 val specialItem = new SpecialItem(56.8,"Sepcial Book", 10) println(specialItem) //Sepcial Book Cost: 51.12 }
Some restrictions related to Overriding:
– Cannot override a var with a val or def, doing this is an error:
class Item(var price:Double, var description:String){ var discountedPrice = price override def toString():String = { description+" Cost: "+discountedPrice } } class SpecialItem(price:Double, description:String, var discountPercent:Double) extends Item(price,description){ //This is an error for both def and val override def discountedPrice:Double = { price - ((discountPercent/100) * price) } }
In case there the var in super class is abstract then it can be overridden in the subclass.
– A val in Superclass cannot be overridden by var or def in subclass.
Overriding def with var
A field declared as var can override the def defined in the Superclass. The important thing to note here is that a var can override only a getter/setter pair in the Super class. Let me explain you with an example:
class Item(var price:Double, var description:String){ def discountedPrice_=(discPrice:Double){ price = discPrice} def discountedPrice = price override def toString():String = { description+" Cost: "+discountedPrice } } class SpecialItem(price:Double, description:String, override var discountedPrice:Double) extends Item(price,description){ }
In the above example the Item class has a getter/setter like methods and in the SpecialItem we make use of discountedPrice field which is declared as var to override the discountedPrice getter/setter pair in the Super class. Suppose we remove the override modifier from the discountedPrice field, we would get the following error:
InheritanceTest.scala:10: error: overriding method discountedPrice in class Item of type => Double; variable discountedPrice needs `override' modifier class SpecialItem(price:Double, description:String, var discountedPrice:Double) ^ one error found
These were the few basic concepts related to Inheritance and overriding. We are yet to see how one can declare Abstract classes and also an Interface equivalent in Scala called Traits.