Scala, Scala, y nada más.

Después de tantos posts sobre Scala, de tantos snippets de código, y tantos conceptos rarunos, llega un post que teníamos pendiente desde casi el comienzo de este blog. ¿Qué recursos existen para profundizar en Scala? Pues bien…ahora os contamos nuestros favoritos.

yoda_meme

Libros: un buen punto de partida 🙂

  • Programming in Scala: un clásico. Escrito por el mismísimo Odersky y con la tercera edición recién sacada del horno.
  • Funcional Programming in Scala (también conocido, en un afán de originalidad y sencillez, como el libro rojo ). Un libro que abre la mente al paradigma funcional y que es recomendable no solo para gente que quiera programar en Scala, sino para gente que le interese la programación funcional.

Cursos: para dar un poco más de profundidad.

  • En el tema de los cursos online, Coursera y la nueva especialización de programación  funcional en Scala tienen todo el monopolio. Consta de 4 cursos + 1 proyecto y aborda en profundidad los aspectos más importantes del lenguaje.
  • Por otro lado, scala-exercises nos permite practicar de una forma más rápida, pero no por eso menos eficaz. Totalmente recomendable.

Eventos: no solo para beber cerveza  😉

  • Scala Days : sin duda la convención anual más importante de Scala. Desde hace un año se realizan dos convenciones, una en América y otra en Europa. Además, publican los vídeos de todas sus charlas 🙂
  • Scala World: convención en UK con una gran acogida y en la que puedes escuchar y ver a algunos de los mayores gurús de Scala.
  • Scala eXchange: otra de las convenciones más conocidas. Se realiza en Londres en el mes de Diciembre.

Estos son los recursos que conocemos y que nos han parecido interesante. Sin duda hay muchos más que nos dejamos en el tintero. Si echas en falta alguno en esta lista, cualquier aportación será bienvenida 🙂

Anuncios

Scala: Code interpretation at runtime

With today’s post, we’ll dive into Scala code generation on the fly: at runtime. We have to be cautious of not mixing concepts with Scala macros, which generate code at compile-time. These make use of Scala type system, which is much safer than generating code at runtime.

House-of-cards-but-why

When is it useful to make use of this mechanism then? We’ll try to shed light on this by following a very simple example, getting abstract of real implementation (that you may find at Scalera’s Github).

The problem: “da” serializer

Let’s suppose a not-so-wild case, which consists on communicating two services via an event bus (we’ll get abstract of its implementation: it could be a message queue like Kafka, Akka streams, …).

The main idea is the following:

Sender-receiver-schema

The producer knows how to send and the consumer has an associated callback for message arrivals:

trait Producer{
  def produce(message: Any): Try[Unit]
}
trait Consumer{
  val consume: Any => Unit
}

Both producer and consumer services know the message types that may arrive. In our example, they could be one of these:

case class Foo(att1: Int, att2: String)
case class Bar(att1: String)

If the producer wants to send a message using the event bus, it will have to serialize it somehow (JSON, Byte array, XML, …) so, by the time it reaches the opposite end, the consumer will start the inverse process (deserialization) and will get the original message.

…nothing weird so far.

Whydoeseverythinghavetobesocomplicated

If we have a JSON serializer …

trait JsonSer[T] {
  def serialize(t: T): String
  def deserialize(json: String): T
}

and we serialize our message …

implicit val fooSerializer: JsonSer[Foo] = ???
val foo: Foo = ???
producer.send(implicitly[JsonSer[Foo]].serialize(foo))

How do we know which deserializer to use when the consumer gets the message?

Option 1: Try every possible serializer until one of them works

In our consumer, we’d have:

lazy val consumer = new Consumer {
  override val consume: Any => Unit = {
    case message: String =>
      Seq(barSerializer, fooSerializer).flatMap { ser =>
        Try(ser.deserialize(message)).toOption
      }.headOption.fold(ifEmpty = println("Couldn't deserialize")) {
        case bar: Bar => println("it's a bar!")
        case foo: Foo => println("it's a foo!")
        case _ => println("it's ... something!")
      }
  }
}

A lil’ bit coarse, right? If the proper serializer is the last of a 100 list, we would have tried and failed with 99 serializers before (Such a waste of CPU!).

4d8

Besides, we could also consider the case of having a different type deserializer, but it fits with the received message, so it would partially or wrongly deserialize the message.

Option 2: Add the message type to the message itself

We could add an extra layer wrapping the message for indicating the message type that it contains. This way, when receiving it, we could determine the serializer type we have to use.

MessageWrapper

For writing the type, we’ll make use of Scala’s TypeTags, getting info about the T contained message type.


//Wrapper for the message (and its serializer)

import scala.reflect.runtime.universe.{TypeTag, typeTag}

case class Message[T: TypeTag](content: T){
  val messageType: Message.Type = typeTag[T].tpe.toString
}
object Message {

  type Type = String

  def typeFrom(msg: String): Message.Type = ???

  implicit def messageSer[T:TypeTag:JsonSer]: JsonSer[Message[T]] = ???

}

//We'll make use of it for sending

producer.produce(messageSer[Foo].serialize(Message(foo)))

//And we redefine the consumer

lazy val consumer = new Consumer {
    override val consume: Any => Unit = {
      case message: String =>
        Message.typeFrom(message) match {

          case "org.scalera.reflect.runtime.Bar" =>
            println("it's a bar!")
            val value = messageSer[Bar].deserialize(message).content
            println(value.att1)

          case "org.scalera.reflect.runtime.Foo" =>
            val value = messageSer[Foo].deserialize(message).content
            println("it's a foo!")
            println(value.att2)

          case _ =>
            println("it's ... something!")
        }
    }
  }

As you can see, we don’t have to try every possible serializer anymore. Instead of that, from the message type we’ve extracted from the Message wrapper we have added, we’re able to use the proper deserializer.

But it is also true that we have to add an extra case for each string that represents the message type. Wouldn’t it be nice to deserialize somehow and to have the defined case only for the already deserialized objects? (Something similar what we first tried but without trying all posible serializers). Something like:

lazy val consumer = new Consumer {
  override val consume: Any => Unit = { msg =>
    genericDeserialize(msg) match {
      case f: Foo =>
      case b: Bar =>
      case _ =>
    }
  }
}

Option 2-cool: Serializers ‘under the hood’

For achieving something similar, we have to get focused on that genericDeserialize method: Which signature should it have? Initially, something like this:

def genericDeserialize(msg: String): Any

An Any? Seriously? My fellows, at runtime, we have no idea about the type we can get. We just know that, from a String, we’ll get ‘some….thing’. The match that applies to that Any will allow us to go from something totally abstract to more concrete types.

At this point is where both reflect library and Scala compiler appear.

reflect.Toolbox

The Toolbox API allows parsing strings and getting the resulting AST (abstract syntax tree). From that AST, it is able to evaluate the expression and returns an instance of an Any as well.

For instantiating a Toolbox and use type references, we hace to add as SBT dependencies the following:

libraryDependencies ++= Seq(
  "org.scala-lang" % "scala-compiler" % "2.11.8",
  "org.scala-lang" % "scala-reflect" % "2.11.8")

For example, if we wanted to parse the "2".toInt + 4 operation,

import scala.tools.reflect.ToolBox
import scala.reflect.runtime.{universe => ru}
import ru._

//  Scala compiler tool box
val tb = ru.runtimeMirror(
  this.getClass.getClassLoader).mkToolBox()

println(ru.showRaw(tb.parse("2".toInt + 4")))

we would get the abstract syntax tree generated as a String (by using showRaw):

Apply(Select(Select(Literal(Constant("2")), TermName("toInt")), TermName("$plus")), List(Literal(Constant(4))))

If we use the toolbox for evaluating the parsed expression,

println(tb.eval(tb.parse("2".toInt + 4")))

we’ll get an Any that represents the resulting value of the sum:

6

“Da” serializer

Once we’ve seen how it generally works, we apply the same principle to our serializer, so the expression we’re going to try to interpret is similar to:

{
  import scala.reflect._;
  import spray.json._;
  import org.scalera.reflect.runtime._;
  import MySprayJsonImplicits._;
  import MyJsonSerImplicits._;

  implicitly[JsonSer[Message[$messageType]]]
}

where MySprayJsonImplicits and MyJsonSerImplicits represent the objects that contain both the Spray implicits for JsonFormat and the JsonSer implicits that we have defined before.

$messageType represents the concrete type to deserialize that we would have got by using the TypeTag (as seen before).

If we adapt it to our code, we’ll get something similar to:

object GenSer {

  import scala.tools.reflect.ToolBox
  import scala.reflect.runtime.{universe => ru}
  import ru._

  //  Scala compiler tool box
  private val tb = ru.runtimeMirror(this.getClass.getClassLoader).mkToolBox()

  def genericDeserialize(msg: String)(serContainers: Seq[AnyRef]): Any = {

    val messageType = Message.typeFrom(msg)

    val serContainersImport = serContainers.map(container =>
      "import " + container.toString.split("\\$").head + "._").mkString(";\n")

    val expr =
      s"
         |{
         |  import scala.reflect._;
         |  import spray.json._;
         |  import org.scalera.reflect.runtime._;
         |  $serContainersImport;
         |
         |  implicitly[JsonSer[Message[$messageType]]]
         |}
        ".stripMargin

    tb.eval(tb.parse(expr))
      .asInstanceOf[JsonSer[Message[Any]]]
      .deserialize(msg).content
  }

}

If you take a look, we’ve empowered the generic deserialization method notation to hold a sequence of objects to import, so we won’t make explicit which object contains the Spray implicits and which one contains our JsonSer‘s.

val serContainersImport = serContainers.map(container =>
  "import " + container.toString.split("\\$").head + "._").mkString(";\n")

It is also noteworthy that, when deserializing, we get a Message[Any]; so we’ll have to get the ‘content’ field that represents the raw value of Any type that holds the deserialized message.

The result

So finally, we can now make use of our function for generically deserialize and let our consumer code be ‘swaggy’:

lazy val consumer = new Consumer {
  override val consume: Any => Unit = { 
    case msg: String =>
      genericDeserialize(msg)(Seq(case3,Message)) match {
        case bar: Bar => println("it's a bar!")
        case foo: Foo => println("it's a foo!")
        case _ => println("it's ... something!")
      }
  }
}

Conclusions

Being able to evaluate code at runtime let us do a lot of interesting things when we want to interpret String based types. However, these kind of techniques won’t care about the so worthy and safe Scala type system, so these are tools to be used with a lil’ bit of care.

It is also kind of expensive in time terms to evaluate these expressions. I would recommend to use a type cache in this case. Something really simple like a map:

type TypeName = String
var cache: Map[TypeName, JsonSer[Message[_]]]

And when invoking the method, we’ll check if the type evidence (JsonSer) we’re looking for is already stored in the map. If so, we’ll use it, otherwise, we’ll create and store it in the cache, using it as result.

post-28553-Steve-Jobs-mind-blown-gif-HD-T-pVbd

Easy peasy…
Peace out!

Scala: Interpretación de código en runtime

En el post de hoy vamos a ver cómo generar código de Scala al vuelo: en tiempo de runtime. Hemos de ser cautos de no confundirlo con las macros de Scala, las cuales generan código en tiempo de compilación. Estas últimas hacen uso del sistema de tipos de Scala, lo cual es infinitamente más seguro que generar código en tiempo de ejecución.

House-of-cards-but-why

¿Cúando es útil hacer uso de este mecanismo entonces? Trataremos de arrojar luz siguiendo un ejemplo muy sencillo, abstrayéndonos de la verdadera implementación, la cual podéis encontrar en el Github de Scalera

El problema: “el” serializador

Supongamos un caso (no tan descabellado) en el que queramos comunicar dos servicios vía un bus de eventos (nos abstraeremos de la implementación: podría ser una cola de mensajes tipo Kafka, un stream de Akka, …).

El punto de partida es el siguiente:

Sender-receiver-schema

El productor sabe enviar y el consumidor tiene asociado un callback para cuando llegue un mensaje:

trait Producer{
  def produce(message: Any): Try[Unit]
}
trait Consumer{
  val consume: Any => Unit
}

Tanto el servicio productor como el consumidor conocen los tipos de mensajes que pueden llegar, en nuestro ejemplo serán estos:

case class Foo(att1: Int, att2: String)
case class Bar(att1: String)

Si el servidor quiere enviar un mensaje usando el bus de eventos, deberá serializarlo de alguna forma (JSON, array de bytes, XML, …) para que, al llegar al otro extremo, el consumidor realice el proceso inverso (deserialización) y obtenga el mensaje original.

…hasta aquí nada extraño.

Whydoeseverythinghavetobesocomplicated

Si tenemos un serializador para JSONs …

trait JsonSer[T] {
  def serialize(t: T): String
  def deserialize(json: String): T
}

y serializamos nuestro mensaje…

implicit val fooSerializer: JsonSer[Foo] = ???
val foo: Foo = ???
producer.send(implicitly[JsonSer[Foo]].serialize(foo))

¿Cómo sabemos qué deserializador usar cuando el consumidor reciba el mensaje?

Opción 1: Probar con todos hasta que uno encaje

En nuestro consumidor tendríamos:

lazy val consumer = new Consumer {
  override val consume: Any => Unit = {
    case message: String =>
      Seq(barSerializer, fooSerializer).flatMap { ser =>
        Try(ser.deserialize(message)).toOption
      }.headOption.fold(ifEmpty = println("Couldn't deserialize")) {
        case bar: Bar => println("it's a bar!")
        case foo: Foo => println("it's a foo!")
        case _ => println("it's ... something!")
      }
  }
}

Un poco burdo, ¿no? Si el serializador correcto es el último de 100, estaríamos probando y fallando con 99 antes de dar con el correcto (¡qué desperdicio de CPU!).

4d8

Además, también podría darse el caso de que hubiera un deserializador para otro tipo, pero que encaja y es capaz de deserializar parcial o erróneamente el mensaje.

Opción 2: Añadir el tipo al mensaje

Podríamos añadir una capa por encima al mensaje e indicar el tipo de mensaje que es. Así, al recibirlo, podríamos determinar el tipo de serializador que necesitamos usar.

MessageWrapper

Para escribir el tipo, nos apoyaremos en los TypeTag de Scala, obteniendo información sobre el tipo de mensaje contenido T.


//Wrapper for the message (and its serializer)

import scala.reflect.runtime.universe.{TypeTag, typeTag}

case class Message[T: TypeTag](content: T){
  val messageType: Message.Type = typeTag[T].tpe.toString
}
object Message {

  type Type = String

  def typeFrom(msg: String): Message.Type = ???

  implicit def messageSer[T:TypeTag:JsonSer]: JsonSer[Message[T]] = ???

}

//We'll make use of it for sending

producer.produce(messageSer[Foo].serialize(Message(foo)))

//And we redefine the consumer

lazy val consumer = new Consumer {
    override val consume: Any => Unit = {
      case message: String =>
        Message.typeFrom(message) match {

          case "org.scalera.reflect.runtime.Bar" =>
            println("it's a bar!")
            val value = messageSer[Bar].deserialize(message).content
            println(value.att1)

          case "org.scalera.reflect.runtime.Foo" =>
            val value = messageSer[Foo].deserialize(message).content
            println("it's a foo!")
            println(value.att2)

          case _ =>
            println("it's ... something!")
        }
    }
  }

Cómo podéis ver, ya no tenemos que ir probando con todos los serializadores posibles hasta que demos con uno que funcione; sino que, a partir del tipo de mensaje (extraido del envoltorio de tipo Message que hemos añadido), somos capaces de usar el deserializador adecuado.

Pero también es cierto, que tenemos que añadir un case por cada string que representa el tipo. ¿No sería mejor poder deserializar (como sea) y que el case solo esté definido sobre los objetos ya deserializados (como antes pero sin probar a lo loco con mil serializadores)? Algo de este estilo:

lazy val consumer = new Consumer {
  override val consume: Any => Unit = { msg =>
    genericDeserialize(msg) match {
      case f: Foo =>
      case b: Bar =>
      case _ =>
    }
  }
}

Opción 2-guay: Serializadores ‘under the hood’

Para conseguir algo parecido, debemos de centrarnos en ese método genericDeserialize: ¿qué signatura debería tener? Inicialmente algo del siguiente estilo:

def genericDeserialize(msg: String): Any

¿Un Any? ¿En serio? Amigos, en tiempo de runtime, no tenemos ni idea del tipo que nos puede llegar. Solo sabemos que, a partir de un String, vamos a obtener un ‘algo’. El match que se aplica sobre dicho Any nos permitirá pasar de algo totamente abstracto a tipos más concretos.

Es en este punto, donde entra en juego la librería de reflect y el compilador de scala.

reflect.Toolbox

La api de Toolbox permite parsear cadenas de texto y obtener el AST (abstract syntax tree) resultante. Del mismo modo, a partir del AST es capaz de evaluar la expresión devolviendo una instancia de un tipo determinado.

Para poder instanciar un Toolbox y usar referencias a tipos, es preciso añadir como dependencias a nuestro proyecto las librerías de scala-compiler y scala-reflect:

libraryDependencies ++= Seq(
  "org.scala-lang" % "scala-compiler" % "2.11.8",
  "org.scala-lang" % "scala-reflect" % "2.11.8")

Si por ejemplo quisiéramos parsear la operación "2".toInt + 4,

import scala.tools.reflect.ToolBox
import scala.reflect.runtime.{universe => ru}
import ru._

//  Scala compiler tool box
val tb = ru.runtimeMirror(
  this.getClass.getClassLoader).mkToolBox()

println(ru.showRaw(tb.parse(""""2".toInt + 4""")))

nos devolverá el árbol sintáctico generado como un string (usando showRaw):

Apply(Select(Select(Literal(Constant("2")), TermName("toInt")), TermName("$plus")), List(Literal(Constant(4))))

Si a partir de la expresión parseada, usamos el toolbox para evaluarla,

println(tb.eval(tb.parse(""""2".toInt + 4""")))

obtendremos un Any que representa el valor resultante de la suma:

6

“El” serializador

Una vez visto el funcionamiento general, aplicamos el mismo principio a nuestro serializador, de manera que la expresión que vamos a intentar interpretar es algo similar a:

{
  import scala.reflect._;
  import spray.json._;
  import org.scalera.reflect.runtime._;
  import MySprayJsonImplicits._;
  import MyJsonSerImplicits._;

  implicitly[JsonSer[Message[$messageType]]]
}

donde MySprayJsonImplicits y MyJsonSerImplicits representan los objetos que contienen tanto los implícitos de Spray para JsonFormat que hemos definido, como los implícitos de la type class JsonSer que hemos definido nosotros.

$messageType representa el tipo concreto a deserializar que habremos obtenido previamente usando el TypeTag (como hemos visto antes).

Si lo adaptamos a nuestro código obtendremos algo similar a:

object GenSer {

  import scala.tools.reflect.ToolBox
  import scala.reflect.runtime.{universe => ru}
  import ru._

  //  Scala compiler tool box
  private val tb = ru.runtimeMirror(this.getClass.getClassLoader).mkToolBox()

  def genericDeserialize(msg: String)(serContainers: Seq[AnyRef]): Any = {

    val messageType = Message.typeFrom(msg)

    val serContainersImport = serContainers.map(container =>
      "import " + container.toString.split("\\$").head + "._").mkString(";\n")

    val expr =
      s"""
         |{
         |  import scala.reflect._;
         |  import spray.json._;
         |  import org.scalera.reflect.runtime._;
         |  $serContainersImport;
         |
         |  implicitly[JsonSer[Message[$messageType]]]
         |}
        """.stripMargin

    tb.eval(tb.parse(expr))
      .asInstanceOf[JsonSer[Message[Any]]]
      .deserialize(msg).content
  }

}

Si os fijáis, hemos permitido en la notación del método de deserialización genérica, que se le pase una secuencia de objetos a importar, de manera que no se explicita qué objeto es el que contiene los implícitos de Spray y qué otro contiene los de nuestro JsonSer.

val serContainersImport = serContainers.map(container =>
  "import " + container.toString.split("\\$").head + "._").mkString(";\n")

También cabe destacar que, al deserializar, obtenemos un Message[Any]; por lo que posteriormente hay que obtener el campo ‘content’ que representa el valor plano de tipo Any que representa el mensaje deserializado.

El resultado

Ahora sí, podemos usar nuestra función para deserializar de manera genérica y dejar el código de nuestro consumidor de manera ‘reshulona’:

lazy val consumer = new Consumer {
  override val consume: Any => Unit = { 
    case msg: String =>
      genericDeserialize(msg)(Seq(case3,Message)) match {
        case bar: Bar => println("it's a bar!")
        case foo: Foo => println("it's a foo!")
        case _ => println("it's ... something!")
      }
  }
}

Conclusiones

Poder interpretar código en tiempo de runtime da bastante juego cuando queremos interpretar tipos en base a String’s. Ahora bien, interpretar código en runtime se pasa por el forro el sistema de tipos que tanta seguridad aporta en Scala, por lo que son herramientas a usar con algo de cuidado.

También es algo costoso en tiempo la evaluación de estas expresiones. Os recomendaría que usarais una cache de tipos. Algo tan sencillo como un mapa:

type TypeName = String
var cache: Map[TypeName, JsonSer[Message[_]]]

Y al ejecutar el método, comprobar si existe ya un JsonSer almacenado en el mapa. De ser así, usamos ese y en caso contrario, lo creamos, lo almacenamos en la caché y lo devolvemos como resultado.

post-28553-Steve-Jobs-mind-blown-gif-HD-T-pVbd

Easy peasy…
¡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

Scala: One language to rule them all (I)

In the beginning, there were not programming languages, just machine code. Automatic programming came to save all us by casting power rings to rule the machines: Programming languages. They diversified, inspired new ones, constituted a rich ecosystem. Among them appeared a highly useful kind of computer languages: DSLs.

DSLs

Domain Specific (computer) Languages have been around for quite a long time. The academic description of this kind of languages states that they are centred and used for an specific application domain. DSLs are small and concise which implies that they guide their users in the process of describing actions, entities or relations within their domain of application. What’s more important, they are made to fit their purpose.

If I am doing statistics research, why should worry about memory management?!!

It isn’t surprising that a whole kingdom of these mini-languages has evolved and took over machine learning tools, scientific programming, hardware design and management, modeling…

Wasn’t this a blog on Scala? Leave the history for academics!

Yeah this might sound as the stories from the past. However, in the context of the current times, when we all seem obsessed by data acquisition, storage and analysis and taking into account that this data is usually complex to manage because of its variability. We are forced to deal with dozens of different ways of managing data and many of them pass through the use of DSLs: SQL, HiveQL, CQL, bash, grep, awk, R, C’mon! How can I even finish the list! Let’s forget of what is to come.

What if a tool would give as the power to create simple, guided and short languages to perform specific domain tasks within.  What if Scala was a kind of DSL where the D stands for the Domain of Creating new DSLs?!

When its creators named Scala they were not just thinking on its capabilities in code reuse and  potential use in horizontal concurrent environments; they also kept in mind the extensibility of the language. Some of the features in that direction are:

  • Infix notation: objectA.method(objectB) can be written as objectA method objectB
  • Lack of operators: There are no operators as separated entities, just methods. Precedence order and associativity rules are provided by the last character of each method name.This way, any method name NOT ending with `:` gets associated from left to right:
    obj1 + obj2 is the same as writing obj1.+(obj2) whereas obj1 +: obj2 is as writing obj2.+:(obj1).
    Similarly, operator precedence is provided by a priority list of method name ending characters. e.g: `*` gets a higher priority than `+`, obj1 + obj2 * obj3  is always interpreted as obj1 + (obj2 * obj3).The mentioned precedence priority list is as follows:

    • Any letter, no matter case.
    • |
    • ^
    • &
    • Symbols = and !
    • Symbols < and >
    • :
    • Arithmetic operations + and –
    • Arithmetic operations  *, / and %
    • Any other special character.
  • Advanced object oriented features: object, trait, …

These features can be combined to model and build internal DSLs within the Scala programming language.

Scala DSLs 101

Infix notation is the main feature to create our own embedded languages.

Consider the following trait:

trait MovingRobot {
  def moveForward(): MovingRobot = {
    println("Robot moved one position forward")
    this
  }
  def moveBackward(): MovingRobot = {
    println("Robot moved one position backward")
    this
  }
}

Which can be mixed in an object declaration as:

object robot extends MovingRobot

Its methods can be called using traditional dot notation:

robot.moveForward.moveBackward

But infix notation give us a more natural way to talk with this simple bot:

robot moveForward() moveBackward
robot moveForward
robot moveBackward

This is the simplest  of all possible DSLs.

State transitions

Yes, simple but rather imperative and useless.  Commands are not changing the system state besides the lateral effect behind println:

simpliest_automaton

At this point, there are two options to model the effects of the DSL instructions:

  • The mutable approach: Somehow easiest to Scala new comers from imperative languages but it is way more bug prone. This one is rather similar to the approach followed by so many builders in Java. Check Java’s StringBuilder:

    The builder state is the string that is being composed. Methods, such as append(double d), return a reference to the instance of the builder whose state has been altered by the very same method.  Hence, the same reference is always returned since is the same StringBuilder instance which is mutating call after call, sounds familiar?!mutable_state
  • The immutable one (or the path of wisdom): Do not change anything, return a new state with the attributes derived from the previous state your action. From now, this post will only cover this approach.

The beauty of the second solution is that each action returns a new state object having a 1 to 1 relation with the system state. That is, the code entities are a perfect reflection of all the changes. Moreover the state is immutable by definition.

state /steɪt/  n., adj., v., stat•ed, stat•ing. 
n.

  1. the condition of a person or thing with respect to circumstances or experiences;
    the way something is[countable; usually singular]the state of one’s health.
  2. the condition of substances with respect to structure, form, etc.[countable]Water in a gaseous state is steam.

(www.wordreference.com)

Discussing why immutability drives to way less buggy systems is out of the scope of this post, hundreds of explanations can be found by googling “immutability reduces bugs”. Even Java creators decided it was better, at least for their strings.

state_transition

Each transition returning a whole new state reduces its responsibility  to just one: To generate a new state hence simplifying the DSL design. No changes in the state are to be expected beyond explicit transition calls.

The nitty-gritties of immutable state transitions

Following the utterly complex example of our uni-dimensional robot API (at this point you must have realized that the previous Scalera Challenge included a beautiful DSL), it can be altered to make it follow the above-described functional approach:

// All states extend `RobotState`
trait RobotState {
  def position: Int
}

// Transitions which can be mixed with any state for which they
// make sense.

trait MovementTransitions {
  self: RobotState =&amp;gt;

  def moveForward(nSteps: Int = 1): RobotState with MovementTransitions

  def moveBackward(nSteps: Int = 1): RobotState with MovementTransitions

}

// States
// In this example, states only differ in the robot position so they all
// are represented by the same case class.
case class Robot(position: Int) extends RobotState with MovementTransitions {

  def moveForward(nSteps: Int = 1) =
    Robot(position + nSteps)

  def moveBackward(nSteps: Int = 1) =
    Robot(position - nSteps)

}

// Initial state
val robot = new Robot(0)

And its use:

robot moveForward(10) moveBackward() position

The code above is an oversimplification but shows the basic tricks behind Scala DSLs, namely: The use of infix notation, families of states and transitions only usable within state definitions.

A bit of theory: Really? State Machines?

Is the state machine model actually needed to implement DSLs? Yes, if you like avoiding shooting yourself in the foot.

shootfoot

Immutable state machines are easy to understand, maintain and expand.

On the other hand, DSLs are languages, formal languages with grammars with a place in Noam Chomsky’s classification, commonly, Regular Grammars and Context-Free grammar.

  • Which theoretical machine is able to recognize/process languages with regular grammars? A finite state automaton
  • In the case of Context-Free grammar languages, they can be processed by push-down automatons which (ALERT! Oversimplification ahead) can be regarded as a finite automaton enjoying the perk of making use of its own stack to place and read symbols.

The transition model described afore seems to be just made for implementing this kind of machines. A self-answered question arises as to whether DSLs’ developers should dedicate their efforts to find buggy and flimsy solutions when such a solid model is available.

– Well, I suggest you gentlemen invent a way to put a square peg in a round hole.

gene_krantz

– Sir, we have plenty of round pegs!

engineer

Coming soon…

In the next episode: A practical DSLs development step by step, no more history, theory or that silly things nobody cares about! Just…

letsdoit

Scala: Un lenguaje para gobernarlos a todos (I)

Al principio, no teníamos lenguajes de programación, sólo código máquina. Entonces, la programación automática vino para salvarnos a todos. Proporcionando anillos de poder para controlar a las máquinas: Estos fueron llamados “Lenguajes de programación”. Se diversificaron, sirvieron de inspiración para otros nuevos y acabaron constituyendo un rico ecosistema. De entre ellos surgió un nuevo y útil género de lenguajes para ordenadores: Los DSLs.

DSLs

Los lenguajes de propósito específico, Domain Specific (computer) Languages, existen desde hace bastante tiempo. La definición académica para este sub-grupo establece que han de estar enfocados en el marco de un dominio concreto de aplicación. Los DSLs son pequeños y concisos, esto implica que son de gran ayuda ya que guían a sus usuarios a través del proceso de describir acciones, entidades y relaciones dentro de su dominio de aplicación. Aún más importante es el hecho de que están hechos y diseñados para servir a un único propósito.

Si soy un matemático y estoy haciendo un estudio estadístico con mi ordenador ¿Por qué debería preocuparme acerca de la gestión de memoria?

No es de sorprender que haya surgido un gran reino de mini-lenguajes que han tomado el poder sobre actividades teles como el aprendizaje automático, la programación científica, el diseño y gestión de hardware, modelado de datos, …

¡Y a mi qué! ¿No era esto un blog sobre Scala?

¡Cierto! todo esto puede sonar a antiguas batallitas. Sin embargo, en una actualidad en la que todos parecemos estar obsesionados por la adquisición, almacenamiento y análisis de grandes volúmenes de datos que son, a su vez, de naturaleza muy variable (o lo que es lo mismo, mezclando peras con manzanas); Estamos obligados a enfrentarnos a docenas de formas de tratar estos datos y muchas de estas formas no son más que casos concretos de DSLs: SQL, HiveQL, CQL, bash, grep, awk, R… !Por favor! !Cuando va a acabar esta lista! Probablemente: Nunca. Y eso que estamos obviando lo que está por venir.

Que maravilla si hubiese una herramienta que nos ayudase, pobres humanos, a construir DSLs, un meta-DSL que, de alguna manera, nos guiase a la hora de desarrollar nuevos DSLs. Esta herramienta existe, y se llama Scala.

Cuando los creadores de este gran (no sólo por sus bondades sino por su extensión) lenguaje de programación le pusieron nombre, no sólo lo hicieron pensando en su capacidad para la re-utilización de código y potencial uso en entornos concurrentes con facilidad para escalar horizontalmente, sino que también tenían en mente su potencial para ser fácilmente expandido. Quizás sea esa la razón de su basta extensión en sintaxis y herramientas. Algunas de las características de Scala en la dirección de la expansibilidad son:

  • Notación infija: Cualquier llamada a un método que recibe un objeto como parámetro puede ser escrita de forma infija. Esto es,
    objA.metodo(objB) puede escribirse como objA metodo objB.
  • No existencia de operadores: A diferencia de otros lenguajes, carece de operadores como elementos con entidad propia. Todo son métodos cuyas reglas de precedencia y asociatividad están determinadas por el último carácter del nombre del método.Así, cualquier método cuyo nombre no acabe en el caracter `:` asocia de izquierda a derecha: obj1 + obj2 es lo mismo que obj1.+(obj2) en tanto que obj1 +: obj2 es lo mismo que obj2.+:(obj1).
    Algo parecido ocurre con la precedencia ya que existe un orden de importancia de caracteres finales, un ejemplo es la mayor importancia de `*` frente a `+` :
    obj1 + obj2 * obj3  
    es siempre igual a obj1 + (obj2 * obj3).Esta es la lista de importancia (de menor a mayor prioridad):

    • Todas las letras del alfabeto, en mayúsculas o minúsculas.
    • |
    • ^
    • &
    • Los símbolos = y !
    • Los símbolos < y >
    • :
    • Las operaciones aritméticas + y –
    • Las operaciones aritméticas *, / y %
    • Cualquier otro caracter especial.
  • Características avanzadas de programación orientada a objetos: object, trait, …

 

Estas tres características se combinan para proporcionar un entorno completo para el desarrollo de DSLs internos en el seno de Scala.

Primeros pasos

La notación infija sienta las base sobre la que construir nuestros lenguajes embebidos en Scala.

Partiendo, por ejemplo, del siguiente trait:

trait MovingRobot {
  def moveForward(): MovingRobot = {
    println("Robot moved one position forward")
    this
  }
  def moveBackward(): MovingRobot = {
    println("Robot moved one position backward")
    this
  }
}

Que puede mezclarse en la declaración de un objeto:

object robot extends MovingRobot

Podemos modelar los movimientos del un robot virtual llamando a los métodos de MovigRobot de una forma tradicional:

robot.moveForward.moveBackward

Pero el uso de la notación infija proporciona da lugar a un código mucho más cercano al lenguaje natural:

robot moveForward() moveBackward
robot moveForward
robot moveBackward

Este es el tipo más simple de los DSLs embebidos en Scala y sirve como punta de partida para enfoques más avanzados.

Transiciones de estado

Sí, simple y también imperativo además de ser de poca utilidad. Los comandos no están cambiando el estado del sistema más allá del efecto lateral que implica la impresión de caracteres por la salida estándar realizada por medio de println:

simpliest_automaton

Con DSLs de este nivel, existen dos opciones para modelar los efectos de las instrucciones del DSL:

  • El enfoque mutable: Es el más sencillo para aquellos llegados a Scala desde lenguajes imperativos pero, definitivamente, es mucho más arriesgado en lo que a la introducción de bugs respecta. La idea es muy similar a a que hay detrás de tantos builders o acumuladores de Java, por ejemplo, StringBuilder:El estado del acumulador es la cadena que se está componiendo. Métodos, como append(double d), devuelven una referencia a la instancia del acumulador cuyo estado se está modificando como consecuencia de la llamada. De esta manera, la misma referencia se devuelve llamada tras llamada ya que es la misma instancia de StringBuilder la que muta. ¿Suena familiar?

    mutable_state

  • El enfoque inmutable (o el camino a la sabiduría):  ¡No se debe cambiar nada! Hay que devolver un nuevo estado con los atributos derivados del estado anterior y la acción realizada. De ahora en adelante, sólo se tratará esta técnica.

La belleza de la segunda solución radica en que cada acción devuelve un único estado que mantiene una relación 1 a 1 con los estados reales del sistema modelado. Esto significa que las entidades del código que implementa al DSL son un reflejo exacto de los cambios y estados que se desean representar. Además, el estado es inmutable por definición.

estado
Del lat. status.Escr. con may. inicial en aceps. 6 y 7.
1. m. Situación en que se encuentra alguien o algo, y en especial cada uno de sus sucesivos modos de ser o estar.

(www.rae.es)

Explicar el por qué del hecho de que la programación basada en la inmutabilidad es más segura (en lo que la introducción de bugs respecta) que la basada en la mutabilidad de objetos está fuera del alcance de este artículo, cientos de explicaciones están al alcance de buscador. Algunas razones están muy bien resumidas en este artículo de IBM.

Incluso, los creadores de Java, decidieron que la inmutabilidad era mejor, al menos para sus cadenas de texto.

state_transition

Devolviendo en cada transición un, totalmente nuevo, estado se reduce la lista de responsabilidades del código que implementa dicha transición a sólo una: Generar un nuevo estado. Esto genera diseños mucho más sencillos para el conjunto del DSL. No pueden darse cambios inesperados fuera de llamadas explícitas a los métodos de transición.

Al grano de las  transiciones inmutables

Siguiendo el extremadamente complejo ejemplo de nuestra API para robots unidimensionales (llegados a este punto, un ávido lector de Scalera probablemente se de cuenta de que el anterior reto Scalera incluía un bonito DSL). Este API puede cambiarse para seguir el enfoque funcional arriba descrito:

// All states extend `RobotState`
trait RobotState {
  def position: Int
}

// Transitions which can be mixed with any state for which they
// make sense.

trait MovementTransitions {
  self: RobotState =>

  def moveForward(nSteps: Int = 1): RobotState with MovementTransitions

  def moveBackward(nSteps: Int = 1): RobotState with MovementTransitions

}

// States
// In this example, states only differ in the robot position so they all
// are represented by the same case class.
case class Robot(position: Int) extends RobotState with MovementTransitions {

  def moveForward(nSteps: Int = 1) =
    Robot(position + nSteps)

  def moveBackward(nSteps: Int = 1) =
    Robot(position - nSteps)

}

// Initial state
val robot = new Robot(0)

A continuación, un sencillo ejemplo de uso:

robot moveForward(10) moveBackward() position

Esto es una simplificación extrema que muestra las técnicas básicas detrás de los DSLs embebidos en Scala que puede resumirse en:

  • El uso de la notación infija.
  • De familias de estados y transiciones entre estos.
  • Limitación de las transiciones de forma que sólo pueden producirse desde un estado y resultar en otro completamente nuevo que, podría compartir, la mayoría de los atributos con su predecesor.

Un poco de teoría: Máquinas de estado ¿En serio?

¿El realmente necesario un modelo de diseño y programación basado en máquinas de estado?  La respuesta es sí, siempre que no quieras acabar dándote un tiro en tu propio pie.

shootfootLas máquinas de estados inmutables son sencillas de mantener, entender y expandir.

Por otro lado, hay que tener en cuenta que los DSLs no son otra cosa que lenguajes formales con gramáticas que tienen su lugar en la clasificación de Chomsky: Habitualmente Gramáticas regulares y gramáticas independientes de contexto.

  • ¿Qué tipo de máquina es capaz de procesar/reconocer lenguajes basados en gramáticas regulares? Los autómatas finitos.
  • En el caso de las gramáticas independientes de contexto, son los autómatas de pila los que pueden reconocer/procesar sus lenguajes. Estos (¡Ojo! Simplificación) no son más que autómatas finitos que pueden hacer uso de una pila auxiliar dónde colocar y de dónde leer símbolos que pueden determinar el resultado de una transición, junto con el estado anterior y la entrada.

El modelo de transiciones expuesto en las secciones anteriores parece encajar a la perfección con las máquinas teóricas de estado. Surge una pregunta que es, as su vez, su propia respuesta: ¿Debería un desarrollador invertir su tiempo en buscar nuevas soluciones, poco probadas y que pueden ser inestables o estar cargadas de bugs cuando tiene un modelo tan firme a su alcance?

– Bien, les sugiero caballeros que inventen una forma de encajar una clavija cuadrada en un agujero redondo.

gene_krantz

– Pero, señor, ¡Si nos sobran clavijas redondas!

engineer

En el siguiente episodio…

Desarrollo práctico de un DSL útil, paso a paso. Sin historias de guerra, teoría y sin ninguna de esas cosas “tan aburridas”. Sólo…

letsdoit