Throwing the baby out with the bathwater

Richard Hale Shaw writes on and his conclusion is “it’s too confusing” and “I’d suggest not even using using statements”. I think that position is a little harsh, but I think that the main problem is that using tries to provide support for “scoped locals” and it doesn’t do it well enough.

Richard refers to this C# idiom for deterministic resource release.

using(MyObj obj = new MyObj())
{
   obj.DoStuff();
}

The point being that although the memory that MyObj uses will not be reclaimed until the garbage collector runs other resources that MyObj uses could be released at a precisely defined point via an implementation of IDisposable.

Richard points out that you are not forced to create the object in the using statement and that if you pass in an already existing object you might write code that relies on being able to use that object after the using statement ends and disposes of the object. He then suggests that because of this you should consider not using using statements…

Given that he delves into the IL that results from using a using statement and shows how it’s simply syntactic sugar for the corresponding try/finally construct. I assume that his “don’t do it” recommendation equally applies to this:

MyObj obj = new MyObj()
try
{
   obj.DoStuff();
}
finally
{
   if (obj != null) obj.Dispose();
}

Which, to me, looks like a suggestion that using IDisposable at all is a bad idea… He may have a point. In the nice and fluffy .Net world where you don’t have to worry about resource management ;) because the garbage collector does it for you the use of IDisposable brings back all the resource management issues that .Net tried so hard to avoid. I think they just got their syntactic sugar wrong.

Lets rewind to this time five years ago when thoughts of deterministic destruction in .Net were being raised. This posting, “Resource management” from Brian Harry on the DOTNET@DISCUSS.DEVELOP.COM list seems to be the story on the .Net resource management design, and the conception of IDisposable and using. (Having just read back through Brian’s stuff my immediate thought was “this guy should blog!” he does, here, but not often. Pity!). I think, as a solution for the “scoped locals” problem, using is only halfway there… Given that the using was designed to be used to implement scoped locals and given that it’s just syntactic sugar over the usual IL that is generated if you do the work that’s required long hand, I think they should have gone further and actually added the concept of a “scoped local” as a first class concept in .Net.

For those of you not familiar with the C++ RAII idiom, scoped locals are used a lot for resource management in C++. The basic idea is that you create an object that manages a resource and it acquires the resource when you create the object and it releases the resource when you destroy the object. You then create one of these objects on the stack at the scope where you wish to use the resource and it takes care of getting the object for you and releasing it when you done. The advantage that RAII has over managing the resource lifetime yourself is that when the object goes out of scope it cleans up. This means that you can have multiple returns from a function, including “returning” via an exception, and the resource will always be cleaned up correctly at exactly the right time. You end up with code like this:

{
   if (/* something */)
   {
      CDatabaseConnection connection(/* stuff */);
      
      /* do stuff with the connection */
  
   }  // Database connection is released when execution passes here...
}

You’ll find that in “good” C++ code you’ll hardly ever see bare resources being used, they’ll always be wrapped in objects that tend to live on the stack and allow scope rules to determine when they’re released.

Of course in .Net you can’t have objects on the “stack”. Everything is “heap” allocated using new and then you just forget about it and let the garbage collector do its job. I think the solution for using would have been to allow the appearance of stack based objects, the code would look something like this.

{
   {
      MyObj obj;

      obj.DoStuff();
   } // end of scope, object 'obj' disposed.
}

This could result in pretty much the same IL as the using statement above. Yet it can’t be misused. Note that I’m not suggesting any changes to how memory is allocated, it’s just a different form of syntactic sugar than the one they ended up with. I’d almost be tempted to say that these scoped objects should have a “destructor” and that they shouldn’t be allowed to be created via new, but then I like restrictions that prevent programmers misusing features ;).

Given explicit support for scoped local objects in .Net, the confusion that Richard finds with using could go away. I guess it’s always easy to come up with “better” designs, especially with 5 years worth of hindsight, but I don’t see why there would be any problem with this kind of functionality, what are the downsides?