Scalera tip: Uncle SAM

Today’s Scalera tip (and it’s been a while since last published tip) is about one of the Scala 2.12 version features that we fancy the most regarding the possibility of avoiding too much boilerplate.

Uncle SAM

Let’s suppose we’ve defined a type class that gathers certain amount of common implemented functionality like:

trait Comparisson[T]{

  def compare(t1: T, t2: T): Int

  def greaterThan(t1: T, t2: T): Boolean =
    compare(t1, t2) > 0

  def greaterEqualThan(t1: T, t2: T): Boolean =
    compare(t1, t2) >= 0

  def equalTo(t1: T, t2: T): Boolean =
    compare(t1, t2) == 0

  def lowerThan(t1: T, t2: T): Boolean =
    compare(t1, t2) < 0

  def lowerEqualThan(t1: T, t2: T): Boolean =
    compare(t1, t2) <= 0

  
}

…in that case the remaining job would consist on defining the compare method.
For creating the different instances of Comparisson we could either create implicit vals or implicit objects (nothing new about type classes so far):

object Comparisson {

  implicit val intComparisson: Comparisson[Int] =
    new Comparisson[Int]{
      def compare(t1: Int, t2: Int): Int = t1 - t2
    }

  implicit val booleanComparisson: Comparisson[Boolean] =
    new Comparisson[Boolean] {
      def compare(t1: Boolean, t2: Boolean): Int = {
        List(t1, t2)
          .map(b => if (b) 1 else 0)
          .reduce(_ - _)
      }
    }

}

Defining anonymous Comparisson instances (or extending from that trait in case of objects) was the only way of defining these instances so far.

With Scala’s 2.12 version a new concept known as SAM (Single Abstract Method) comes up. It basically allows defining an anonymous instance by providing a function equivalent to the only abstract method of the trait/abstract class.

When applying to the proposed example:

object Comparisson {

  implicit val intComparisson: Comparisson[Int] =
    (t1: Int, t2: Int) => t1 - t2

  implicit val booleanComparisson: Comparisson[Boolean] =
    (t1: Boolean, t2: Boolean) =>
      List(t1, t2)
        .map(b => if (b) 1 else 0)
        .reduce(_ - _)

}

Cute, right? Just as a reminder, do have in mind that if we don’t explicitly type the expression, the compiler won’t understand that it has to do its magic and it will assume that what we’ve just implicitly defined is a mere function:

object Comparisson {
  
  implicit val intComparisson =
    (t1: Int, t2: Int) => t1 - t2

  //  The previous inferred type will be (Int, Int) => Int

}

And we’re not telling this because it already happened to us…

Peace out!

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s