Type classes provide a way of achieving ad hoc
polymorphism. We’ll look at
what they are, why they’re useful, how they’re typically encoded in Scala.
We’ll make our own `Simple`

type class that has a single
operation called `simplify`

returning a
`String`

, and provide instances of it for Scala’s
`List`

and `Int`

classes, along with our own
class `C`

. Finally, we’ll add convenient syntax in the Scalaz
style to make it extremely easy to use the `simplify`

operation. This might be the most hands-on, easy to understand explanation of
type classes you’ve ever encountered!

## Rationale

A common way to express polymorphism in Scala is inheritance. This is brittle
because the polymorphic relationship between supertype and subtype must be
defined where the subtype itself is defined. For example, if you have an
`Animal`

trait, your `Dog`

class must
declare its relationship as a subtype of `Animal`

as part of
its definition. This is problematic when you do not own potential subtypes (i.e.
they’re provided by a library). It also tightly couples the subtype to all of
its implementations of its potential supertypes. A given subtype may already
have all the methods needed to implement the behavior of a given supertype but
doesn’t know or care about the supertype at definition time. Though less common,
another problem is a subtype may be able to implement a supertype’s operations
in multiple, distinct ways (e.g. multiplication and addition implementations of
a Monoid over `Int`

). With inheritance this is impossible.

## Scalaz

Let’s start with one of the simplest type classes in Scalaz:
`Equal`

. `Equal`

describes “a type safe
alternative to universal equality” (if you’re wondering why this is useful or
necessary, ask me in the comments). Here’s an example of providing an instance
of `Equal`

over our own class `C`

that uses
value equality to compare two instances.

```
class C(val name: String)
implicit val equalC: Equal[C] = new Equal[C] {
override def equal(c1: C, c2: C) = c1.name == c2.name
}
```

Now let’s say we want a `notEqual`

method that works on any
`A`

provided there is evidence of
`Equal[A]`

:

```
def notEqual[A: Equal](a1: A, a2: A): Boolean =
!implicitly[Equal[A]].equal(a1, a2)
val c1 = new C("foo")
val c2 = new C("bar")
notEqual(c1, c2)
//=> true
```

Sidenote for those unfamiliar with *context bounds*: the context bound ```
[A:
Equal]
```

is what ensures we have an implicit
`Equal[C]`

instance available when running ```
notEqual(c1,
c2)
```

. An equivalent and perhaps more clear implementation
without context bounds would look like this:

```
def notEqual[A](a1: A, a2: A)(implicit e: Equal[A]) = !e.equal(a1, a2)
notEqual(c1, c2)
//=> true
```

However, there’s an even more concise way of writing this using context bounds
and Scalaz’ `/==`

operator for instances of
`Equal`

, or even its unicode `≠`

alias:

```
def notEqual[A: Equal](a1: A, a2: A): Boolean = a1 /== a2
// or
def notEqual[A: Equal](a1: A, a2: A): Boolean = a1 ≠ a2
```

Since Scalaz already provides these operators, `notEqual`

is purely
didactic.

Another common typelcass in Scalaz is `Show`

. This corresponds
to Haskell’s `Show`

type class, and is used to indicate a
type that can be represented in some way as a string, e.g. for logging or
printing in a REPL. Here’s an instance for our `C`

class
example from before.

```
implicit val showC: Show[C] = new Show[C] {
override def show(c: C) = s"C[name=${c.name}]"
}
```

Scalaz provides syntax helpers that allow us to simply call
`.show`

on any type that provides evidence of
`Show`

. We’ll look at how that works in detail toward the end.

```
new C("qux").show
//=> res22: scalaz.Cord = C[name=qux]
```

## Simple

Now that we’ve gotten a taste for using a few of Scalaz’ type classes, let’s build our own, along with some syntax helpers in the Scalaz style.

```
trait Simple[F] {
def simplify(f: F): String
}
```

This is our type class definition. It defines a single operation
`simplify`

for a given `F`

and returns a
`String`

. Before we provide instances, let’s define a method
that expects a `Seq`

of `Simple`

instances
and outputs them separated by newlines.

```
def manySimple[A](simples: Seq[A])(implicit s: Simple[A]): String =
"Many simples:\n\t" + simples.map(s.simplify).mkString("\n\t")
```

We can use this to easily try out instances. Let’s start with an instance of
`C`

:

```
implicit def simpleC: Simple[C] = new Simple[C] {
override def simplify(c: C) = s"Simplified: ${c.show}"
}
```

We can manually call this by implicitly obtaining a
`Simple[C]`

then calling `simplify`

:

```
implicitly[Simple[C]].simplify(new C("hello"))
```

Or we can try out the `manySimple`

method:

```
manySimple(Stream(new C("foo"), new C("bar"), new C("qux")))
//=> Many simples:
//=> Simplified: C[name=foo]
//=> Simplified: C[name=bar]
//=> Simplified: C[name=qux]
```

Let’s try another one: `Int`

.

```
implicit val simpleInt: Simple[Int] = new Simple[Int] {
override def simplify(i: Int) = s"Simplified Int with value of $i"
}
```

This is getting easy, right?

```
implicitly[Simple[Int]].simplify(123)
//=> Simplified Int with value of 123
```

We can even provide an instance for `List[A]`

but only if
`A`

itself has a `Simple`

instance:

```
// Evidence for Simple[List[A]] given evidence of Simple[A]
implicit def simpleList[A: Simple]: Simple[List[A]] = new Simple[List[A]] {
override def simplify(l: List[A]) = {
val simplifyA = implicitly[Simple[A]].simplify _
s"Simplified list:\n${l.map(simplifyA).mkString("\n")}"
}
}
```

Try it out:

```
implicitly[Simple[List[Int]]].simplify((1 to 5).toList)
//=> Simplified list:
//=> Simplified Int with value of 1
//=> Simplified Int with value of 2
//=> Simplified Int with value of 3
//=> Simplified Int with value of 4
//=> Simplified Int with value of 5
```

Hopefully you have a feel for how this works (ignoring how unuseful our
`Simple`

is IRL). Next, let’s follow Scalaz lead and
provide some convenient syntax for working with our new type class; typing
`implicitly[Simple[_]]`

over and over again is starting to get
old.

## Syntax

Wouldn’t it be nice if we could just call `.simplify`

on objects which provide
evidence of a `Simple`

? Well, we can via some neat implicit
tricks. Check it out:

```
final class SimpleOps[F](val self: F)(implicit val F: Simple[F]) {
final def /^ = F.simplify(self)
final def ⬈ = F.simplify(self)
}
trait ToSimpleOps {
implicit def ToSimpleOps[F](v: F)(implicit F0: Simple[F]) =
new SimpleOps[F](v)
}
object simple extends ToSimpleOps
trait SimpleSyntax[F] {
def F: Simple[F]
implicit def ToSimpleOps(v: F): SimpleOps[F] =
new SimpleOps[F](v)(SimpleSyntax.this.F)
}
// New definition of our Simple typeclass that provides an instance of
// SimpleSyntax
trait Simple[F] { self =>
def simplify(f: F): String
val simpleSyntax = new SimpleSyntax[F] { def F = Simple.this }
}
```

Here we’ve provided two syntax operators as aliases to
`simplify`

(because no type class is legit without unicode
operator aliases).

```
import simple._
1 ⬈
//=> Simplified Int with value of 1
new C("I am C") ⬈
//=> Simplified: C[name=I am C]
List(1,2,3) ⬈
//=> Simplified Int with value of 1
//=> Simplified Int with value of 2
//=> Simplified Int with value of 3
// boring
new C("bar") /^
//=> Simplified: C[name=bar]
```

## Conclusion

Type classes are a powerful method of adding support for a set of operations on an existing type in an ad hoc manner. Because Scala doesn’t encode type classes at the language level, there is a bit of boilerplate and implicit trickery to create your own type classes (compare this with Haskell, where classes are elegantly supported at the language level) and operator syntax.

View the full code listing for this post.

### Further reading

- Introduction to Typeclasses in Scala (2013)
- Types and Typeclasses — Learn you a Haskell
- Simalacrum — a modern, concise type class encoding for Scala using annotations
- Typeclassopedia — overview of Haskell’s type classes, many of which are also represented in Scalaz, along with a very useful diagram showing relationships between type classes.