Skip to content

Instantly share code, notes, and snippets.

@anoopelias
Last active December 7, 2021 23:42
Show Gist options
  • Save anoopelias/4507041 to your computer and use it in GitHub Desktop.
Save anoopelias/4507041 to your computer and use it in GitHub Desktop.
What is the fuzz about Type Classes? #scala

Assume you have a couple of classes,

case class Person(name: String, age: Int)
case class Employee(person: Person, salary: Double)

Lets say for some reason,

  • You don't want to change this source, but
  • You should be able to add features save(person) and save(employee), and
  • You need clearly separate implementations for both the types,

You start by defining a type class,

trait DBObject[T] {
  def save(t: T)
}

Then you define an implementation for each of your types as implicit objects,

implicit object PersonDBO extends DBObject[Person] {
  def save(p: Person) = //Do whatever you need to do to save p: Person  
}

implicit object EmployeeDBO extends DBObject[Employee] {
  def save(e: Employee) = //Do whatever you need to do to save e: Employee  
}

And then you define your one single generic save method,

def save[T](obj: T)(implicit dbo: DBObject[T]) = dbo.save(obj)

From then onwards you can use save(employee) to save employees, and save(person) to save persons.

Also, if you noticed, let's say you want to add a new type Company. You can give an implicit save implementation for that one as well in your most recent part of the code, without touching any of the code you have already written!

case class Company(name: String, employees: List[Employee])

implicit object CompanyDBO extends DBObject[Company] {
  def save(c: Company) = //Do whatever you need to do to save c: Company  
}

Any other goodies you can think about for Type Classes?

@anoopelias
Copy link
Author

Improving this further,

Instead of defining PersonDBO object, let us implement a PersonDBO class along with implicit type conversion.

Firstly this would mean you need to define your type class slightly differently,

trait DBObject[T] {
    def save()
}

And your dbo object as,

class PersonDBO(p: Person) extends DBObject[Person] {
    def save() = //Do what you need to do to save p:Person
}

implicit def dboOf(p: Person) = new PersonDBO(p)

Which will then let you call

val p: Person = ...
p.save()

@anoopelias
Copy link
Author

Scala 2.10 adds sugar by introducing 'implicit classes' reducing the class and implicit definition in the above comment to,

implicit class PersonDBO(p: Person) extends DBObject[Person] {
    def save() = //Do what you need to do to save p:Person
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment