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!

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 challenge: From Earth to the Moon

We have started a new year, and we want to make some solid headway. As we promised, one of our New Year’s resolutions is trying to innovate and make this blog more social. For this reason, let us introduce you the first Scalera challenge, just for driving you crazy 🙂

From Earth to the Moon

The ESA (European Space Agency) wants to send two robots (rovers) to the Moon. They are fitted with a sophisticated landing support: a parachute. The problem here is that it seems both robots won’t land at the same place…
Once they’ve landed at the same place as their own parachutes at the Moon, which has a discrete surface of infinite size, both rovers must find each other to start the mission together.

The challenge consists on programming the rovers using a limited command set, so they finally manage to find each other. Keep in mind that the same program will be loaded on both robots and they don’t have any programatic way to know which their identifiers are.

DSL for manouver

The command set that will be used for programming the rovers is composed of:

  • MOVE <direction> : It moves the rover a discrete space unit to the left or to the right.
  • IF FOUND PARACHUTE <command> : If the rover finds a parachute on the floor, at its feet wheels, then execute the given command.
  • NOP: Rover does nothing…
  • GOTO <lineId> : It jumps to the command placed at the given line.

Participate!

moonrover_example

You can find the project for start coding your robots at github.
You’ll find all the technical info you might need at the README.md file.

If you want to participate, just drop us an email to scalerablog at gmail dot com with the Launch.scala file that contains the program you have designed to solve the problem. Don’t forget to include your twitter user name for mentioning you at our virtual hall of fame 😛

The deadline will be two natural weeks from this post publication.

Among all best solutions (less clock ticks, less program lines,…) we’ll raffle the blog t-shirt 🙂

Come on and good luck!

How many things have been denied one day, only to become realities the next!

Jules Verne

Scalera challenge: De la Tierra a la Luna

Hemos entrado en el nuevo año, y hemos querido hacerlo pisando fuerte. Como prometimos, uno de nuestros propósitos para este año es tratar de innovar y hacer más participativo el blog. Por ello, os presentamos nuestro primer desafío Scalera, para poner a prueba vuestras cabezitas 🙂

De la Tierra a la Luna

forever-alone-moon_o_1332879

La ESA (Agencia Espacial Europea) quiere mandar dos robots (rovers) a la Luna. Para aterrizar disponen de un sofisticado sistema: un paracaídas. El problema es que todo apunta a que los robots no aterrizaran en el mismo sitio…
Una vez aterrizados, justo encima de sus propios paracaídas, en la Luna, la cual tiene una superficie discreta de tamaño infinito, ambos rovers deben encontrarse para empezar el desarrollo de la misión juntos.

El reto consiste en programar, utilizando un conjunto de instrucciones limitado, el rover de manera que se acaben encontrando. Ten en cuenta, que el mismo programa será cargado en ambos robots y los rovers no tienen forma programática de saber su identificador.

DSL de navegación

El set de instrucciones para programar los rovers se compone de:

  • MOVE <direction> : Mueve el rover una unidad del espacio discreto hacia la izquierda o la derecha.
  • IF FOUND PARACHUTE <command> : Si el rover encuentra un paracaídas en la parcela de suelo donde se encuentra, entonces ejecuta la instrucción indicada.
  • NOP: El rover no hace nada…
  • GOTO <lineId> : Salta a la instrucción que se encuentra en la línea indicada.

¡Participa!

moonrover_example

Puedes encontrar el proyecto para empezar a programar tus robot en github.
Encontrarás toda la información técnica necesaria en el fichero README.md.

Para participar solo teneis que mandarnos a scalerablog at gmail dot com el fichero Launch.scala con el programa que habéis usado y vuestro usuario de twitter para mencionaros en nuestro hall de la fama virtual 😛

El plazo de participación finaliza en dos semanas naturales desde la fecha de publicación de este post.

Entre las mejores soluciones (menos ticks de reloj empleados, menos lineas de programa) sortearemos una camiseta del blog 🙂

¡Ánimo y mucha suerte!

Cuántas cosas negadas la víspera han sido una realidad al día siguiente

Julio Verne