Compiler Enforced Disposal?
Posted by Davy Brion on November 16th, 2008
I stumbled upon a blog post by Kim Hamilton on When To Call Dispose. The most interesting part about the post is that this is from someone who works on the Base Class Libraries team. The following part is especially striking:
A recent internal email thread unearthed extreme differences of opinion about when Dispose(void) should be called on an IDisposable. The rival suggestions were:
1. Always call Dispose
2. Avoid calling Dispose; rely on cleanup at finalization
This led to a long discussion and a realization that — while it seems like we’ve said everything there is to say about Dispose — it’s time for some more Dispose guidance.
I don’t know about you guys, but the thought of Base Class Library developers not being sure on when Dispose should be called is something that makes me quite uncomfortable. If anyone should know, it’s these guys, right?
Another interesting quote from the post:
Whatever distinction we eventually use, API docs should explicitly call out IDisposables that must be Disposed.
Great… now we are supposed to rely on the MSDN docs to find out which IDisposables need to be disposed and which ones don’t.
I kinda like the IDisposable pattern, but it’s truly a shame that there are so many types that implement the IDisposable interface without really needing to implement it. I’ve always considered the IDisposable interface to be a contract which states “if you use me, you must dispose me”. For certain types, this is true. Unfortunately, for other types that implement the interface it’s not true even though the IDisposable documentation is pretty clear about this:
When calling a class that implements the IDisposable interface, use the try/finally pattern to make sure that unmanaged resources are disposed of even if an exception interrupts your application.
In a perfect .NET world, there would be no types implementing IDisposable without actually requiring disposal (IMHO). Again, i think the interface is a contract that must be followed by everyone who makes use of it. Then again, it does feel pretty pointless to dispose types of which you know that it really doesn’t make a difference.
The introduction of explicit Code Contracts in .NET 4.0, got me thinking about trying to make disposal of types that really require it enforced by the compiler. What i have in mind is not possible with the Code Contracts in .NET 4.0, but it’s something that i think would be a good addition to the .NET Framework.
Suppose we could do the following:
[RequiresDisposal]
public class MyDisposableType : IDisposable
{
public void DoSomething()
{
// does something really cool and/or important
}
public void Dispose()
{
// this would contain an important disposable implementation
}
}
Basically just a type which implements IDisposable, and there’s an attribute that specifies that the disposal of this type is really required. The following code should then fail to compile:
private void SomeMethod()
{
new MyDisposableType().DoSomething();
}
Whereas this code would compile without errors:
private void SomeMethod()
{
using (var disposableType = new MyDisposableType())
{
disposableType.DoSomething();
}
}
It’s just a thought and obviously, this isn’t possible right now. But i think it would be great if it were possible. We could do all sorts of things with this approach… for instance, if an object owns a reference to an IDisposable type which has the [RequiresDisposal] attribute, the compiler could enforce that the object owning the reference must implement IDisposable and have the [RequiresDisposal] attribute as well. I think we’d end up with a system were types that really require disposal can’t be used without properly disposing them.
Thoughts?
November 16th, 2008 at 11:23 pm
I like the idea of a compiler enforcing the disposing of IDisposable objects. However, I think the fact that an object implements IDisposable should be enough as is. I do not see any reasons to introduce a RequiresDisposal attribute for that.
November 16th, 2008 at 11:58 pm
well, i thought of the attribute to distinguish between IDisposables where it’s not that important that you dispose of them, and IDisposables where you really, really should.
I know that a lot of IDisposables still call Dispose in their Finalizer method if the object hasn’t been Disposed of so you could argue that there are _no_ IDisposables that really require being Disposed of. But Finalizers can lead to other performance issues, so i don’t think that all IDisposables actually use that approach.
November 17th, 2008 at 12:20 pm
The problem with adding an attribute to force the compiler to throw compile time exceptions is that the compiler cannot always know if the attribute is there.
If you have a method:
private IDisposable GetObject(bool b)
{
// Return an IDisposable that is marked with
// the RequiresDisposal attribute if b is true
// else an IDisposable that is not marked with
// the RequiresDisposal attribute.
}
Then if the GetObject method is invoked the compiler would not be able to see if the RequiresDisposal attribute is present and will at best throw a Runtime exception.
But as you mentioned if the use of the IDisposable has been standardized from the start (and those standards actually followed) we would not be sitting with this issue now.
November 17th, 2008 at 12:28 pm
good point about it not always been clear wether or not we’re dealing with an instance that has the attribute or not
and yeah, if Microsoft had been very clear about the IDisposable interface/contract from the start, and if everyone had followed the conventions than all of this wouldn’t have been such a big deal… but the way it is now with all the confusion and the conflicting advice is just terrible. Especially when some BCL developers even think you should just rely on finalization… that is just wrong on so many levels IMHO
November 17th, 2008 at 1:57 pm
[...] Compiler Enforced Disposal? (Davy Brion) [...]
November 17th, 2008 at 3:30 pm
I like the idea.
November 17th, 2008 at 4:17 pm
If C# finally gets those compiler hooks (as Anders promised) the same way like the Boo compiler supports them, then you can role out your own mechanism. Alas I think this is a C# 5.0 feature
November 17th, 2008 at 8:27 pm
I have to agree with Den Ben. An interface is a contract that explicitly defines the interaction between client and server. If something is implementing IDisposable and it doesn’t need disposing 2 things should happen:
1. Remove IDisposable from the list of interfaces the class implements and marked the Dispose method with [Obsolete]
2. Find the developer(s) that made the choice to mark classes not requiring disposal with IDisposable and whack them across the knuckles with a steel rule (my old woodwork teachers favourite method of making a lesson out of a poorly chosen action)
=)
November 18th, 2008 at 1:05 pm
I agree with Den Ben also… I’d add that having the compiler enforce disposal would be difficult to get right. For instance, I usually say that the class that creates should be the class that Dispose()es. There’s a whole bunch of situations where a class may have a reference to an IDisposable, but should not be the one Dispose()ing it. This would be especially true for objects created through an IoC container.
Also, is there any severe drawback to calling Dispose() on classes that don’t require it (other than having a few extra using() blocks around)?
November 18th, 2008 at 1:09 pm
nope, there is no real drawback to calling Dispose() methods that aren’t really required. The only ‘drawback’ is that it’s just more code than is needed.