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

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