There’s been a bit of discussion of late about using statements, and how they’re more often being used for purposes other than just releasing resources. As always, there are those people who think it’s a flagrant abuse of a feature and shouldn’t be done, then there are those that like it. I’m in between. I do like what the using statement gives us, but I also think it is a bit of an abuse.

The “traditional” usage of the using statement can be found quite often in the land of files and streams. Take the following example, which opens a file and then closes it when it drops out of the using scope.

using (var stream = File.OpenRead("myFile.txt"))
{
  // do something with the file
}

Examples of the alternative usage can be found all over the place, but Rhino Mocks is one that’s close to my heart. Here’s from the record/replay syntax, anything in the scope of the using is recorded, and once it drops out of scope it’s no longer in record mode.

using (mocks.Record())
{
  Expect.Call(customer.Address)
    .Return("123 Rester St");
}

Again, I do like what the using statement gives us outside of releasing resources (I’m not disputing it’s usefulness there). However, I think the using keyword itself adds noise and clouds intention.

With the adoption of 3.5, I’ve started using an alternative syntax instead of usings. Actions and anonymous methods to the rescue.

Scope(() =>
{
  // do something within this scope
});

It’s a little bit more noisy in the compiler satisfying department, but because you have full control over naming, you can reveal intention more. No more unclear “using”.

So how does it work? Simple really, the method takes an Action delegate, which it the executes almost immediately. I say almost, because you can execute code before and after the execution. That gives you the benefits of the using statements wrapping ability.

public void Scope(Action action)
{
  // do something before
  action();
  // do something after
}

Some more examples:

File.OpenRead("myFile.txt", file =>
{
  // do something with the file
});
mocks.Record(() =>
{
  Expect.Call(customer.Address)
    .Return("123 Rester St");
});

I prefer this syntax over the using statement. Of course, it’s only valid for 3.5 projects.

Tags:

Comments...

  1. Personally i like where u are going with this. However, I think the using statement is easier to read.

    Your statement ‘No more unclear “using”’ to me is false. Lambda’s are much harder to read/understand for the average developer.

    By Derik Whittaker10 Oct, 2008 @ 7:55 pm

  2. That’s a fair point. To me personally, it’s more readable, but perhaps to the average dev it isn’t.

    With the proliferation of lambdas in frameworks, I’d hope that they’ll move into the collective developer consciousness before too long.

    Ignoring the regular developer tax for a moment, I still believe the using statement itself is redundant in most of the non-disposable usages of it. We’ve come to ignore it in most cases. using (mocks.Record()) doesn’t really make sense when you read it, but mocks.Record(() =>) does.

    By James Gregory10 Oct, 2008 @ 8:23 pm

  3. I never liked the fact that the using keyword is the only way to declare custom “scopes”, and that you have to use Dispose to perform end-of-scope actions. But I agree that it’s better than nothing.

    Your solution is actually the exact solution ruby uses as one of its main idioms — except in ruby, lambda syntax is even more readable because of adjacent lambda parameters and the do..end syntax:

    File.OpenRead(“myFile.txt”) do |file|
    # do something with the file
    end

    And, of course, there’s Boo to the rescue with its own flavor of the same thing:

    File.OpenRead(“myFile.txt”) do(file):
    // do something with the file
    end

    Which, combined with meta methods and parentheses-less invocations, means you can make your scopes work their magic at compile time rather than at runtime, which really allows freedom in declaring custom scopes.

    By Avish — 10 Oct, 2008 @ 9:23 pm

  4. That’s one of the few things that annoys me about lambdas in C#, they remind me of Ruby and it’s much better syntax!

    By James Gregory10 Oct, 2008 @ 9:33 pm

  5. I definitely feel your pain, and have found myself recently implementing the lambda-style replacements to see how they would hold up, and I gotta tell ya that I’m torn on the issue and almost tempted to head back to the using style. I have two primary concerns with the lambda-based approach (syntactical weirdness for some developers aside for the moment.)

    1. (and this is the biggie, as far as I’m concerned) stack trace obfuscation. There’s nothing like seeing a tonne of anonymous classes and their methods popping up all over your stack traces to send someone running for the hills when trying to diagnose an issue in lambda-heavy code.

    2. Perf overhead. When the pedal needs to hit the metal, I suspect that a compiler-inserted try/finally with a dispose call in the finally is going to destroy the anonymous class instantiation / delegate invocation perf-wise. Admittedly, I have no numbers to back this up at this point as I am fundamentally more concerned about issue #1 at the moment, but the potential perf issue is there nagging me in the back of my mind. Has anyone compared perf, I wonder?

    By Jeremy Gray — 10 Oct, 2008 @ 4:42 am

  6. @Jeremy: Thanks for the comments. I’m not concerned by your concerns, but that doesn’t mean they aren’t valid!

    I’ve not had any trouble with debugging lambdas, and Fluent NHibernate is pretty heavy in them. Maybe I’ve got it yet to come…

    Regarding performance, I never worry about it when it comes to syntax. The implications of using lambdas on performance will be so negligible compared to a badly written DB query, or IO operations, it’s not even worth thinking about. Unless somebody can prove to me there is a significant performance loss (and I’m talking seconds, not microseconds), then I’m not worried.

    By James Gregory10 Oct, 2008 @ 7:55 am

  7. @James – agreed in general on all points, with perhaps a few nits to pick. :)

    Regarding debugging, it isn’t you are I that I am worried about. ;) Not every developer on my team has the same level of experience, however, hence some of my concern.

    Regarding perf, I do agree with you that there are far bigger fish to fry but one problem that can come up with approaches like these (and the disposable approach presents similar possible issues) is that if they are going to hurt your perf they are going to do it in a way that is often spread quite widely across your app, but in tiny increments in each location. It is as if the entire app drags a bit, and since it drags the whole app equally (assuming you’ve used these mechanisms in enough places to have them being hit across a large percentage of application usage) it can be hard to diagnose and correct the issue because it won’t reveal a clear hotspot in a profile. Harder, at least, than killing the worst hotspot and moving onto the next one. Now, that’s not to suggest that this is even remotely insurmountable, of course. Rather just to say that one needs to keep a slightly different kind of lookout for the effects of mechanisms like these because they can drag the app down a bit differently than most normal perf issues do. I mention it only because I’ve seen people with reasonable amounts of experience and a profiler in hand still miss this kind of issue, that’s all. :)

    In any case, thanks for the post and the kind exchange of commentary!

    By Jeremy Gray — 10 Oct, 2008 @ 5:14 pm

  8. You make some good points. Your performance argument is interesting, and I’d like to subscribe to your newsletter. It certainly is something to bare in mind, at the very least in a “I’ll remember that idea for later so I can save the day” way. ;)

    By James Gregory10 Oct, 2008 @ 8:39 am

Post a comment...

Trackbacks...

  1. Pingback from Console colours wrapper — James Gregory