Petr Novak
Feb 23, 2017 · 1 min read

For our own types I would recommend to place typeclass implementations into companion object. This way when importing e.g. Circle it automatically imports its implicit typeclass instances. This way it is as seamless as when using subtyping.

case class Circle(radius: Double)object Circle {
implicit object CircleShape extends Shape[Circle] {
override def area(circle: Circle) : Double = ???
}
}

There is similarity to subtyping:

class Circle(radius: Double) extends Shape {
override def area: Double = ???
}

To find all type relations we look at both, type declaration to find subtype relations and into companion object to find which typeclasses are implemented. Implicits should be at the top of companion object so that they can be found as easily as “Circle extends Shape”.

Unlike plain traits, typeclasses allows to implement given behaviour for any type we don’t have under control and can’t add “extends Shape” to it. This way we can use these types in polymorphic code without loosing their identity by wrapping them into adapters.

    Petr Novak

    Written by