# Type Classes and the Expression Problem

The Expression Problem describes a trade-off between OOP and FP, in which adding functionality requires changing existing code:

New Functionality OOP FP
Add a new data type implementation No Changes Changes
Add behavior to an existing data type Changes No Changes

Type classes help avoid this trade-off by allowing us to add both new data type implementations and new behaviors for existing data types without needing to change existing code.

Given a `Shape` type and a couple of implementations:

``````trait Shape
case class Circle(radius: Double) extends Shape
case class Square(side: Double) extends Shape``````

We can write a type class to compute the area of each shape:

``````trait Area[A] {
def area(x: A): Double
}

object Area {
def of[A : Area](x: A): Double =
implicitly[Area[A]].area(x)
}

implicit object CircleArea extends Area[Circle] {
}

implicit object SquareArea extends Area[Square] {
override def area(x: Square): Double = x.side * x.side
}``````

We can add a new data type implementation `Triangle`, and an `Area` instance for it:

``````case class Triangle(base: Double, height: Double) extends Shape

implicit object TriangleArea extends Area[Triangle] {
override def area(x: Triangle): Double = 0.5 * x.base * x.height
}``````

We can also add new behavior to compute the perimeter of each of our shapes:

``````trait Perimeter[A] {
def perimeter(x: A): Double
}

object Perimeter {
def of[A : Perimeter](x: A): Double =
implicitly[Perimeter[A]].perimeter(x)
}

implicit object CirclePerimeter extends Perimeter[Circle] {
override def perimeter(x: Circle): Double = 3.14 * x.radius * 2
}

implicit object SquarePerimeter extends Perimeter[Square] {
override def perimeter(x: Square): Double = x.side * 4
}``````

## Example

``````println(s"Area.of(Circle(2)): \${Area.of(Circle(2))}")
println(s"Area.of(Square(3)): \${Area.of(Square(3))}")
println(s"Area.of(Triangle(4, 5)): \${Area.of(Triangle(4, 5))}")
println(s"Perimeter.of(Circle(2)): \${Perimeter.of(Circle(2))}")
println(s"Perimeter.of(Square(3)): \${Perimeter.of(Square(3))}")``````

## Demo

This file is literate Scala, and can be run using Codedown:

``````\$ curl https://earldouglas.com/posts/type-classes/expression.md |
codedown scala | xargs -0 scala -nc -e
Area.of(Circle(2)): 12.56
Area.of(Square(3)): 9.0
Area.of(Triangle(4, 5)): 10.0
Perimeter.of(Circle(2)): 12.56
Perimeter.of(Square(3)): 12.0``````