In David Pollak's book, Beginning Scala, he introduces a using
control structure that is helpful in several ways. First, it can be used to automatically close any resource that has a close
method. Second, it's a great example of how to create a custom control structure in Scala.
UPDATE: Don’t use this code in production. Instead, use the scala.util.Using object. This code and blog post is shown here for informational and educational purposes only.
David Pollak’s ‘using’ control structure
Here's the source code for the using
control structure he created:
// this import is required when using reflection, like `using` does import scala.language.reflectiveCalls /** * From the book, Beginning Scala, by David Pollak. */ object Control { def using[A <: { def close(): Unit }, B](param: A)(f: A => B): B = try { f(param) } finally { param.close() } }
This is a clever bit of code that creates a new control construct you can use named using
that we'll use to perform our inserts. If you're comfortable with the syntax shown, you can see that this construct automatically calls the close()
method on the param it's given.
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |
How the ‘using’ control structure works
Let's look at how the using
control structure works. First, here's the source code again:
import scala.language.reflectiveCalls object Control { def using[A <: { def close(): Unit }, B](param: A)(f: A => B): B = try { f(param) } finally { param.close() } }
Here's how the using
method works:
A
andB
both define generic types.A
can be an instance of any class that has aclose()
method. (This type of definition is known as a structural type in Scala.)B
can be any type; no restrictions are specified.- The
f
parameter specifies a block of code that takes a typeA
as input and transforms it to a typeB
. - In the function body,
f
is executed withparam
as its input parameter inside thetry
block. When that finishes, or if it throws an exception, theclose()
method is called onparam
.
Next, here's another look at the code that calls the using
method:
using(MongoFactory.getConnection) { conn => MongoFactory.getCollection(conn).save(mongoObj) }
The first parameter passed to using is MongoFactory.getConnection
, which is an instance of MongoConnection
. The MongoConnection
class has a close()
method, so it's legal to pass this instance in as the first parameter. The second parameter passed in is an anonymous function that takes the parameter of type A
(the MongoConnection
) and converts it to type B
, which is the result of the save(mongoObj)
method call on the MongoConnection
instance. The result of that save method call is a WriteResult
instance, though I don't use that instance in this example.
The ‘using’ control structure and the Loan Pattern
The using
control structure implements something that’s known as the Loan Pattern. Basically a resource is loaned to some block of code, and then that resource is guaranteed to be closed. The following code demonstrates how to use using
when reading from a file:
import Control._ object TestUsing extends App { using(io.Source.fromFile("example.txt")) { source => { for (line <- source.getLines) { println(line) } }} }
Using ‘using’ with MongoDb and Casbah
As a quick note, here’s a complete MongoDb/Casbah example:
import com.mongodb.casbah.Imports._ import Common._ import Control._ object Insert extends App { // create some Stock instances val apple = Stock("AAPL", 600) // save them to the mongodb database saveStock(apple) // uses the 'using' control structure to automatically close the db connection def saveStock(stock: Stock) { using(MongoFactory.getConnection) { conn => { MongoFactory.getCollection(conn).save(buildMongoDbObject(stock)) } } } }
While I later learned that you don't need to close Casbah connections manually like this, this approach shows how to use the using
method in your own code.
Summary
I hope this discussion of David Pollak's using
control structure is helpful. If you need a control structure that automatically calls a close
method on an object, or wanted an example of how to create your own control structure, I hope this has been helpful.