“Nothing” else matters…

What’s Nothing, my precious?

Nothing es un tipo un poco especial dentro de la jerarquía de clases de Scala.

Para empezar no es instanciable: no podemos generar una instancia de ninguna manera.

Raro,¿no? Esto se explica un poco mejor con la segunda particularidad: es un tipo que extiende de tooooodas las clases. ¿También las definidas por el usuario? También.

scala-hierarchy

Entonces, ¿para qué sirve? El ejemplo más claro es None. Si Option[T] no fuese covariante, para cada T, habría que definir un None[T]. Y por tanto tendríamos que None[Int] sería distinto de None[String]…¡imaginaos el lío!

Pero dado que Option[+T] es covariante*, y Nothing es un subtipo de cualquier clase, no es necesario declarar un None para cada T que contuviera la lista, sino que hay un único None con la siguiente signatura:

object None extends Option[Nothing]
  //...with Product with Serializable

Lo mismo ocurre para Nil.

Inferencia de tipos

Cuando definimos métodos o valores en Scala, al principio y siendo puristas, definimos el tipo de los mismos:

val myVal: String = "hi"
def myMethod(n: String): Boolean =
  (n % 2 == 0)

Pero es bastante frecuente que, tras el paso del tiempo y habiendo tirado muchas líneas de código, empecemos a olvidar añadir el tipo que devuelven estas expresiones:

val myVal = "hi"
def myMethod(n: String) =
  (n % 2 == 0)

No ocurre nada, el compilador se encarga de inferir los tipos devueltos…siempre que tenga pistas suficientes para averiguarlo. Es entonces cuando surge la amenaza del coco “Nothing”

Nothing’s coming

Imaginemos que tenemos un método genérico del siguiente tipo:

def getFirstElement[T](list: List[T]): Option[T] =
  list.headOption

Lo que hace el método es devolver el primer elemento de una lista (si lo tuviera). ¿Dónde puede empezar a complicarse todo?

Supongamos que queremos probar el método con una lista vacía. Nuestra experiencia nos indica que la mejor forma de hacerlo es empleando el método apply de List sin ningún argumento: List().
Sin embargo, si le pasamos este argumento a nuestro método:

val first = getFirstElement(List())

veremos que nos devuelve:

first: Option[Nothing] = None

No seamos malos con el compilador, reconozcamos que no le hemos dado facilidad alguna para inferir el tipo correcto. Una forma muy sencilla para hacerlo sería usando el método empty del objeto List:

val first = getFirstElement(List.empty[Int])
first: Option[Int] = None

aunque también podría inferirse añadiendo el parameter type en la invocación del método

val first = getFirstElement[Int](List())
first: Option[Int] = None

¡Y listo! Y ahora que lo pienso, el post quedó un poco soso sin memes…

60965939

* Covarianza: Se dice que C[T] es covariante en T, si dado un V<:T, C[V]<:C[T] . Este tema se verá más en profundidad en futuros (que no lejanos) posts 🙂

Anuncios

One thought on ““Nothing” else matters…

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