Sunday, February 12, 2006

Using using

With garbage-collected languages such as Java and C#, managing memory resources is handled automatically. But dealing with other resources such as files or database connections has to be done manually. You can't rely on garbage collection to free such resources. You have to explicitly close and dispose these resources. But that can get tricky when exceptions occur. For example in this Java code:
FileWriter fw = new FileWriter("log.txt"); 
fw.println("Foo"); 
// Other stuff 
fw.close() 
If an exception is thrown after the file is opened but before it's closed, the file will remain open. And you have a resource leak. There's a finalize method on the underlying stream but that won't get called unless the garbage collector recycles the object. And there's no guarantee that that will happen. In the meantime, if you leak enough file handles, you can get into trouble. The idiom to deal with this problem in Java is to use a try/finally block:
FileWriter fw = null
try {  
    fw = new FileWriter("log.txt");    
    fw.println("Foo");    
    // Other stuff    
}    
finally {   
    if (fw != null) { 
        fw.close();
    }
}
This works but can be kind of tedious and error prone. What we need is a way to declare a block-scoped object reference that won't let the object escape the block without being disposed. C# has such a feature, the using statement. Here's what the block would look like in C#:
using (TextWriter tw = File.CreateText("log.txt")) { 
    tw.WriteLine("Foo"); 
    // Other stuff 
}
Cool but how's that work? The type of the variable declared in the using statement needs to implements System.IDisposable. Its Dispose method will automatically be called when the using block is done. In this case, the Dispose method causes the file to be closed.

The compiler transforms our using block into code that looks like this:
TextWriter tw = null;
try {  
    tw = File.CreateText("log.txt");  
    tw.WriteLine("Foo");  
    // Other stuff  
}  
finally {  
    // Check for a null resource.  
    if (tw!= null)  
    {  
        // Call the object's Dispose method.  
        ((IDisposable)tw).Dispose();  
    }  
}
The using statement isn't rocket science but whenever you deal with a resource that needs to be cleaned up you naturally turn to it. If Java had support for using, people wouldn't need to resort to ugly hacks like this.

Protecting resource objects with a block scope wasn't invented for C#; it's possible to get the same sort of behavior by declaring block-scoped variables in C++. But the syntax isn't as clean. The concept of using a special block form is popular in Lisp languages, such as with-open-file in Common Lisp. In languages that allow special forms and syntax extension such as Scheme this is a pretty simple extension. It's just a simple syntax transform. But it's still quite useful and makes it clear that you're dealing with a resource that needs to be disposed of properly.