Programming in D – Tutorial and Reference
Ali Çehreli

Other D Resources

scope

As we have seen in the previous chapter, expressions that must always be executed are written in the finally block, and expressions that must be executed when there are error conditions are written in catch blocks.

We can make the following observations about the use of these blocks:

The scope statements have similar functionality to the catch and finally scopes but they are better in many respects. Like finally, the three different scope statements are about executing expressions when leaving scopes:

Although these statements are closely related to exceptions, they can be used without a try-catch block.

As an example, let's write the function above with a scope(failure) statement:

void foo(ref int r) {
    int addend = 42;

    r += addend;
    scope(failure) r -= addend;

    mayThrow();
}

The scope(failure) statement above ensures that the r -= addend expression will be executed if the function's scope is exited due to an exception. A benefit of scope(failure) is the fact that the expression that reverts another expression is written close to it.

scope statements can be specified as blocks as well:

    scope(exit) {
        // ... expressions ...
    }

Here is another function that tests all three of these statements:

void test() {
    scope(exit) writeln("when exiting 1");

    scope(success) {
        writeln("if successful 1");
        writeln("if successful 2");
    }

    scope(failure) writeln("if thrown 1");
    scope(exit) writeln("when exiting 2");
    scope(failure) writeln("if thrown 2");

    throwsHalfTheTime();
}

If no exception is thrown, the output of the function includes only the scope(exit) and scope(success) expressions:

when exiting 2
if successful 1
if successful 2
when exiting 1

If an exception is thrown, the output includes the scope(exit) and scope(failure) expressions:

if thrown 2
when exiting 2
if thrown 1
when exiting 1
object.Exception@...: the error message

As seen in the outputs, the blocks of the scope statements are executed in reverse order. This is because later code may depend on previous variables. Executing the scope statements in reverse order enables undoing side effects of earlier expressions in a consistent order.