What is a Type Class And How To Create Them In Scala

Reading Time: 2 minutes

What are Type Classes

A type class is an interface that defines some behavior. Simply put, it is a programming technique that we often use to add new behaviors to existing user-defined data types without altering the source code.

Need for Type Class

While working on projects we often feel the need to add new behaviors to our user-defined types. A naive way to do it is to directly alter the source code.

Type class is a programming technique that allows us to add new behaviors to closed data types without using inheritance and without having access to the original source code of those types.

Problem Statement

We have an Employee case class.

sealed trait Person

case class Employee(name: String, experience: Int) extends Person

Now we will add a method promote to the employee object that simply prints if the employee is eligible to be promoted or not using his/her experience.

def promote(args...): Unit = {
    /* Logic to determine whther the employee can be promted based on years of experience */

What we want is to be able to call this method like it belongs to the Employee class:

val emp = Employee("Prakhar")
emp.promote

3 Steps to create Type Classes in Scala

The process involves the creation of the following components:

  • A trait with at least one generic type which will be the Type class
  • An instance of the type class for the specific type that we want to extend
  • Extension methods for the new functionality

Step 1: Creating the type class

The first step involves the creation of a generic trait with the behavior that we want to add to the Employee class

trait ExperiencedPerson[T] {
  def promote(person: T): Unit
}

Step 2: Creating instance of the type class

Next, we make an instance and provide it with the behavior that we want to add to the Employee class

object ExperiencedPersonInstance {
  implicit val experiencedEmployee: ExperiencedPerson[Employee] = new ExperiencedPerson[Employee] {
    override def promote(employee: Employee): Unit = {
      if(employee.experience > 3) println("I am experienced enough to be promoted.")
      else println("I do not have enough experience to be promoted.")
    }
  }
}

Step 3: Creating the extension method

We write a method that will expose our newly created functionality and the goal is to access the methods directly from the instances of the Employee class.

To achieve this we make use of the Implicit classes.

object ExperiencedPerson {
  import ExperiencedPersonInstance.experiencedEmployee

  implicit class Promote[T](person: T) {
    def promote(implicit experiencedPerson: ExperiencedPerson[T]): Unit = {
      experiencedPerson.promote(person)
    }
  }
}

Main Class

In the code written above we see how to add a new method for the Employee class.

Next, we see how we can access the method as if it belongs to the Employee class

object Main extends App {
  import ExperiencedPersonInstance.experiencedEmployee
  import ExperiencedPerson._

  val emp = Employee("Prakhar", 5)
  emp.promote
}

Output

Here, the employee has experience of more than 3 years and so he is eligible to be promoted.

Conclusion

So in this blog, we create a type class in Scala and learn how to use them to extend the functionality of our Employee class.

We can now create more extensions in a similar way and add new behaviors without tinkering with the source code.

knoldus