Scala Trait: The Magnificent feature that enables Multiple Inheritance

Knoldus Blog Audio
Reading Time: 5 minutes
Scala Trait Introductory Image

In this blog, we will discuss Scala Trait and how it helps us to implement multiple inheritance in Scala and to increase code reusability.

What is Trait?

According to the dictionary, a Trait is a distinguishing property or feature, typically one belonging to a person or genetically determined characteristics.

In Scala, Trait encapsulates methods and field definitions that can be re-used by extending them into classes. As Scala doesn’t allow multiple inheritance, so to overcome this Scala trait comes into the picture.

Traits are used to define object types by specifying the signature of the supported methods. A trait is like an interface with partial implementation. Traits are a collection of abstract and non-abstract methods. We can create a trait that can have all abstract methods or some abstract and some non – abstract methods.

Traits are used to share interfaces and fields between classes. Classes and objects can extend traits, but traits can not be instantiated and therefore have no parameters.

How the Scala traits are defined?

Traits are defined just like a class definition except that it uses the keyword trait.

trait Trait_Name {
//Methods
//Fields
}

Now, we will create a trait consisting of two methods sum and multiply. One will be abstract and the other will be non-abstract and we will extend the trait to a class where we can override the abstract method of the sum.

After that, we will create an object class that will implement the methods defined. So we will create an object of Calculator class and using that object we will call the methods of sum and multiply.

//A Calculator trait consisting of two methods one is abstract and another is non-abstract.
trait TraitCalculator {
  //Abstract Method to sum two numbers
  def sum(valueOne: Int, valueTwo: Int): Int

  // Non-abstract method to multiply two numbers
  def multiply(valueOne: Int, valueTwo: Int): Int = {
    val result = valueOne * valueTwo
    result
  }
}
//Calculator class extending the Trait Calculator

class Calculator extends TraitCalculator {
  // overriding the sum method of trait class.
  override def sum(valueOne: Int, valueTwo: Int): Int = {
    val result = valueOne + valueTwo
    result
  }

//An object class to implement the trait.
object CalculatorImplementation extends App {
// Creating a object of the Calculator class which have extended the trait      TraitCalculator

  val calculatorImpl = new Calculator

  //Using the object calculatorImpl we have called the abstract method sum.

  print(calculatorImpl.sum(2,3) + "\n")

  //Using the object calculatorImpl we have called the non abstract method multiply

  print(calculatorImpl.multiply(2,4) + "\n")

}

Now, Lets see how traits helps Scala in implementing multiple inheritance.

Implementation of Multiple Inheritance in Scala Using Trait

So, We will explain the implementation of multiple inheritance in Scala using an example. For this, we will create two traits for Queue and Stack.

Trait Queue

Queue trait will contain two non-abstract methods of enqueue and dequeue. Enqueue method will insert the item to the queue at the rear position and increase the value of the rear by one and the dequeue method will remove the item from the front of the queue and increase the value of the front by one following the property of First In First Out(i.e., FIFO).

trait Queue {
  var queue:List[Double] = List.empty
  var front: Int = -1
  var rear: Int = -1
  /* Here we are defining enqueue method which will enqueue the  item to the queue     following the property of FIFO.*/
  def enqueue(item: Double): String = {
    if(rear == -1 && front == -1) {
      front = front + 1
      rear = rear + 1
      queue = queue ::: List(item)
      "Item is enqueued."
    }
    else{
      rear = rear + 1
      queue = queue ::: List(item)
      "Item is enqueued.."
    }
  }
  /* Here we are defining dequeue method which will dequeue the  item from the queue following the property of FIFO.*/
  def dequeue: String = {
    if(front == -1 && rear == -1){
      "Underflow.."
    }
    else if(front == rear ){
      queue=queue.drop(1)
      front = -1
      rear = -1
      "Item dequeued.."
    }
    else{
      queue = queue.drop(1)
      front = front + 1
      "Item dequeued.."
    }
  }
  /* Here we are defining the getQueue method that will return the queue.
  * */
  def getQueue: List[Double] = {
    queue
  }
}

Trait Stack

Stack trait will also contain two non-abstract methods push and pop. The push method will push the item to the stack at the top position and increase the value of the top by one. And the pop method will remove the item from the stack at the top position and decrease the value of the top by one following the property of Last In First Out (i.e., LIFO).

trait Stack{
  var stack: List[Double] = List.empty
  var top: Int = -1
  /* Here we are defining push method which will push the  item to the stack following the property of LIFO.*/
  def push(item: Double): String = {
    top = top + 1
    stack = stack ::: List(item)
    "Item is pushed to stack.."
  }
  /* Here we are defining pop method which will pop the  item from the Stack following the property of LIFO.*/
  def pop(): String = {
    if(top == -1){
      "Stack Underflow.."
    }
    else{
      stack = stack.dropRight(1)
      top = top - 1
      "Item is popped from the stack.."
    }
  }
  /* Here are defining getStack method that will return the stack.
  * */
  def getStack: List[Double] = {
    stack
  }
}

Extending Both Traits To The Main class

So, here comes the beauty of traits that enables multiple inheritance in Scala. In this object, we have extended two traits using the keywords extends and with.

object TraitImplementation extends Queue with Stack with App {

  /* Here we are overriding the enqueue method to create a double queue.
   * The item enqueued will be double of that we have given as a input to the method.*/
  override def enqueue(item: Double): String = {   
    if(rear == -1 && front == -1) {
      front = front + 1
      rear = rear + 1
      val doubleOfItem = 2 * item         // creating a double of the item.
      queue = queue ::: List(doubleOfItem)
      "Item is enqueued.."
    }
    else{
      rear = rear + 1
      val doubleOfItem = 2 * item         // creating a double of the item.
      queue = queue ::: List(doubleOfItem)
      "Item is enqueued.."
    }
  }
  /* Here we are overriding the push method to create a square stack.
   * The item pushed will be square of the input that has been provided as a parameter to the function.
   * */
  override def push(item: Double): String = {
    top = top + 1
    val squareOfItem = scala.math.pow(item,2) // creating a square of the input.
    stack = stack ::: List (squareOfItem)
    "Item is pushed to stack.."
  }

This object has extended the Queue trait along with Stack trait.

In the above implementation, we have overridden the enqueue method of trait Queue to create a Double queue. The item enqueued will be double what we have given as an input to the method. This means if we give 2 as input then 4 will be enqueued.

Likewise, we have also overridden the push method of trait Stack to create a Square stack. The item pushed will be square of what we have given as an input to the method. This means if we give 4 as input then 16 will be pushed.

After executing the main method of object TraitImplementation, the following output will be produced.

Output produced after implementing main method .

Conclusion

In this blog, we have learned about the Scala traits, how it enables multiple inheritance in Scala. We have implemented multiple inheritance by inheriting two traits in a single class in Scala.

References

https://docs.scala-lang.org/tour/traits.html

Knoldus-blog-footer-image

1 thought on “Scala Trait: The Magnificent feature that enables Multiple Inheritance6 min read

Leave a Reply

%d bloggers like this: