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!

Anuncios

Responder

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

Logo de WordPress.com

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

Imagen de Twitter

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

Foto de Facebook

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

Google+ photo

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

Conectando a %s