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

Scalera tip: El tío SAM

En el tip de Scalera de hoy (y ha llovido ya un tanto desde el último que publicamos) hablaremos sobre una de las features de Scala 2.12 que nos ha parecido bastante interesante de cara a evitar escribir boilerplate

El tio SAM

Supongamos que hemos definido una type class que tiene bastante funcionalidad común del tipo:

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

  
}

…en cuyo caso solo nos restaría definir el método compare.
Para crear las distintas instancias de Comparisson bien podemos crear implicit vals o implicit objects (hasta aquí nada nuevo sobre type classes en Scala):

object Comparission {

  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(_ - _)
      }
    }

}

Definir instancias anónimas de Comparisson (o extender de dicho trait para el caso de objects) era la única forma de definir estas instancias hasta el momento.

Con la versión 2.12 de Scala surge el concepto de SAM (Single Abstract Method) que básicamente permite definir una instancia anónima aportando una función de orden superior equivalente al único método abstracto en el trait/abstract class.

Si aplicamos al caso anterior quedaría algo como:

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(_ - _)

}

Cuqui, ¿no? Simplemente como recordatorio, tened en cuenta que si no anotamos el tipo de manera específica, el compilador no entiende que tiene que hacer su magia y asumira que lo que hemos definido de manera implícita es una función:

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

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

}

Y no es que lo recordemos porque nos haya pasado a nosotros….

¡Agur de limón!

Seven deadly sins of lambda expressions

A few weeks ago, we talked about lambda expressions. We learnt how to use them and some of the advantages they offer.

But, as the old saying goes, all that glitters is not gold. Last April, Jamie Allen came to our Scala meetup in Madrid and spoke about the dark sideof lambda expressions: “What you need to know about lambdas”. In this post we’ll give you an overview of that talk and support the fact that lambda expressions are not to be taken lightly.

First problem: Not reusable.

As a name is not being given to the function, we won’t be able to use it anywhere else in the code.

Second problem: Cannot be tested in isolation.

Provided that it is an ad-hoc function, implemented and embedded at some specific point, it cannot be tested in a separate way.

Third problem: Maintainance.

In general, it is not good practice to use excessive complicated and nested lambda expressions. With them, our code becomes somewhat obscured and thus, difficult to follow and maintain.

List(1, 2, 0, 3, 4).flatMap(
  x => (1 to x).filter(
    _ % 2 == 0
  ).map( _ * 2 )
)

//List(4, 4, 4, 8)

Fourth problem: error messages.

This problem varies depending on the programming language used. In some cases, error messages will be manageable and in many others, you may feel the desire to slice your wrists off. In our case, in Scala, when there’s an error in an anonymous function we’ll get an error like this:

List(1, 2, 0, 3, 4).map(1 / _)

java.lang.ArithmeticException: / by zero
at $anonfun$1.apply$mcII$sp(<console>:8)
at $anonfun$1.apply(<console>:8)
at $anonfun$1.apply(<console>:8)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.immutable.List.foreach(List.scala:318)
...

Given that no name was given to the function, the system will throw the error in a $$anonfun. A bit of a WTF, isn’t it?

Fifth problem: Hard time debugging.

Actually, this is not a particular problem of lambda expressions but of the way the code is expressed when using them. If several lambda expressions are written in the same line and there’s an error in any of them, we won’t be able to know which one is causing trouble. That’s why it is highly convenient to separate them in several lines.

The expression

List(1, 2, 0, 3, 4).map(_ + 1).filter(_ % 2 == 0).map(_ * 2)

would be better written this way:

List(1, 2, 0, 3, 4).map(_ + 1)
  .filter(_ % 2 == 0)
  .map(_ * 2)

Sixth problem: they can encapsulate variables with state

Lambda expressions can access the whole state of their scope. Therefore, they might have access to some mutable value and lead to different results in different execution contexts. Something that we definitely don’t want in functional programming.

Seventh problem … 

Their problems can be enclosed into just six statements and lead to inconsistent post titles…

desk_flip

Conclusion

As we have seen, the use of lambda expressions may give rise to a few headaches. That’s why it is recommended to only use those ones which are less complex. In case we want to do something more sophisticated or intricate, the best thing to do is to define a method in order to test and debug it without any trouble. Besides, special precautions shall be taken not to use scope variables that may change its value. We should not deviate from our functional perspective.

I heartily recommend you to take a look at the talk . Many more details were treated in it (this post is just a brief overview) and it might help us to work with lambda expressions in a better way.

Los 7 pecados capitales de las expresiones lambda

Hace unas semanas estuvimos hablando de expresiones lambda. Vimos como utilizarlas y algunas de las ventajas que ofrecen.

Sin embargo, no es oro todo lo que parece. El pasado mes de Abril, Jamie Allen vino al meetup de Scala en Madrid y nos habló del lado oscuro de las expresiones lambda: “What you need to know about lambdas”. En este post vamos a hacer un overview de la charla, y corroborar que no podemos usar expresiones lambda de cualquier manera.

Primer problema: No es reutilizable

Debido a que no estamos poniendo nombre a la función, no podremos reutilizarla en otros lugares.

Segundo problema: No se puede testear de forma aislada

Como es una función implementada de forma ad-hoc, e incrustada en algún lugar, no es posible probarla de forma aislada.

Tercer problema: Mantenimiento

No es bueno abusar de expresiones lambda complicadas y anidadas. Provoca que nuestro código se vuelva dificil de seguir, y por tanto, poco mantenible.

List(1, 2, 0, 3, 4).flatMap(
  x => (1 to x).filter(
    _ % 2 == 0
  ).map( _ * 2 )
)

//List(4, 4, 4, 8)

Cuarto problema: trazas de error

Este problema varía en función del lenguaje de programación que se utilice. En algunos casos las trazas de error serán mejores y en otros casos te darán ganas de cortarte las venas. En nuestro caso, en Scala, cuando aparece un error en una función anónima obtendremos un mensaje de error con esta pinta:

List(1, 2, 0, 3, 4).map(1 / _)

java.lang.ArithmeticException: / by zero
at $anonfun$1.apply$mcII$sp(<console>:8)
at $anonfun$1.apply(<console>:8)
at $anonfun$1.apply(<console>:8)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.immutable.List.foreach(List.scala:318)
...

Debido a que no se ha dado nombre a la función, el sistema nos devolverá un error en un $$anonfun. Un poco WTF.

Quinto problema: Dificultad para depurar

Realmente no es un problema propio de las expresiones lambda, sino de la forma de expresar el código.
Si encadenamos varias expresiones lambda en la misma línea y existe algún error en alguna de ellas, no podremos saber cual de ellas ha fallado. Por ello es conveniente separarlas en varias líneas.

La expresión

List(1, 2, 0, 3, 4).map(_ + 1).filter(_ % 2 == 0).map(_ * 2)

será mejor expresarla de esta forma:

List(1, 2, 0, 3, 4).map(_ + 1)
  .filter(_ % 2 == 0)
  .map(_ * 2)

Sexto problema: Puede encapsular variables con estado

Una función lambda puede tener acceso a todo el estado de su scope. Por tanto, puede tener acceso a algún valor mutable y hacer que tengamos diferentes resultados en cada ejecución. Algo que no queremos en la programación funcional.

Séptimo problema …

Sus problemas se pueden encapsular en solo seis y provocan que algunos títulos de post no encajen del todo.

desk_flip

Conclusión

Como hemos podido ver, usar expresiones lambda puede originar algunos quebraderos de cabeza. Por ello se recomienda usar solo aquellas que tengan una baja complejidad. En caso de que queramos hacer algo más complejo o enrrevesado será mejor definir un método para poder testearla y depurarla sin ningún tipo de problema. Además, hay que tener especial cuidado de no utilizar variables del scope que puedan cambiar de valor. Debemos seguir un enfoque funcional.

Os recomiendo que le echéis un ojo a la charla . En ella se profundiza mucho más (este post solo ha sido un pequeño resumen) y puede ayudarnos a trabajar con expresiones lambda de una mejor forma.

Lambda Expressions Everywhere

From the makers of ‘Anonymous classes’ comes… anonymous functions. Or as friends call them: lambda expressions. Anonymous functions, as we already saw in a previous post, are functions that don’t need to be declared previously. Let’s see an example: A function which returns the length of a String removing any blank space in it could be defined as:

  def length(s: String): Int = s.replaceAll(" ", "").length

Its equivalent anonymous function would be:

  (s: String) => s.replaceAll(" ", "").length

The type of this expression is: String => Int

Where can we use anonymous functions?

The most common way to use them is in function that accept other functions as parameter. This type of functions are called Higher Order Functions. Functions that return a function as result are also known as higher order functions. Fantastic, extraordinary… an example, please? Thanks to our unlimited imagination, we’ll create a simple integer calculator. Let’s define our calculator in the following way:

  object Calculator {
    
    def sum(n1: Int, n2: Int): Int = n1 + n2

    def subtract(n1: Int, n2: Int): Int = n1 - n2

    def multiplicate(n1: Int, n2: Int): Int = n1 * n2

    def divide(n1: Int, n2: Int): Int = n1 / n2
  }

Hmmmm, cool. A class with some methods in it. It works but… what if we try and take a more generic turn?
meme-functions

What we really want is to apply a binary operation. That operation, given two integers, will return a new integer. We could say that we need a method like this:

  def calculate(n1: Int, n2: Int)(operation:(Int, Int) => Int) =
    operation(n1, n2)

As can be appreciated, we are actually passing a function as parameter. We are using an anonymous function. In order to make it more readable, we can create a new type that represents the integer binary operation: (Int, Int) => Int.

  type Operation = (Int, Int) => Int

And if we apply this to our calculate method:

  def calculate(n1: Int, n2: Int)(operation: Operation) =
    operation(n1, n2)

This method can be used in several ways:

1) The easiest one: we insert a previously defined function.

  def addition(n1: Int, n2: Int) = n1 + n2

calculate(1, 2)(addition) //returns 3

2) There is no function defined. Besides, the function is pretty simple and it won’t be used elsewhere in the code. All right then, we can use a lambda expression:

  calculate(1, 2)((n1: Int, n2: Int) => n1 + n2) //returns 3

As can be seen, in this case, an anonymous function is used to define the operation we want to apply to the two integers. It is a nimble and quick way to define functions. But that’s not all. Thanks to the type inference, we can avoid writing the type of the input parameters:

  calculate(1, 2)((n1, n2) => n1 + n2) //returns 3

And with a spoonful of syntactic sugar…

  calculate(1, 2)(_ + _) //returns 3

What advantages do we have when compared to the object oriented implementation?

  • Our code is significantly reduced:
  object Calculator {

    type Operation = (Int, Int) => Int
    
    def calculate(n1: Int, n2: Int)(operation: Operation) =
      operation(n1, n2)
  }
  • We are not bound to use only the operations that we have hardcoded in our implementation. We can create more complex operations on the fly:
  calculate(1, 2)((n1, n2) => (n1 + n2) * (n1 - n2))

As it always happens in Scala, its misuse might lead to unpleasant consequences. In future posts, we’ll take a look at the dark side of lambda expressions. In the meantime, we shall remain naively happy.

Expresiones Lambda a cholón

De los creadores de las clases Anónimas llega…..funciones anónimas. O como les llaman los amigos: expresiones lambda. Las funciones anónimas, como ya vimos en un post anterior, son funciones que no es necesario declarar previamente. Vamos a ver un ejemplo: Una función que devuelva la longitud de un String eliminando los espacios en blanco la podemos definir de la siguiente forma:

  def length(s: String): Int = s.replaceAll(" ", "").length

Su equivalente en función anónima será la siguiente:

  (s: String) => s.replaceAll(" ", "").length

El tipo de esta expresión será: String => Int

¿Dónde podemos usar funciones anónimas?

Lo más usual es utilizarlo en funciones que, como parámetro, aceptan otras funciones. A este tipo de funciones se les llama Funciones de Orden Superior (o Higher Order Function). También son funciones de orden superior aquellas que como resultado devuelven una función. ¿Pues muy bien. Mu rico….¿un ejemplo? Gracias a una imaginación desbordante, vamos a crear una calculadora de números enteros muy simple. Podemos definir una calculadora de la siguiente forma:

  object Calculator {
    
    def sum(n1: Int, n2: Int): Int = n1 + n2

    def subtract(n1: Int, n2: Int): Int = n1 - n2

    def multiplicate(n1: Int, n2: Int): Int = n1 * n2

    def divide(n1: Int, n2: Int): Int = n1 / n2
  }

Mmmmm, guay. Una clase con varios métodos. Funciona. Pero…¿y si probamos a darle un giro más genérico? meme-functions Realmente lo que queremos es aplicar una operación binaria. Dicha operación, dado dos enteros, devolverá un nuevo entero. Podemos decir que necesitamos un método como este:

  def calculate(n1: Int, n2: Int)(operation:(Int, Int) => Int) =
    operation(n1, n2)

Como se puede ver, estamos pasando realmente una función como parámetro. Estamos utilizando una función anónima. Para hacerlo más legible, podemos crear un nuevo tipo que represente la operación binaria de enteros: (Int, Int) => Int.

  type Operation = (Int, Int) => Int

Y lo aplicamos a nuestro método calculate:

  def calculate(n1: Int, n2: Int)(operation: Operation) =
    operation(n1, n2)

Este método puede ser llamado de varias formas:
1) La facilita: le inserto una función definida anteriormente:

  def addition(n1: Int, n2: Int) = n1 + n2

calculate(1, 2)(addition) //returns 3

2) No tengo una función definida. Además, la función es simple y no se volverá a usar en ningún otro punto del código. Pues nada, meto una expresión lambda

  calculate(1, 2)((n1: Int, n2: Int) => n1 + n2) //returns 3

Como se puede observar, en este caso se utiliza una función anónima para definir la operación que queremos aplicar a los dos enteros. Es una forma ágil y rápida de definir funciones. Pero no se queda aquí. Gracias a la inferencia de tipos, nos podemos saltar marcar el tipo de los parámetros de entrada:

  calculate(1, 2)((n1, n2) => n1 + n2) //returns 3

Y si aplicamos un poco de sintatix sugar….

  calculate(1, 2)(_ + _) //returns 3

¿Qué ventajas tenemos respecto a la implementación orientada a objetos?

  • Nuestro código se reduce de manera significativa:
  object Calculator {

    type Operation = (Int, Int) => Int
    
    def calculate(n1: Int, n2: Int)(operation: Operation) =
      operation(n1, n2)
  }
  • No estamos atados a utilizar solo las operaciones que hemos definido a fuego en nuestra implementación. Podemos hacer otras operaciones más complejas al vuelo:
  calculate(1, 2)((n1, n2) => (n1 + n2) * (n1 - n2))

Como siempre pasa en Scala, su mal uso puede provocar problemas algo desagradables. En futuros post veremos el lado oscuro de las expresiones lambda. Mientras tanto viviremos felices.