Scala Context Bounds as 'Has-A' Relationship

How to understand the meaning of context bounds as a relationship

Context bounds is a well-known Scala construct. It can simplify your code, help constructing type classes or obtaining a TypeTag. But how can it be easily read and understood while reading the code?

Basically, context bounds can be seen as a shorthand notation for an additional implicit parameter. Thus the following definitions are equivalent:

def f[A : B](a: A) = ???
def f[A](a: A)(implicit b: B[A]) = ???

But what it really means to define a type with context bounds, how it can be easily understand? Let’s start with an example:

case class Planet(name: String)
trait Destroyer[T] {
  def destroy(t: T)
}

We’ve defined a case class Planet and a type-parametrized trait Destroyer. How about destroying a whole planet? 😈 We will need a powerful wepon.

  implicit val deathStar: Destroyer[Planet] = (p: Planet) => println(s"${p}: BOOOM!")

Here we go! And now we would like to use the wepon, in fact we could make a method for using any available Destroyer to destroy specific type of objects:

def useDeadlyWepon[A : Destroyer](something: A) = {
  implicitly[Destroyer[A]].destroy(something)
}

And what we got here is a method that accepts any object of type A which has a Destroyer or we could say, type A for which there is a Destroyer, meaning Destroyer[A]. Using this kind of understanding of context bounds, we can more easily read the source code.

In this example, implicitly looks in the scope for an explicit value with the specified type, hence invoking the useDeadlyWepon method with a parameter of type Planet will use the deathStar internally:

useDeadlyWepon(Planet("Alderaan"))
// Planet(Alderaan): BOOOM!

Context bounds can be combined with lower / uper bounds, e.g. let’s make a method for sorting animals, it can accept any Animal type, which has or for which there is an Ordering defined.

trait Animal {
  val name: String
}
implicit val byName: Ordering[Animal] = (x: Animal, y: Animal) => x.name.compare(y.name)

def sortAnimals[A <: Animal: Ordering](as: Seq[A]): Seq[A] = as.sorted

Quite intuitive, isn’t it?

I’ve found the idea in this great comment on StackOverflow and I wanted to share it, since reading it was one of my aha-moments, which greatly simplified the way I am able to read Scala code.

meme