mercredi 16 mai 2018

Scala Type Class pattern vs Pattern Matching or Overloading

I'm struggling to come up with a good mental model for when is a problem a good fit for the Type Classes pattern?

Recently I was working with a model like

sealed trait FooBar
case class Foo() extends FooBar
case class Bar() extends FooBar

Intuitively I would simply pattern match

def handle(x: FooBar) = x match {
  case f: Foo => println("foo")
  case b: Bar => println("bar")
}

or use subtyping/overloading explicitly like

object Overloading {
  def handle(x: Foo) = println("foo")
  def handle(x: Bar) = println("bar")
}

On the other hand, the type class approach is verbose and I don't see any benefit from using it:

trait FooBarThing[T <: FooBar] {
  def handle(x: T): Unit
}

object TypeClass {

  implicit object HandleFoo extends FooBarThing[Foo] {
    def handle(x: Foo) = println("foo")
  }

  implicit object HandleBar extends FooBarThing[Bar] {
    def handle(x: Bar) = println("bar")
  }

  def process[T <: FooBar](x: T)(implicit ev: FooBarThing[T]): Unit = {
    ev.handle(x)
  }
}

I've found many articles explaining how to write type classes but not much on when?

Aucun commentaire:

Enregistrer un commentaire