Scalera tip: Handling sticky implicit contexts

A couple of days ago (translation for the masses: like a month ago) I noticed Viktor Klang was tweeting about removing the annoying implicit evidences from methods. And some things I read seemed so elegant to me that I was forced to share some related ideas with all of you that don’t follow him at Twitter (@viktorklang).

Setting some context

Imagine the typical polymorphic method where we need an execution context for evaluating some Future:

import scala.concurrent.{ExecutionContext, Future}

def myMethod[T]
  (element: T)
  (implicit ev: ExecutionContext): Future[Boolean] = ???

You could say it’s as typical as disgusting, having to repeat the same exact words in the following 10 method definitions: (implicit ev: ExecutionContext).

Playing with type alias

The happy idea that is being proposed is to define a type alias like the following one:

type EC[_] = ExecutionContext

This way, by adding some syntax sugar, we would re-define the method signature:

def myMethod[T:EC](element: T): Future[Boolean] = ???
myMethod("hi")

Beautiful, isn’t it?

Some other possibilities

Non-polymorphic methods

In case our method isn’t parameterized, we would have to add some boilerplate (by adding a wildcard for the type that parameterizes the method). In essence, it should be working the same principle:

def myMethod[_:EC](element: Int): Future[Boolean] = ???
myMethod(2)

Multiple implicit contexts

The not-so-crazy case in which we needed several implicit parameters of different natures, we would have to define as many type alias as different type parameters we required:

type EC[_] = ExecutionContext
type MongoDB[_] = MongoDBDatabase

def myMethod[_:EC:MongoDB](element: Int): Future[Boolean] = ???

But what if …?

Multiple implicit parameters with same type

In case we have several implicit parameters that share the same type,

def myMethod
  (element: Int)
  (implicit ev1: ExecutionContext, ev2: ExecutionContext): Future[Boolean] = ???

it turns out that …

Well, by definition that’s impossible given that it would incur in some ambiguity issue when resolving implicits. It’s true that Scala allows having these kind of signatures, but we could only invoke them by making explicit the arguments contained in the second parameter group.:

myMethod(2)(ec1,ec2)

which is kind of…

Type-constructor implicit contexts

When we have implicit parameters that are also type constructors like List[T], Future[T], Option[T]

…well, it actually depends.

Case 1

If the type that parameterizes the method and the one that parameterizes the evidence are not related, there’s no big deal: we define another type alias and move on:

type EC[_] = ExecutionContext
type MongoDB[_] = MongoDBDatabase
type IntOpt[_] = Option[Int]
type StrList[_] = List[String]

def myMethod[_:EC:MongoDB:IntOpt:StrList](
  element: Int): Future[Boolean] = ???

Which would be equivalent to:

def myMethod(
  element: Int)(
  implicit ev1: ExecutionContext,
  ev2: MongoDBDatabase,
  ev3: Option[Int],
  ev4: List[String]): Future[Boolean] = ???

Case 2

If the type that parameterizes the method and the one that parameterizes the evidence have to match …

Well, it’s not possible. The syntax sugar we’re using here implies that both types have to match. Maybe it was too pretty for our bodies 🙂

See you in the next post. Peace out!

Anuncios

Scalera tip: contextos implícitos pegajosos

El otro día (para la gente normal: hace cosa de 1 mes) vi que el gran Viktor Klang twiteaba acerca de como quitar las molestas evidencias implícitas en definiciones de métodos. Y me pareció tan elegantes algunas de las cosas que leí, que me vi en la obligación de compartir algunas ideas al hilo de dichos consejos con aquellos de vosotros que no le sigáis aun en Twitter (@viktorklang).

La situación

Imaginad el típico método polimórfico en el cual necesitamos un execution context para ejecutar un futuro:

import scala.concurrent.{ExecutionContext, Future}

def myMethod[T]
  (element: T)
  (implicit ev: ExecutionContext): Future[Boolean] = ???

Es tan típico como feo, el tener que repetir la coletilla de (implicit ev: ExecutionContext) en 10 métodos seguidos…

Jugando con type alias

La idea feliz que se propone es definir un type alias del siguiente tipo:

type EC[_] = ExecutionContext

De esta forma, re-definiríamos la cabecera de nuestro método como sigue:

def myMethod[T:EC](element: T): Future[Boolean] = ???
myMethod("hi")

¿Bello o no?

Otras posibilidades

Métodos no polifórmicos

En el caso en que nuestro método no esté parametrizado, tendríamos que añadir algo de boilerplate (añadiendo un wildcard para el tipo que parametriza el método), pero en esencia debería seguir funcionando el mismo principio:

def myMethod[_:EC](element: Int): Future[Boolean] = ???
myMethod(2)

Múltiples contextos implícitos

En el no-tan-descabellado caso en el que necesitáramos varios parámetros implícitos de distintos tipos, necesitaríamos definir tantos type alias como tipos distintos de parámetros requiriésemos:

type EC[_] = ExecutionContext
type MongoDB[_] = MongoDBDatabase

def myMethod[_:EC:MongoDB](element: Int): Future[Boolean] = ???

Pero, ¿y si…?

Múltiples parámetros implícitos del mismo tipo

En el caso de que tengamos múltiples parámetros implícitos del mismo tipo,

def myMethod
  (element: Int)
  (implicit ev1: ExecutionContext, ev2: ExecutionContext): Future[Boolean] = ???

ocurriría que …

Bueno, por definición eso es imposible ya que incurriría en un problema de ambigüedad a la hora de resolver implícitos. Es cierto que Scala nos permite este tipo de signaturas, pero sólo podríamos invocar al método haciendo explícitos los argumentos del segundo grupo de parámetros:

myMethod(2)(ec1,ec2)

Lo cual es un tanto…

Contextos implícitos que son constructores de tipos

Cuando tenemos parámetros implícitos que son constructores de tipos como List[T], Future[T], Option[T]

En realidad depende.

Caso1

Si el tipo que parametriza el método y el que parametriza la evidencia no están relacionados, no hay mucho problema: definimos otro type alias y a correr:

type EC[_] = ExecutionContext
type MongoDB[_] = MongoDBDatabase
type IntOpt[_] = Option[Int]
type StrList[_] = List[String]

def myMethod[_:EC:MongoDB:IntOpt:StrList](
  element: Int): Future[Boolean] = ???

Lo cual sería el equivalente a:

def myMethod(
  element: Int)(
  implicit ev1: ExecutionContext,
  ev2: MongoDBDatabase,
  ev3: Option[Int],
  ev4: List[String]): Future[Boolean] = ???

Caso 2

Si el tipo que parametriza el método y el que parametriza la evidencia tienen que concordar …

Bueno no es posible. El syntax sugar implica que el tipo que parametriza el método vaya en concordancia con el tipo que parametriza nuestra evidencia. Quizás era todo demasiado bonito 🙂

Hasta el próximo post. ¡Agur de limón!

Scalera tip: Why ‘scala.util.Try’ doesn’t have ‘finally’ clause?

Some days ago, a work colleage raised the million-dollar question.

If we use the traditional java try, we could be handling some code similar to this:

val connection = database.getConnection()
var data: Seq[Data] = Seq()
try {
  val results = connection.query("select whatever")
  data = results.map(convertToWhatIneed)
} catch {
  case t: Throwable => logger.error("Oh noes!")
} finally {
  connection.close()
}

In Scala, we have a more functional version of this mechanism: scala.util.Try.
The same example could be implemented by using this data type:

val connection = database.getConnection()
val data: Seq[Data] = Try{
  val results = connection.query("select whatever")
  val data: Seq[Data] = 
    results.map(convertToWhatIneed)
  connection.close()
  data
} recover {
  case t: Throwable => 
    logger.error("Oh noes!")
    connection.close()
    Seq.empty[Data]
} get

The question is, why doesn’t scala.util.Try even consider a finally clause like Java’s try?

Side effects….side effects everywhere…

If you remember the post where David talked about Try[T] data type, it’s a type that may have two different possible values Success(t: T) or Failure(t: Throwable).

On the other hand, if you remembet another post where we talked about vals and vars, we mentioned the referential transparency as principle that must be followed for considering a function to be pure.

So, if we test this principle with the previously described snippet, we could replace the Try[Seq[Data]] expression with the same type value that we would have got by evaluating the expression; and we should retrieve the same result. I.e.:

val connection = database.getConnection()
val data: Seq[Data] = 
  Success(Seq(data1,data2,data3)).get

We can see it hasn’t closed the connection that we opened before though…

o6dau

For this reason, it makes more sense to code something like this:

val connection = database.getConnection()
val data: Seq[Data] = Try{
  val results = connection.query("select whatever")
  results.map(convertToWhatIneed)
} recover {
  case t: Throwable => 
    Seq.empty[Data]
} get
connection.close()

This way, the data value can be replaced easily, without any extra side effect implication.

…And for this reason, fellows, it doesn’t make sense to think about a finally clause for Try[T]! 🙂

Peace out!

Scalera tip: ¿Por qué ‘scala.util.Try’ no tiene ‘finally’?

Hace algunos días, un compañero del trabajo planteó la duda del millón.

Si usamos el try tradicional de Java, podríamos encontrarnos con código similar a:

val connection = database.getConnection()
var data: Seq[Data] = Seq()
try {
  val results = connection.query("select whatever")
  data = results.map(convertToWhatIneed)
} catch {
  case t: Throwable => logger.error("Oh noes!")
} finally {
  connection.close()
}

En Scala, disponemos de una versión más funcional de este mecanismo: scala.util.Try.
El mismo ejemplo, utilizando esté tipo de datos, sería algo como

val connection = database.getConnection()
val data: Seq[Data] = Try{
  val results = connection.query("select whatever")
  val data: Seq[Data] = 
    results.map(convertToWhatIneed)
  connection.close()
  data
} recover {
  case t: Throwable => 
    logger.error("Oh noes!")
    connection.close()
    Seq.empty[Data]
} get

La pregunta es, ¿por qué scala.util.Try no considera una claúsula finally como el try de java?

Side effects….side effects everywhere…

Si recordáis el post en el que David habló sobre el tipo Try[T], es un tipo que puede tener dos posibles estados: Success(t: T) o Failure(t: Throwable).

Por otra parte, si hacéis memoria sobre el post en el que hablábamos sobre los valores y las variables, mencionábamos la transparencia referencial como principio que debe cumplirse para considerar una función pura.

Por lo tanto, si ponemos a prueba este principio con el snippet arriba descrito, podríamos sustituir la expresión de tipo Try[Seq[Data]] por el valor del mismo tipo que hubiéramos obtenido al evaluar la expresión, y deberíamos tener el mismo resultado. Por ejemplo:

val connection = database.getConnection()
val data: Seq[Data] = 
  Success(Seq(data1,data2,data3)).get

Sin embargo, vemos que no ha cerrado la conexión que hemos abierto justo antes…

o6dau

Por ese motivo, tiene más lógica hacer algo así como:

val connection = database.getConnection()
val data: Seq[Data] = Try{
  val results = connection.query("select whatever")
  results.map(convertToWhatIneed)
} recover {
  case t: Throwable => 
    Seq.empty[Data]
} get
connection.close()

De esta forma, el valor de data puede ser sustituido fácilmente, sin implicar más efectos de lado.

…¡y por esto, amigos, no tiene sentido pensar en un finally para Try[T]! 🙂

Agur de limón

Scalera tips: How NOT to change your actor’s state

A common key when working with Akka, is modifying properly our actor’s state. If we jog our memory, this framework paradigm allows us to program modeling the concurrency based on actors and message passing. From that base, we could define an actor as a computing unit that may have state and perform tasks based on messages that it will receive through its mailbox and that will be processed sequentially .

That means that, in order to avoid side effects, the actor’s state modification has to take place when processing a message. So senseful so far. However, it’s a pretty common mistake to do something similar to this:

class MyActor extends Actor {

  var state: Int = 0

  def receive = {

    case "command" => 
      Future(state = 1)

    case "someOtherCommand" => 
      state = 2

  }

}

In this case, we have no more warranty that the state change (whose only responsible of keeping it consistent and thread safe is the actor) might cause side efects given that, in the precise moment where the Future modifies the var, it’s possible that the state is being modified by the actor itself (probably as a reaction to some other received message).

This Future[Unit] might not be a block like that. It could be the result of having asked to some other actor:

class MyActor extends Actor {

  type State = Int

  var state: State = 0

  def receive = {

    case "command" => 
      (service ? "giveMeMyNewState").map{
        case newState: State => state = newState
      }

    case "someOtherCommand" => 
      state = 2
  }

}

Something that probably none of us has ever tried.

giphy

The proper way

If we want to modify the actor’s state as result of having previously asked to some other actor and without breaking the concurrency control of the actor, it could be achieved like this:

class MyActor extends Actor {

  type State = Int

  var state: State = 0

  def receive = {

    case "command" => 
      (service ? "giveMeMyNewState") pipeTo self

    case "someOtherCommand" => 
      state = 2

    case newState: State => 
      state = newState
  }

}

With pipeTo we specify to send to certain actor the result of having evaluated some future when its resolved. This way we’re indicating that, when we get the response of the other actor, it will be sent to our mailbox, so it will be processed like a normal message, sequentially.

bill_murray_gif_1

Easy peasy 🙂

Scalera tips: Como NO modificar el estado de tu actor

Una cuestión habitual a la hora de trabajar con Akka, es modificar de manera correcta el estado de nuestro actor. Si recordamos la base del paradigma de este framework que nos permite programar modelando la concurrencia en base a actores y el paso de mensajes, es que un actor puede definirse como una unidad computacional que puede tener estado y realiza tareas en base a mensajes que recibe en su mailbox y que procesará de manera secuencial.

Esto significa que, para no tener efectos de lado, es necesario que la modificación del estado del actor se haga al procesar un mensaje. Hasta aquí todo tiene sentido. No obstante, es un fallo bastante común el hacer algo del siguiente estilo:

class MyActor extends Actor {

  var state: Int = 0

  def receive = {

    case "command" => 
      Future(state = 1)

    case "someOtherCommand" => 
      state = 2

  }

}

En ese caso, ya no tenemos garantía de que el cambio de estado (cuyo único responsable de mantenerlo consistente y thread-safe es el actor) puede generar efectos de lado dado que en el momento en que futuro modifica el var es posible que el estado esté siendo modificado por el propio actor, desencadenado por el procesamiento de otro mensaje.

Este Future[Unit] puede no ser un bloque como tal, sino el resultado de haber preguntado a otro actor:

class MyActor extends Actor {

  type State = Int

  var state: State = 0

  def receive = {

    case "command" => 
      (service ? "giveMeMyNewState").map{
        case newState: State => state = newState
      }

    case "someOtherCommand" => 
      state = 2
  }

}

Algo que probablemente nadie de nosotros haya intentado jamás.

giphy

La forma correcta

En caso de querer modificar el estado del actor como resultado de dicha consulta a otro actor sin romper el control de concurrencia sobre el estado, se podría hacer como sigue:

class MyActor extends Actor {

  type State = Int

  var state: State = 0

  def receive = {

    case "command" => 
      (service ? "giveMeMyNewState") pipeTo self

    case "someOtherCommand" => 
      state = 2

    case newState: State => 
      state = newState
  }

}

Con pipeTo lo que hacemos es mandar a cierto actor el resultado de evaluar un futuro cuando este se resuelva. De esta manera estamos indicando que, cuando tengamos la respuesta del otro actor, se envie a nuestro mailbox, de manera que se procesará como otro mensaje más, de manera secuencial.

bill_murray_gif_1

Easy peasy 🙂

Scalera tips : parámetros por defecto y sobrecarga

Hoy toca un post breve pero espero que descubra algo nuevo para algunos. Hoy hablaremos de los problemas que puede dar la sobrecarga al tener parámetros por defecto.

Vamos a empezar definiendo los conceptos básicos:

– Sobrecarga: …really?
– Parámetros por defecto: en Scala, es posible definir parámetros por defecto en los métodos. Estos parámetros nos permitirán obviar algunos parámetros en su llamada. Vamos a ver un ejemplo:

def getUri(host: String = "localhost", port: Int = 8080): String = "$host:$port"

getUri("127.0.0.1", 8081) //"127.0.0.1:8081"
getUri(port = 8081) //"localhost:8081"
getUri("127.0.0.1") //"127.0.0.1:8080"
getUri() //"localhost:8080"

Genial…y ¿cuál es el problema?

Vamos a crear el siguiente trait:

trait A {
  def a(a: Int, p: Boolean = false)
  def a(b: Boolean = false)
}

y ahora compilamos y…

giphy2

error: in trait A, multiple overloaded alternatives of method a define default arguments.

Sin embargo, si quitamos el parámetro por defecto de la primera función:

trait A {
  def a(a: Int, p: Boolean)
  def a(b: Boolean = false)
}

y compilamos …..

giphy1

todo va bien.

¿Cuál es la causa de este kilombo?

El problema es que el compilador utilizará los parámetros por defecto para generar los nombres de unas funciones auxiliares que utilizará para tratar los método con valores por defecto (no olvidemos que seguimos en la JVM). Veamos el ejemplo que aparece en la documentación:

def f(a: Int = 1, b: String)
// generates a method: def f$default$1 = 1
f(b = "3")
// transformed to: f(b = "3", a = f$default$1)

Como se puede observar, se genera una nueva función y se sobreescribe la llamada al método original haciendo uso de dicha función.

Después de esto, podemos decir que en el primer caso de nuestro kilombo, las dos funciones auxiliares creadas tendrán este nombre:

def a$default$1 = false

y por ello se producirá un conflicto de nombres.

En el segundo caso, al no existir un parámetro por defecto en el primer método, solo se generará una nueva función y, por tanto, no se producirá ningún conflicto.

Y hasta aquí el post 🙂