Implementing The Disposable Pattern In Scala

One excellent feature of the CLR in general and C# in particular is deterministic finalization: the ability to control when resources are released. In C# this is realized with the IDisposable interface and the "using" keyword. Effectively, the statements:

using (File myFile = File.Open("foo.txt"))
{ /* Do something with myFile */ }

Are equivalent to the following

File myFile = File.Open("foo.txt");
try
{ /* Do something with myFile */ }
finally
{ myFile.Dispose(); }

The usual use of the Dispose method which is, as you can see above, called when "myFile" goes out of scope is to perform general clean up. In this case it would release any open handles to the file, if any: doing so in this deterministic manner is in most situations a much better idea than waiting until the garbage collector gets around to finalizing your object and doing the cleanup there, although File will of course support this paradigm to ensure that its open handles are eventually released.

There are actually more interesting uses than resource management that are made of the using keyword in C#, such as transaction management (the scope of the transaction is the scope of the using block), mock playback (mocks are automatically verified by Dispose) and many more of the class of scope management problems encountered during everyday programming (e.g. calling Begin/EndUpdate on a particular Control while you do lots of setup work on it). Hopefully this litany of examples has convinced you that we simply must have "using" added to Java - but alas that particular behemoth is unlikely to acquire this rather nice feature any time soon. Instead I have elected to show you how we can add this feature to a JVM based language, Scala, using the advanced features of its type system and functional programming paradigm.

Right, let's get started! First, let's have an interface for all things we want to consider Disposable, just as in C#:

trait Disposable[S] {
  def dispose()
}

Don't let the word "trait" throw you: although you can do some cool stuff with traits, for our purposes they are just like Java's interfaces. We have simply defined a method, dispose, on the Disposable interface that will be called to do cleanup.

Now, we could just have all things we use "using" with implement this interface, but this feels kind of limiting. This is all well and good for our own classes, but what about interfacing with Java code that doesn't know a thing about our interface? In particular, it would be nice to be able to use our new functionality with JDBC and SWT, which have a common pattern of making use of close and dispose methods respectively to perform cleanup. So, let's define two implicit conversions, known as "views" in Scala-land, from objects that define methods with those signatures to a Disposable!

  implicit def close2disposable[S](what : S { def close() }) : Disposable[S] =
    new Disposable[S] {
      def dispose() {
        try {
          what.close
        }
        catch {
          case t => ()
        }
      }
    }

  implicit def dispose2disposable[S](what : S { def dispose() }) : Disposable[S] =
    new Disposable[S] {
      def dispose() {
        what.dispose
      }
    }

This is cool stuff. These function is making use of a very nice feature of Scalas type system, structural subtyping, to operate on arbitrary objects that define particular methods. For example, the type

S { def close() }

defines a type of class S which must contain the method close, which takes no arguments and returns void (aka Unit, in Scala). With this, it is statically valid to call close() on any variable of type S within the body of our implicit conversion, and I make use of this by returning a new anonymous inner class which implements Disposable and calls the close method of the implicitly converted variable when dispose is invoked (wrapping it in appropriate exception handling, since e.g. the "close" method in JDBC can throw SQLException, and we don't want that masking exceptions thrown in the body of the using block). We define the view on things with a dispose method similarly, but this time we needn't handle exceptions since we assume anything with a dispose method is already going to be well behaved.

Notice that this is effectively statically safe duck typing, so you can have all the flexibility of a dynamic language like Python in exactly the places you need it, but keep the compile time guarantees of Scala in the majority of your code base, where you don't need that power.

Now all that remains to be done is to define the using "keyword" itself. There isn't a way to perfectly emulate the C# syntax in Scala, to the best of my knowledge, but we can come pretty damn close by defining a function which takes one curried argument which is the thing to dispose and another which is the block to dispose it after:

  def using[S <% Disposable[S], T](what : S)(block : S => T) : T = {
    try {
      block(what)
    }
    finally {
      what.dispose
    }
  }

To those uninitiated in the ways of Scala, that first line can look a little scary, so let's look at it in more detail.

def using[S <% Disposable[S], T]

tells us that we are declaring a method called "using" which is parameterized on two type arguments: S, which must have a view of type Disposable[S], and T. Next,

(what : S)(block : S => T)

says that the method takes two arguments: "what" of type S (which we specified must be Disposable in the type constraint earlier) and a block which takes one of those S objects and returns a T. The fact that brackets, rather than a comma, separate the two arguments shows that the method is curried, i.e. it may be partially applied by its callers: this makes for some nicer code later on. The final T just tells us that the method returns something of type T.

Armed with this understanding, it should be very easy to see that the body of the function is statically safe and does just the same thing as the C# example I showed at the start of this post. That's all pretty neat! Let's see some of the code you might write using this function, assuming that the method definitions I've just given have been added to an object called Disposable which accompanies the trait of the same name:

import com.omegaprime.Disposable._

class Closable {
  System.out.println("Constructed")

  def close() {
    System.out.println("Closing")
  }

  def doSomething() {
    System.out.println("Doing something")
  }
}

object Program {
  def main(args : Array[String]) {
    using (new Closable()) (closable => {
      closable.doSomething
    })
  }
}

This will print:

Constructed
Doing something
Closing

Lovely stuff! The sharp eyed reader will have noticed that the implicit conversions I defined above actually both apply for some objects (i.e. those which have both close and dispose methods): they might then be tempted to ask which conversion to Disposable gets used by the compiler for such an object. The answer for me is that it seems that the close method is always picked as the one to be called by Disposable.dispose, but I suspect this is an implementation detail, and will probably even vary from version to version: from the compilers perspective these two choices must be equally good.

I hope this article has gone some way to showing you some of the advanced features of Scala and how they can be used to solve real problems in software engineering. Note, however, that if you are going to play along at home you need at least version 2.6 of the language, as structural types were only added recently

12 thoughts on “Implementing The Disposable Pattern In Scala

  1. Nice! I liked the example and the explanation that comes with it. One small remark on syntax -- the usage example can be written a bit more concisely:

    using (new Closable) { closable =>
    closable.doSomething
    }

    This makes use of the convention that method arguments can be enclosed in braces as an alternative to parentheses.

  2. Of course you get this for free with CPython because it uses reference counting.

    This means that as soon as something goes out of scope you can rely on it being garbage collected and its '__del__' method being called. No need to wait for gaqrbage collection...

    πŸ™‚

    You also have the 'with' statement in Python 2.5 which is similar to the .NET 'using'.

    Miss you at Resolver.

    Michael

  3. In case he doesn't get time, this is by Max Bolingbroke... He is currently an undergraduate student of computer science at Cambridge university and one of the best .NET programmers I know. πŸ™‚

    There you go Max, you owe me πŸ˜‰

  4. Heh, thanks for the kind words Michael πŸ˜‰

    I guess reference counting isn't too bad as long as you don't mind memory leaks due to cycles, but then Python _is_ only a toy language πŸ˜‰ πŸ˜‰

  5. I was just writing about structural subtyping as "static duck typing" over here.

    For comparison, here is "using" in OCaml:


    let using d f =
    try f d; d#dispose
    with e -> d#dispose; raise e

    class disposable () =
    let _ = print_endline "Constructing" in
    object
    method dispose = print_endline "Disposing"
    method doSomething = print_endline "Doing something"
    end

    ;;

    using (new disposable ()) (fun disposable ->
    disposable#doSomething
    )

    There is no OCaml equivalent of the implicit conversions.

  6. I propose an even (IMHO) simplier syntax:


    def using[S T) : T = {
    try {
    block
    }
    finally {
    what.dispose
    }
    }

    This simplifies calls to:


    val closable = new Closable
    using(closable) {
    closable.doSomething
    }

    The downside is that the Closable instance cannot be create inside the paranthesis.

  7. After thinking a bit about this:
    With a small modification, 'using' even takes multiple arguments:

    def using[S T) : T = {
    try {
    block
    }
    finally {
    for( w
    Example:

    using(closable1, closable2) {
    closable1.doSomething
    closable2.doSomething
    }

    Wow this is just great.
    And now somebody tell the blog software not to mess up the code formatting πŸ˜‰

  8. Sorry didn't work πŸ™
    Ok another try:

    def using[S <% Disposable[S], T](what : S*)(block : => T) : T = {
    try {
    block
    }
    finally {
    for( w <- what )
    w.dispose
    }
    }

  9. Why does Disposable have a type parameter? It doesn't seem to be of any use -- I tried and the example worked without the type parameter on Disposable.

Comments are closed.