Understanding the implementation of type classes

I was following this page to understand implementing type class in scala (ad-hoc polymorphism).

At one point the author changes this line

def show[A](a: A)(implicit sh: Show[A]) = sh.show(a)


def show[A: Show](a: A) = implicitly[Show[A]].show(a)

the code show(12) works in both the cases.

The second case expects A to be of type Show. But Int is not of type Show. But still show[Int](12) works. How?

The second statement is not saying that A is of type Show, but is a context bound which declares that there is an implicit object of type Show[A] in scope. Then implicitly[Show[A]] returns this implicit object.


Also note, that implicitly is also just a simple method taking an implicit parameter and returning it:

def implicitly[T](implicit e: T) = e

So a context bound is especially useful, when you do not need to use the implicit value directly (like in your example) but only call methods that use it, because then you can remove the second parameter list without changing your implementation. When using it like here, I personally prefer to give it a name in the parameter list.

Echoing the other comments, I find it helpful to pronounce [A: Show] as “A has a Show”. (As opposed to “A is a Show”.) It isn’t a subclass of Show, but there is a Show for it.

And note that this:

def show[A: Show](a: A)

desugars to roughly:

def show[A](a: A)(implicit $ev: Show[A])

They really are functionally identical, it’s just the one gives you a useful name for the implicit and the other doesn’t.