I am working through the Scala with Cats book and I am wondering how the library implements some functionality that is described in an example. Specifically it is about automatically generating an implicit class from an existing type class definition using implicit conversion.
I am specifically referring to exercise 1.4.6 in the Scala with Cats book. For completeness, I have reproduced the code below.
import cats.Show
import cats.instances.int._
import cats.instances.string._
import cats.syntax.show._
final case class Cat(name: String, age: Int, color: String)
implicit val catShow = Show.show[Cat] { cat =>
val name = cat.name.show
val age = cat.age.show
val color = cat.color.show
s"$name is a $age year-old $color cat."
}
println(Cat("Garfield", 38, "ginger and black").show)
I understand everything about this example except the last line. The catShow implicit only defines the type class. It does not define what the Scala with Cats book refers to as "interface syntax." That is, it does not define the implicit class that would be needed to get the last line to work.
That implicit class would look something like this:
implicit class showCat(in: Cat) {
def show: String = s"${in.name}, ${in.age}, ${in.color}"
}
Obviously, I have not defined this implicit class anywhere, meaning it must be generated automatically. I am thinking it must use some kind implicit conversion that converts from the Show[Cat] instance to the implicit class I have created above.
However, I am not sure how to write this implicit class conversion and was wondering if anyone could help me out, either by describing how the Cats library implements this, or by writing out the code for an implementation that would do the job equally well.
For additional context, please refer to the Scala with Cats book available for free here: https://books.underscore.io/scala-with-cats/scala-with-cats.html
Such implicit class could look like generic
implicit class ShowOps[A: Show](in: A) {
def show: String = implicitly[Show[A]].show(in)
}
rather than specific
implicit class showCat(in: Cat) {
def show: String = s"${in.name}, ${in.age}, ${in.color}"
}
so it's not necessary for implicit conversion to know about Cat
.
Actually with import cats.syntax.show._
you import something similar.
https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/syntax/package.scala#L55
https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/syntax/show.scala
https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/Show.scala#L23-L34