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!

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