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:
Are equivalent to the following
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#:
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
!
This is cool stuff. These function is making use of a very nice feature of Scala’s type system, structural subtyping, to operate on arbitrary objects that define particular methods. For example, the type
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:
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.
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,
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:
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
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
Hi, great post. I want to link to you but I have no idea what your name is! "Anonymous Blogger writes..." sounds so lame.
Thanks
Neil
I was just writing about structural subtyping as "static duck typing" over here.
There is no OCaml equivalent of the implicit conversions.For comparison, here is "using" in OCaml:
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.
Sorry didn't work :(
Ok another try:
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 ;-)
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 ;-) ;-)
Good job Python has cycle detection too... 0GC (Best smiley ever...)
I propose an even (IMHO) simplier syntax:
This simplifies calls to:The downside is that the Closable instance cannot be create inside the paranthesis.
After thinking a bit about this:
With a small modification, 'using' even takes multiple arguments:
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:
This makes use of the convention that method arguments can be enclosed in braces as an alternative to parentheses.