BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News C# Futures: Defer

C# Futures: Defer

Leia em Português

This item in japanese

Best known for its use in Go and Swift, C# proposal #1398 seeks to add defer statements. If you are not familiar with the concept, it can be summarized as a finally block appearing at the beginning of some code instead of the end.

Here is an example from the proposal:

{
   SomeType thing = Whatever...;
   defer {
      thing.Free();
   }
   // some code code using thing
}

This would be interpreted as:

{
    SomeType thing = Whatever...;
    try
    {
        // some code code using thing
    }
    finally
    {
        thing.Free();
    }
}

As it does so closely resemble a finally block, many developers think the syntax is redundant. Neal Gafter of Microsoft presents a counter-argument by claiming it has these advantages:

  • They do not require implementing some interface, such as IDisposable, or creating helper objects that do.
  • They do not add an indentation level to the code, which would be clumsy when there are more than one.
  • They do not move the cleanup code to the end, as try-finally does, but rather they keep the cleanup code logically with the declaration and initialization of the thing that is being cleaned up. In this way they make the code easier to understand.

Alireza Habibi rejects this with:

I don't think that the real problem with using statement is additional indentions nor that you have to implement an interface — this is not a bad thing at all, so there is a contract for types that need cleanup. I think the actual problem here is that you might forget to dispose disposable types; defer statement doesn't help with this at all, it rather encourages you to not implement IDisposable interface and explicitly call methods like Close or Free which in presence of IDisposable seem like code smells.

Sam also questions the new keyword:

If the use case for defer is resource cleanup, then it would seem to be an anti-pattern to me to not require that the thing implement IDisposable. Implementing IDisposable allows tooling to warn you if you create a disposable as a local variable and then never dispose of it. If you make it accepted for resources to not require IDisposable, you lose this benefit.

Another complaint is it makes the order of operations hard to understand. A user going by the handle HaloFour offers this example:

static void Main() {
    Console.WriteLine("Hello"); //1
    defer {
        Console.WriteLine("Foo"); //5
    }
    defer {
        Console.WriteLine("Bar"); //4
    }
    defer {
        Console.WriteLine("Baz"); //3
    }
    Console.WriteLine("World"); //2
}

For your convenience, the order in which the lines will be executed have been added as comments. As you can see, the code is executed from top to bottom, skipping some lines, and then from bottom to top.

Exception Handling

One question discussed is what will the effect of an exception in a defer block will be. With a normal try-finally, the current finally block is aborted but other finally blocks that wrap it will still be executed. Would that be the case for defer or would the first failure cause the others to be bypassed? The general consensus seems to be the remaining defer blocks will still be executed.

Swift avoids this issue by not allowing code that can throw an exception to be called from within a defer block.

The defer statement proposal is currently tagged as a C# 8.x candidate, but that doesn’t mean it was actually chosen to be part of a future C# release. Its official status is “proposal champion”, which means a member of the C# team is interested in representing the feature in a future language design meeting (LDM).

Rate this Article

Adoption
Style

BT