Implicit database connections


#1

We have this method, useConnection that is defined as:

  def useConnection[T](f: Connection => T): T = {
     val connection = getConnection
     try {
        f(connection)
     } finally {
        connection.close()
    }
}

Basically you pass in your code and it takes care of getting a connection and cleaning up.

Some people were calling it like this:
useConnection {implicit connection => /* lots of code */}

In at least one case this lead to a race connection where calls to connection.wasNull returned the wrong value.

How is this possible? Given that the lambda is explicitly passed the connection, how can declaring the lambda to take an implicit connection change anything?


#2

Hmm, implicitness shouldn’t matter because implicit arguments are filled in by the compiler and are just normal arguments at runtime. Do you have a reproducible example? If you’re using futures I would stare at the code and make sure things definitely always happen in the order you expect. You might also ensure that you don’t have an outer implicit connection that’s getting picked up in an inner context where a different non-implicit connection is in use. Wild guesses … more info might help.


#3

The one thing implicit could do is make it so capture of the connection isn’t lexically apparent. For example, this will call query() after close().

useConnection {implicit connection =>
  whatsUp()
}("hi")

def whatsUp()(implicit c: Connection) =
  (s: String) => c.query()

#4

Some people were calling it like this:
useConnection {implicit connection => /* lots of code */}

if “lots of code” makes async calls that would be the culprit; i.e. future in some cases is invoked after the connection has already been closed.