6

I'm trying to avoid mutables variables, but the problem is that I have to access a val that I need to initialize inside the try (it's a db operation that migth fail) and I need that var in the finally block

I tried with several alternatives:

declaring the val inside the try block

try {
  val resultSet = SQL(sql).resultSet
  return ColumnInfo(resultSet.getMetaData)
} catch {
  case e => throw new ColumnInfoException("Error getting metadata")
} finally {
  resultSet.close
}

error: not found: value resultSet

declaring the val outside the try block without initializing it

val resultSet: java.sql.ResultSet
try {
  resultSet = SQL(sql).resultSet
  return ColumnInfo(resultSet.getMetaData)
} catch {
  case e => throw new ColumnInfoException("Error getting metadata")
} finally {
  resultSet.close
}

error: only classes can have declared but undefined members

using a var, which seems to work

var resultSet: java.sql.ResultSet = null
try {
  resultSet = SQL(sql).resultSet
  return ColumnInfo(resultSet.getMetaData)
} catch {
  case e => throw new ColumnInfoException("Error getting metadata")
} finally {
  resultSet.close
}

and finally nesting try-catch block, which seems rather dirty

try {
  val resultSet = SQL(sql).resultSet
  try {
    return ColumnInfo(resultSet.getMetaData)
  } catch {
    case e => throw new ColumnInfoException("Error getting metadata")
  } finally {
    resultSet.close
  }
} catch {
  case e => throw new ColumnInfoException("Error opening resultSet")
}

Is there some better approach I can take to avoid using vars and nesting try-catch blocks?

Ben James
  • 121,135
  • 26
  • 193
  • 155
opensas
  • 60,462
  • 79
  • 252
  • 386

4 Answers4

3
import scala.util.control.Exception._

allCatch.either(SQL(sql).resultSet).right.flatMap{ resultSet =>
  val ans = allCatch.either(ColumnInfo(resultSet.getMetaData))
  resultSet.close
  ans
}.fold(e => throw e, identity)

or you can skip the fold and keep the exception(s) packaged in Left.

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
2

from this question functional try & catch w/ Scala

I learned about the loan pattern: https://wiki.scala-lang.org/display/SYGN/Loan

Play framework itself seems to use it with the DB.withConnection method

Community
  • 1
  • 1
opensas
  • 60,462
  • 79
  • 252
  • 386
2

In Scala, try block is an expression. In your case it can evaluate to a tuple containing both vals:

val res: (java.sql.ResultSet, ColumnInfo) = try {
  val rs = SQL(sql).resultSet
  (rs, ColumnInfo(rs.getMetaData))
} catch {
  case _: Throwable => throw new Exception("Error getting metadata")
} finally {
  res._1.close
}
val columnInfo = res._2
Piotr Pachalko
  • 316
  • 2
  • 2
0

Get rid of the first catch block:

try {
  val resultSet = SQL(sql).resultSet
  try {
    ColumnInfo(resultSet.getMetaData)
  } finally {
    resultSet.close
  }
} catch {
  case e => throw new ColumnInfoException("Error opening resultSet")
}
nilskp
  • 3,097
  • 1
  • 30
  • 34
  • the second catch would also catch any exception from the first try, right? (upvoted, cause it improves my own version...) – opensas Sep 12 '12 at 15:08
  • Yes, it will close the result set, but leave the catching to the outer try block. – nilskp Sep 12 '12 at 17:32