Polymorphism and its types in Scala

Reading Time: 4 minutes

What is Polymorphism :

The simple meaning of polymorphism is a function that has multiple forms. The word Polymorphism is a combination of two words Poly and morphism, poly means many and morphism means form. Functions with the same name are implemented in multiple forms in Polymorphism. The most common use of polymorphism in object-oriented programming occurs when a parent class reference is used to refer to a child class object.

Real-life illustration of polymorphism, a person simultaneously can have various jobs to carry out throughout everyday life. Like a lady simultaneously is a mother, a spouse, a representative, and a girl. So a similar individual must have numerous highlights yet needs to carry out each according to the circumstance and the condition. It is one of the important concepts of the object-oriented programming paradigm.

The advantages of using polymorphism are that it helps to reuse the piece of code. A single variable can be used to store multiple data types. The code is easy to debug.

Types of Polymorphism in Scala:

Scala polymorphism has two main principle forms and the third is similar to generics with a twist:

  1. Subtyping Polymorphism
  2. Generics or Parametric Polymorphism
  3. Ad-hoc Polymorphism

1.) Subtyping :

In subtyping, an instance of a subclass can be passed to a base class in a subclass. We used it in our program when we define super/Parent class or trait and then extend the method in a child class. The vital idea in subtype polymorphism is substitutability as characterized in the Liskov substitution principle. We can perceive a Scala work that displays subtype polymorphism when no less than one of its boundary types has subtypes — that is the point at which it’s a supertype of somewhere around one kind let’s see-through example.

object Calculate extends App{
    trait Shape {
       def Area: Double
    }
    case class Square(side: Double) extends Shape {
        override def Area: Double = side * side
    }
    case class Circle(radius: Double) extends Shape {
       override def Area: Double = Math.PI * radius * radius
    }

     def printArea[T <: Shape](shape: T): Double = (math.floor(shape.Area) * 100)/100

 }


Let’s add a test to capture the expected behavior:

"Shape" should "calculate correct area" in {
    val square = Square(10.0)
    val circle = Circle(12.0)

    assertResult(expected = 10.00)(printArea(square))
    assertResult(expected = 32.19)(printArea(circle))
}


The subtyping relation is written as T <: Shape, to mean that any argument of type T can be safely used in a context where a term of type Shape is expected. We constrain T to the only variable that is a subtype of Shape. So, we say that function printarea() is subtype polymorphic over subtypes of Shape.

2.) Parametric Polymorphism :

Parametric polymorphism is ‘Generics’. The idea is to create data structures and write code that can be generic or type agnostic. We can easily recognize parametric by the presence of one or more type parameters delimited by square brackets in the method signature — they enable us to apply the same logic to different data types polymorphic functions in Scala. Example of Parametric :

object Parametric extends App {

   def Reverse[A](xs:List[A]): List[A] = xs.grouped(2).flatMap(_.reverse).toList

}

We’ve represented the type parameter by the letter A, but we could just as well have used KT, or any other letter — it doesn’t matter. As with all formal parameters, we expect to substitute A during a method call with a concrete type such as IntString, or any other concrete type in our case:

Let’s create a test:

it should "pair-wise reverse lists of any type" in {
    val originalInts = List(1,2,3,4,5)
    val expectedInts = List(2,1,4,3,5)
    val originalStrings = List("a","b","c","d","e")
    val expectedStrings = List("b","a","d","c","e")

    assertResult(expectedInts)(Reverse[Int](originalInts))
    assertResult(expectedStrings)(Reverse[String](originalStrings))

}

Scala compiler can infer the type from the function call argument we pass in. It’s not mandatory that we explicitly pass in the type of argument.

3.) Ad-hoc Polymorphism:

Ad-hoc Polymorphism is similar to generic polymorphism but ad-hoc polymorphism can take different types of arguments, for example, int or string. We can change the behavior of generic code. The compiler switches between various code executions relying upon the type of input a method receives.

See in example:-

object Calculate extends App{

    case class Complex(a: Double, b: Double) {
        def + (result: Complex): Complex = Complex(a + result.a, imaginary + result.b)
        def - (result: Complex): Complex = Complex(a - result.a, imaginary - result.b)
        override def toString: String = s"$a + ${b}i"
}
}

Notice that we can use operators as method names, which actually communicates our intention more clearly, given the context. Secondly, there’s also flexibility in method invocation syntax.

Let’s create a test:

it should "add and subtract complex numbers successfully" in {
    val complex1 = Complex(8.0, 3.0)
    val complex2 = Complex(6.0, 2.0)

    val Sum = complex1 + (complex2)
    val Diff = complex1 - complex2

    assertResult(expected = "14.0 + 5.0i")(actual = Sum.toString)
    assertResult(expected = "2.0 + 1.0i")(actual =  Diff.toString)
}

Notice that we can use postfix notation as in the addition invocation, but Scala also allows us to separate the object, method name, and the argument as in the subtraction invocation where we call (-) as an infix operator. Both are valid syntax in Scala.

Conclusion:

We learned that there are three types of polymorphism in Scala subtyping, generic or parametric, and ad-hoc polymorphism. Subtyping is a standard polymorphism whereas a generic code that normally runs on different types and ad-hoc polymorphism replaces the normal code which runs on the actual type of polymorphism.

References:
https://medium.com/@toidiu/polymorphism-in-scala-8bed74c9ff7c
https://www.scala-exercises.org/scala_tutorial/polymorphic_types

if you find this article interesting, please check out For more blogs click Here

Written by 

Aditya Narayan is a Software Consultant at Knoldus Inc. in Noida. He recently did his B.Tech in Computer Science and Engineering from Abdul Kalam Technical University. He is familiar with C, Html, CSS, Php, JavaScript, and SQL. His hobbies include watching movies, reading books, and traveling in his spare time.