I have moved!

I've moved my blog
CLICK HERE
Showing posts with label IDisposable. Show all posts
Showing posts with label IDisposable. Show all posts

Sunday, 8 February 2009

A functional replacement for the using statement

The using-statement is just that: a statement. Why does this bug me?

The FileStream object has a Length property. Assuming I have a function Open that returns a FileStream ready for us, it is awfully tempting to do this:

Console.WriteLine(Open().Length);

But that is wrong, wrong, wrong, because it postpones the closing of the file handle until the finalization thread gets around to it. No good.

To obtain a value from a disposable object after that object is disposed, you have to store it in a variable declared outside the using-statement, like this:

long length;
 
using (FileStream file = Open())
    length = file.Length;
 
Console.WriteLine(length);

Not very nice. But how about this?

Console.WriteLine(Open().Use(file => file.Length));

Only a little uglier than the wrong version, but a whole lot righter. The Use extension method executes the function passed to it, and returns whatever that function returns, but also disposes of the object it was called on:

public static class DisposableExtensions
{
    public static TResult Use<TArg, TResult>(
        this TArg arg, Func<TArg, TResult> usage)
        where TArg : IDisposable
    {
        try
        {
            return usage(arg);
        }
        finally
        {
            arg.Dispose();
        }
    }
}

Of course, this technique allows us to do something very similar even when we aren’t dealing with objects that implement IDisposable. What we are really doing here is putting the system into some temporary state, then computing something, then undoing that temporary state change. That’s all a  “resource” really is: some state the system gets into that you’ll need to back out of soon. The definition of “soon” varies; for memory allocation, we can be pretty lax, because we have enough memory to support a very large number of small allocations simultaneously, but we can only support a single exclusive file handle on a given file, so we have to be extremely careful.

So a resource is two bits of code: get-into-state and get-out-of-state. Suppose I have a really simple kind of “lock”. I actually support any number of simultaneous locks, but I want to know how many are held at any given time. So my “lock” is just an integer field in my class. To take out a lock, increment it, and to release the lock, decrement it:

public class Lockable
{
    private int _lockCount;
 
    public int OpenLocks
    {
        get { return _lockCount; }
    }
 
    public void Lock()
    {
        _lockCount++;
    }
 
    public void Unlock()
    {
        _lockCount--;
    }
}

How can I help users of my class to ensure they don’t forget to release the lock in a timely fashion?

If you understood the definition of a “resource” I gave above, you’ll have realised that the resource in this case is not the class itself, but a state in which there has been a call to Lock without a corresponding Unlock call. So if the value of _lockCount happens to be 63, then there are 63 resources alive in our program, and we want them to be cleaned up at some point.

So the object-oriented (which doesn’t necessarily mean “good”) way to expose this is to reify our resource, by giving it a class of its own:

public class Lock : IDisposable
{
    private readonly Lockable _res;
 
    public Lock(Lockable res)
    {
        _res = res;
        _res.Lock();
    }
 
    public void Dispose()
    {
        _res.Unlock();
    }
}

Now the users of MyResource can employ the using-statement to call Dispose for them, which takes care of calling Unlock.

Lockable mr = new Lockable();
 
int locks;
using (new Lock(mr))
    locks = mr.OpenLocks;
 
Console.WriteLine(locks);

Fair enough, but as we saw above, that makes it ugly when we just want to write an expression that computes a value while the lock is held. Yes, we could use my Use extension method:

Console.WriteLine(new Lock(mr).Use(l => mr.OpenLocks));

But why not cut out the middleman altogether?

public class Lockable
{
    private int _lockCount;
 
    public int OpenLocks
    {
        get { return _lockCount; }
    }
 
    public T WithinLock<T>(Func<T> f)
    {
        _lockCount++;
 
        try
        {
            return f();
        }
        finally
        {
            _lockCount--;
        }
    }
}

We get rid of the public Lock/Unlock so there’s no way to break the rules, and instead provide a way to conveniently get a parameterless lambda executed inside a lock, guaranteeing that the lock will be released when the computation finishes:

Console.WriteLine(mr.WithinLock(() => mr.OpenLocks));

This addresses a very common complaint about IDisposable, which is that the user has to remember to call Dispose, or else they have to remember to use a using-statement, and it is very easy to forget. With the above alternative technique, the user is not given the ability to forget.

I call such methods "Gateways", although in Java this is called the Execute Around idiom, and it is also exemplified by Common Lisp macros that start with the prefix with-, such as with-open-file.

Of course, there is a minor downside. C# has the error: “Cannot use void as a type argument”. So you have to write a second version of WithinLock that returns void and accepts an Action as its parameter, of which more in my next post.

Wednesday, 12 November 2008

AutoDisposal using PostSharp

I complain to anyone who will listen about the poor language support in C# for the IDisposable interface. Yeah, we’ve got the using statement, and that’s fine as far as it goes.

But compare that to what C++/CLI has: the most complete support of any .NET language. Not just the equivalent of the using statement, but also automatic implementation of IDisposable that takes care of disposing of nested owned objects, including inherited ones, like magic (relatively speaking, unless you’re a C++ programmer in which case you’ve taken it for granted for a decade or two).

The relationship between deterministic clean-up (i.e. destructors) and garbage collection (i.e. finalizers) was quite vaguely understood until Herb Sutter clarified as part of his work on C++/CLI. But now it’s all very clear how it should work – the only problem is, there doesn’t seem to be any movement towards fixing it in any future version of C#.

Anyway, by now you’re probably bored of the ranting and wondering where the code snippets are. So here’s one:

class FunkyResource : IDisposable
{
    public string Label { get; set; }
 
    public void Dispose()
    {
        Console.WriteLine("Disposing " + Label);
    }
}

Not particularly impressive, I grant you, but it serves as a dummy example of a class that represents some resource that needs to be cleaned up. Here we just log the fact that a given instance is being cleaned up, identifying it with a label string.

Here’s where it gets interesting:

[AutoDisposable]
class FunkyOwner
{
    [AutoDispose] 
    private FunkyResource _resource1 = new FunkyResource { Label = "resource1" };
 
    [AutoDispose] 
    private FunkyResource _resource2 = new FunkyResource { Label = "resource2" };
}

This class owns a couple of FunkyResource instances. By “own” I simply mean that when an instance of this class is disposed of, those two resource instances must also be disposed of.

But wait a second – how does FunkyOwner implement IDisposable? The answer is that it automatically does so, because of that [AutoDisposable] attribute.

This is all thanks to the wonderfully powerful PostSharp, which effectively allows you to extend any CLR-based language through custom attributes. And because PostSharp builds on the CLR in a language-independent way, this means that the extensions you create should work in any CLR-based language that supports attributes.

Very briefly, PostSharp registers an extra step in the compilation process of Visual Studio: after your output assembly is built, a program called PostSharp.exe takes a look at it, and performs additional processing on the raw IL in the assembly. And hey presto, extra features make their way into your assembly.

Before we see how this example works, what about inheritance?

class DerivedOwner : FunkyOwner
{
    [AutoDispose] 
    private FunkyResource _resource3 = new FunkyResource { Label = "resource3" };
}

Note that because we’re deriving from a class that has the [AutoDisposable] attribute, we don’t need to specify it again (it will be ignored if we do). If we call Dispose on an instance of DerivedOwner, we get this output:

Disposing resource3
Disposing resource1
Disposing resource2

That is, the resources owned by DerivedOwner are disposed of first, then the base class’s resources are also disposed of. So inheritance works fine.

And what about a mixed scenario, where I want automatic clean-up of owned resources but I also want to run some custom code of my own during disposal?

class MixedOwner : IDisposable
{
    [AutoDispose]
    private DerivedOwner _owner2 = new DerivedOwner();
 
    public void Dispose()
    {
        Console.WriteLine("Disposing MixedOwner");
 
        this.TryDisposeFields();
    }
}

Note the call to TryDisposeFields(), an extension method I cooked up (see below). The reason for the prefix ‘Try’ is that you can call it on anything and it will look for fields marked with the [AutoDispose] attribute. If it finds any, it will dispose of them. If it doesn’t find any, that’s okay – nothing happens.

When manually implementing IDisposable like this, consider making it virtual, so that derived classes can override it, although they must of course call the base class’s version after performing their custom cleanup. It might be good practice in some circumstances to follow the pattern where you have a separate virtual method Dispose(bool) instead. However, that is really intended to allow you to implement a finalizer and a Dispose method together, and these days there are almost no circumstances in which it is recommended that you write a finalizer (unfortunately a lot of old books give out-of-date advice here).

Also note that we don’t need the [AutoDisposable] attribute on the class, as we already implement IDisposable (again, it would have been harmless to add it).

Unsurprisingly, the output of disposing an instance of MixedOwner is:

Disposing MixedOwner
Disposing resource3
Disposing resource1
Disposing resource2

All very nice. And extremely easy to implement, using the “easy” mode of PostSharp which is known as Laos. No need to directly manipulate IL, just write classes to represent your attributes, deriving from base classes that take care of the messy details.

My [AutoDispose] attribute is actually completely trivial because it’s just a simple marker on fields that I look for using reflection. So this isn’t inherently anything to do with PostSharp:

[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public sealed class AutoDisposeAttribute : Attribute { }

Where PostSharp makes an appearance is in the [AutoDisposable] attribute:

[Serializable]
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public sealed class AutoDisposableAttribute : CompositionAspect
{
    public override object CreateImplementationObject(InstanceBoundLaosEventArgs eventArgs)
    {
        return new AutoDisposableImpl(eventArgs.Instance);
    }
 
    public override Type GetPublicInterface(Type containerType)
    {
        return typeof(IDisposable);
    }
 
    public override CompositionAspectOptions GetOptions()
    {
        return CompositionAspectOptions.IgnoreIfAlreadyImplemented;
    }
}

By inheriting the attribute from PostSharp.Laos.CompositionAspect, I’m saying that I want to add an extra interface to any class marked with my attribute. The implementation is created and returned from the CreateImplementationObject method. The other overrides are pretty self-explanatory.

Here’s what my AutoDisposableImpl class looks like:

public sealed class AutoDisposableImpl : IDisposable
{
    private readonly object _instance;
 
    public AutoDisposableImpl(object instance)
    {
        _instance = instance;
    }
 
    public void Dispose()
    {
        _instance.TryDisposeFields();
    }
}

Pretty simple, eh? It just stores a “back pointer” to the object we are extending, so it can call the TryDisposeFields extension method on whatever that object happens to be. In a way, it’s just like MixedOwner except it doesn’t do anything extra.

Actually most of the complicated mess is hidden in that extension method. So here’s the gory detail:

public static void TryDisposeFields(this object instance)
{
    instance.GetType()
        .Chain(type => type.BaseType)
        .SelectMany(type => type.GetFields(BindingFlags.Instance | 
                                           BindingFlags.Public | 
                                           BindingFlags.NonPublic | 
                                           BindingFlags.DeclaredOnly))
        .Where(fieldInfo => fieldInfo.GetCustomAttributes(typeof(AutoDisposeAttribute), false)
                                     .OfType<AutoDisposeAttribute>().Any())
        .Select(fieldInfo => fieldInfo.GetValue(instance))
        .OfType<IDisposable>()
        .ForEach(field => field.Dispose());
}

As you can see, I enjoy chaining a lot of LINQ operators together. The first one, Chain, is a little custom gadget of mine that turns any linked list of T into an IEnumerable<T>. I’ll describe it in a separate post.

After that, I get all the fields of all the types in the inheritance chain into a flat list, using the marvelous SelectMany method. Then I filter them according to whether they have the [AutoDispose] attribute, and select the values of the remaining fields, then filter again based on whether they support IDisposable, and finally I dispose of each one. (That last ForEach method is another one of mine, and I’ve seen a lot of people suggesting the same thing).

So what are the drawbacks of this marvelous scheme? The one major issue with the PostSharp approach is that the Visual Studio IDE does its own compilation of your source to provide auto-completion and other kinds of “intellisense”. It doesn’t look at the assembly on disk, because there might not be one (e.g. if the code doesn’t completely compile without errors yet, as is often the case when you are adding new code, which is precisely the time when you require intellisense features).

This means that the IDE doesn’t know that [AutoDisposable] classes support IDisposable. Nor does the real compilation stage that happens during the build. PostSharp doesn’t kick in until after the compilation has completed. The upshot is that we cannot do this:

using (new FunkyOwner())
{
    Console.WriteLine("Using FunkyOwner...");
}

The using statement needs to statically verify that the object supports IDisposable. It won’t try to resolve this at runtime.

This would seem to be not so much a drawback, more a total friggin’ disaster. However, there is a solution, in the form of another generally applicable extension method:

public static void TryUsing<T>(this T instance, Action<T> action)
{
    try
    {
        action(instance);
    }
    finally
    {
        IDisposable disp = instance as IDisposable;
        if (disp != null)
            disp.Dispose();
    }
}

Now we can write:

new FunkyOwner().TryUsing(funkyOwner =>
{
    Console.WriteLine("Using FunkyOwner...");
});

I arranged the interface of the TryUsing method carefully in order to mimic the characteristic of the using statement. In particular, the object to be disposed of is only given a name by the lambda parameter. This means that it cannot be accidentally used outside of the block where it is “in scope” (i.e. still not yet disposed), unless the programmer makes a special effort to circumvent this protection by storing a reference to the object in a variable declared outside the lambda.

And with that, I have now discussed every single part of the AutoDisposal library. You can download the complete source along with a demonstration program here:

http://www.earwicker.com/AutoDisposalSource.zip

You will of course also need the PostSharp system, which you can get here:

http://www.postsharp.org/download/