scala implicit (3)

typeclass and implicit

Typeclass comes from Haskell, it defines the behaviors of a type. Recall that type defines the behaviors of a family of values. It comes to rescue when we don’t have control of the code, such as not able to update it directly or add extensions to modify its behavior.

import scala.language.implicitConversions

// A typeclass to display type T
trait Show[T] {
  def show(expr: T): String
}

// A type for showcase
// Assume that it cannot be updated
case class Student(name: String, age: Int)

object Show {
	// An implicit Show[Student] value
  implicit object ShowStudent extends Show[Student] {
    override def show(e: Student): String =
      s"Student{name=${e.name}, age=${e.age}}"
  }

	// An Show[List[A]] value if Show[A] is in scope
  implicit def showList[A: Show]: Show[List[A]] = {
    val showA: Show[A] = implicitly[Show[A]]
    new Show[List[A]] {
      override def show(list: List[A]): String =
        list.map(a => showA.show(a)).mkString("[", ",", "]")
    }
  }

	// show any A if Show[A] is in scope
  def show[A: Show](a: A): String = implicitly[Show[A]].show(a)
}

In above code, we can call Show.showdirectly if an implicit Show instance is in scope.

object App {
  def main(args: Array[String]): Unit = {
    val student1 = Student("Leecy01", 20)
    val student2 = Student("Leecy02", 30)
    println(Show.show(student1))
    println(Show.show(List(student1, student2)))
  }
}

How about we want to call show on Student or List[Student] directly? We can define an implicit convert function and then leverage implicit Show instance to do show action for us.

  trait ShowA {
    def show(): String
  }

  // while Show[A] is in scope we can get a ShowA instance
  implicit def convert[A: Show](a: A): ShowA = new ShowA {
    override def show(): String = implicitly[Show[A]].show(a)
  }

  // can call show directly on type
  student1.show()
  List(student1, student2).show()

But I don’t suggest this way as it seems frustrating for others: where does the show method come from? It's like a new syntax created for old types.