0

I'm trying to create a convenience wrapper around my database calls in scala by using a partially applied function:

  def queryResult[B](connection: Connection, sql: String)(process: (CallableStatement,ResultSet) => B): B =
    using (connection) { connection =>
      using (connection.prepareCall(sql)) { statement =>
        var rs: ResultSet = null
        try {
          process(statement, rs)
        } finally if (rs != null) {
          try {
            rs.close()
          }
          catch {
            case e: SQLException => {}
          }
        }
      }
    }

Mainly for automatically closing connections/resultsets. However, I would like the rs variable to return as a var, not a val. Whenever I try to assign rs to a resultset from a query, I get an error that I can't reassign to val.

Alternatively, if you have other ways to maximize code reuse for opening/closing streams/connections, please share too.

Edit: As Randall Schulz mentioned, Scala ARM would address the actual problem. The question as I posted it, however, is not supported in Scala.

hammar
  • 138,522
  • 17
  • 304
  • 385
stan
  • 4,885
  • 5
  • 49
  • 72
  • Are you sure you do need to close *result set* not connection? Isn't *using* statement already do this (I mean closing connections)? And by the way, ARM things like aquire-try-to-do-release in scala usually done with so-named [Loan Pattern](http://blog.knoldus.com/2012/11/16/scalaknol-understanding-loan-pattern/) and looks like using in code above is implementation on LP. – om-nom-nom Jan 11 '13 at 20:13
  • @RandallSchulz: I'm aware of that library, and I might end up using it. But my question still stands. – stan Jan 11 '13 at 20:20
  • @om-nom-nom: Thanks for the link, I didn't even realize it. I know closing a Connection and even a Callable/PreparedStatement should theoretically close all ResultSets as well, however, I want to be 100% that the ResultSet is closed – stan Jan 11 '13 at 20:20
  • I'm closing the Connection in the using() applied function, too – stan Jan 11 '13 at 20:21
  • @StanislavPalatnik The question is not well posed. Functions and methods return values only, not bindings (whether immutable / val or mutable / var). Thus I don't know how to answer that part. – Randall Schulz Jan 11 '13 at 21:39
  • I'd recommend that instead of creating one-off ARM solutions like this you use Josh Suereth's [Scala ARM project](https://github.com/jsuereth/scala-arm). (this was originally a comment that somehow was converted to an answer which was then converted to a comment that seems to have disappeared... The left hand needs to get in sync with the right hand here...) – Randall Schulz Jan 12 '13 at 02:57

1 Answers1

3

What you seem to want is something called pass-by-reference which isn't a very common feature programming languages. Scala does not support it.

In this case, just make "process" return a ResultSet instead of taking one as an argument.

def queryResult[B](connection: Connection, sql: String)(process: CallableStatement => (ResultSet, B)): (ResultSet, B) =
    using (connection) { connection =>
      using (connection.prepareCall(sql)) { statement => {
          val (rs, result) = process(statement)
          if (rs != null) 
             try rs.close
             catch {
               case _ : SQLException =>
             }
          result
       }
     }
   }
James Iry
  • 19,367
  • 3
  • 64
  • 56