Is the ‘finally’ portion of a ‘try … catch … finally’ construct/structure even necessary?

Some languages (such as C++ and early versions of PHP) don’t support the finally part of a try ... catch ... finally construct. Is finally ever necessary? Because the code in it always runs, why wouldn’t/shouldn’t I just place that code after a try ... catch block without a finally clause? Why use one? (I’m looking for a reason/motivation for using/not using finally, not a reason to do away with ‘catch’ or why it’s legal to do so.)

1

In addition to what others have said, it’s also possible for an exception to be thrown inside the catch clause. Consider this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>try {
throw new SomeException();
} catch {
DoSomethingWhichUnexpectedlyThrows();
}
Cleanup();
</code>
<code>try { throw new SomeException(); } catch { DoSomethingWhichUnexpectedlyThrows(); } Cleanup(); </code>
try { 
    throw new SomeException();
} catch {
    DoSomethingWhichUnexpectedlyThrows();
}
Cleanup();

In this example, the Cleanup() function never runs, because an exception gets thrown in the catch clause and the next highest up catch in the call stack will catch that. Using a finally block removes this risk, and makes the code cleaner to boot.

1

As others have mentioned, there’s no guarantee that code after a try statement will execute unless you catch every possible exception. That said, this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>try {
mightThrowSpecificException();
} catch (SpecificException e) {
handleError();
} finally {
cleanUp();
}
</code>
<code>try { mightThrowSpecificException(); } catch (SpecificException e) { handleError(); } finally { cleanUp(); } </code>
try {
   mightThrowSpecificException();
} catch (SpecificException e) {
   handleError();
} finally {
   cleanUp();
}

can be rewritten1 as:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>try {
mightThrowSpecificException();
} catch (SpecificException e) {
try {
handleError();
} catch (Throwable e2) {
cleanUp();
throw e2;
}
} catch (Throwable e) {
cleanUp();
throw e;
}
cleanUp();
</code>
<code>try { mightThrowSpecificException(); } catch (SpecificException e) { try { handleError(); } catch (Throwable e2) { cleanUp(); throw e2; } } catch (Throwable e) { cleanUp(); throw e; } cleanUp(); </code>
try {
   mightThrowSpecificException();
} catch (SpecificException e) {
   try {
       handleError();
   } catch (Throwable e2) {
       cleanUp();
       throw e2;
   }
} catch (Throwable e) {
   cleanUp();
   throw e;
}
cleanUp();

But the latter requires you to catch all unhandled exceptions, duplicate the cleanup code, and remember to re-throw. So finally isn’t necessary, but it’s useful.

C++ doesn’t have finally because Bjarne Stroustrup believes RAII is better, or at least suffices for most cases:

Why doesn’t C++ provide a “finally” construct?

Because C++ supports an alternative that is almost always better: The “resource acquisition is initialization” technique (TC++PL3 section 14.4). The basic idea is to represent a resource by a local object, so that the local object’s destructor will release the resource. That way, the programmer cannot forget to release the resource.


1 The specific code to catch all exceptions and rethrow without losing stack trace information varies by language. I have used Java, where the stack trace is captured when the exception is created. In C# you’d just use throw;.

8

finally blocks are usually used to clear up resources which can help with readability when using multiple return statements:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>int DoSomething() {
try {
open_connection();
return get_result();
}
catch {
return 2;
}
finally {
close_connection();
}
}
</code>
<code>int DoSomething() { try { open_connection(); return get_result(); } catch { return 2; } finally { close_connection(); } } </code>
int DoSomething() {
    try {
        open_connection();
        return get_result();
    }
    catch {
        return 2;
    }
    finally {
        close_connection();
    }
}

vs

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>int DoSomething() {
int result;
try {
open_connection();
result = get_result();
}
catch {
result = 2;
}
close_connection();
return result;
}
</code>
<code>int DoSomething() { int result; try { open_connection(); result = get_result(); } catch { result = 2; } close_connection(); return result; } </code>
int DoSomething() {
    int result;
    try {
        open_connection();
        result = get_result();
    }
    catch {
        result = 2;
    }
    close_connection();
    return result;
}

2

As you’ve apparently already surmised, yes, C++ provides the same capabilities without that mechanism. As such, strictly speaking, the try/finally mechanism is not really necessary.

That said, doing without it does impose some requirements on the way the rest of the language is designed. In C++ the same set of actions is embodied in a class’ destructor. This works primarily (exclusively?) because destructor invocation in C++ is deterministic. This, in turn, leads to some rather complex rules about object lifetimes, some of which are decidedly non-intuitive.

Most of the other languages provide some form of garbage collection instead. While there are things about garbage collection that are controversial (e.g., its efficiency relative to other methods of memory management) one thing generally isn’t: the exact time when an object will be “cleaned up” by the garbage collector is not tied directly to the scope of the object. This prevents its use when cleanup needs to be deterministic either when it’s simply required for correct operation, or when dealing with resources so precious that their cleanup most not be delayed arbitrarily. try/finally provides a way for such languages to deal with those situations that require that deterministic cleanup.

I think those claiming that C++ syntax for this capability is “less friendly” than Java’s are rather missing the point. Worse, they’re missing a much more crucial point about the division of responsibility that goes far beyond syntax, and has a great deal more to do with how code is designed.

In C++, this deterministic cleanup happens in the object’s destructor. That means the object can be (and normally should be) designed to clean up after itself. This goes to the essence of object oriented design–a class should be designed to provide an abstraction, and enforce its own invariants. In C++, one does precisely that–and one of the invariants for which it provides is that when the object is destroyed, the resources controlled by that object (all of them, not just memory) will be destroyed correctly.

Java (and similar) are somewhat different. While they do (sort of) support a finalize that could theoretically provide similar capabilities, the support is so weak that it’s basically unusable (and in fact, essentially never used).

As a result, rather than the class itself being able to do the required cleanup, the client of the class needs to take steps to do so. If we do a sufficiently short-sighted comparison, it can at first glance appear that this difference is fairly minor and Java is quite competitive with C++ in this respect. We end up with something like this. In C++, the class looks something like this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>class Foo {
// ...
public:
void do_whatever() { if (xyz) throw something; }
~Foo() { /* handle cleanup */ }
};
</code>
<code>class Foo { // ... public: void do_whatever() { if (xyz) throw something; } ~Foo() { /* handle cleanup */ } }; </code>
class Foo {
    // ...
public:
    void do_whatever() { if (xyz) throw something; }
    ~Foo() { /* handle cleanup */ }
};

…and the client code looks something like this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>void f() {
Foo f;
f.do_whatever();
// possibly more code that might throw here
}
</code>
<code>void f() { Foo f; f.do_whatever(); // possibly more code that might throw here } </code>
void f() { 
    Foo f;
    f.do_whatever();
    // possibly more code that might throw here
}

In Java we exchange a little more code where the object is used for a little less in the class. This initially looks like a pretty even trade-off. In reality, it’s far from it though, because in most typical code we only define the class in one place, but we use it many places. The C++ approach means we only write that code to handle the cleanup in one place. The Java approach means we have to write that code to handle the cleanup many times over, in many places–every place we use an object of that class.

In short, the Java approach basically guarantees that many abstractions we try to provide are “leaky”–any and every class that requires deterministic cleanup obliges the client of the class to know about the details of what to cleanup and how to do the cleanup, rather than those details being hidden in the class itself.

Although I’ve called it “the Java approach” above, try/finally and similar mechanisms under other names aren’t entirely restricted to Java. For one prominent example, most (all?) of the .NET languages (e.g., C#) provide the same.

Recent iterations of both Java and C# also provide something of a halfway point between “classic” Java and C++ in this regard. In C#, an object that wants to automate its cleanup can implement the IDisposable interface, which provides a Dispose method that’s (at least vaguely) similar to a C++ destructor. While this can be used via a try/finally like in Java, C# automates the task a little more with a using statement that lets you define resources that will be created as a scope is entered, and destroyed when the scope is exited. Though still well short of the level of automation and certainty provided by C++, this is still a substantial improvement over Java. In particular, the class designer can centralize the details of how to dispose of the class in its implementation of IDisposable. All that’s left for the client programmer is the lesser burden of writing a using statement to assure that the IDisposable interface will be used when it should be. In Java 7 and newer, the names have been changed to protect the guilty, but the basic idea is basically identical.

2

Can’t believe nobody else has raised this (no pun intended) – you don’t need a catch clause!

This is perfectly reasonable:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>try
{
AcquireManyResources();
DoSomethingThatMightFail();
}
finally
{
CleanUpThoseResources();
}
</code>
<code>try { AcquireManyResources(); DoSomethingThatMightFail(); } finally { CleanUpThoseResources(); } </code>
try 
{
   AcquireManyResources(); 
   DoSomethingThatMightFail(); 
}
finally 
{
   CleanUpThoseResources(); 
}

No catch clause anywhere is sight, because this method can’t do anything useful with those exceptions; they are left to propagate back up the call stack to a handler that can. Catching and re-throwing exceptions in every method is a Bad Idea, especially if you’re just re-throwing the same exception. It completely goes against how Structured Exception Handling is supposed to work (and is pretty close to returning an “error code” from every method, just in the “shape” of an Exception).

What this method does have to do, though, it to clean up after itself, so that the “Outside World” never needs to know anything about the mess that it got itself into. The finally clause does just that – no matter how the called methods behave, the finally clause will be executed “on the way out” of the method (and the same is true for every finally clause between the point at which the Exception is thrown and the eventual catch clause that handles it); each one is run as the call stack “unwinds”.

What would happen if and exception was thrown that you were not expecting. The try would exit in the middle of it and no catch clause is executed.

The finally block is to help with that and ensure that no matter the exception the cleanup will happen.

2

Some languages offer both constructors and destructors for their objects (e.g. C++ I believe). With these languages you can do most (arguably all) of what is usually done in finally in a destructor. As such – in those languages – a finally clause may be superfluous.

In a language without destructors (e.g. Java) it is difficult (maybe even impossible) to achieve correct cleanup without the finally clause. NB – In Java there is a finalise method but there is no guarantee it will ever be called.

4

Try finally and try catch are two different things which only share the: “try” keyword.
Personally I would have like to see that different. The reason you see them together is because exceptions produce a “jump”.

And try finally is designed to run code even if programming flow jumps out. Whether that be because of an exception or any other reason. It’s a neat way to acquire a resource and make sure it’s cleaned up after without having to worry about jumps.

2

Since this question doesn’t specify C++ as a language I’ll consider a mix of C++ and Java, since they take a different approach to object destruction, which is getting suggested as one of the alternatives.

Reasons you might use a finally block, rather than code after the try-catch block

  • you return early from the try block: Consider this

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>Database db = null;
    try {
    db = open_database();
    if(db.isSomething()) {
    return 7;
    }
    return db.someThingElse();
    } finally {
    if(db!=null)
    db.close();
    }
    </code>
    <code>Database db = null; try { db = open_database(); if(db.isSomething()) { return 7; } return db.someThingElse(); } finally { if(db!=null) db.close(); } </code>
    Database db = null;
    try {
     db = open_database();
     if(db.isSomething()) {
       return 7;
     }
     return db.someThingElse();
    } finally {
      if(db!=null)
        db.close();
    }
    

    compared with:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>Database db = null;
    int returnValue = 0;
    try {
    db = open_database();
    if(db.isSomething()) {
    returnValue = 7;
    } else {
    returnValue = db.someThingElse();
    }
    } catch(Exception e) {
    if(db!=null)
    db.close();
    }
    return returnValue;
    </code>
    <code>Database db = null; int returnValue = 0; try { db = open_database(); if(db.isSomething()) { returnValue = 7; } else { returnValue = db.someThingElse(); } } catch(Exception e) { if(db!=null) db.close(); } return returnValue; </code>
    Database db = null;
    int returnValue = 0;
    try {
     db = open_database();
     if(db.isSomething()) {
       returnValue = 7;
     } else {
       returnValue = db.someThingElse();
     }
    } catch(Exception e) {
      if(db!=null)
        db.close();
    }
    return returnValue;
    
  • you return early from the catch block(s) : Compare

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>Database db = null;
    try {
    db = open_database();
    db.doSomething();
    } catch (DBIntegrityException e ) {
    return 7;
    } catch (DBIsADonkeyException e ) {
    return 11;
    } finally {
    if(db!=null)
    db.close();
    }
    </code>
    <code>Database db = null; try { db = open_database(); db.doSomething(); } catch (DBIntegrityException e ) { return 7; } catch (DBIsADonkeyException e ) { return 11; } finally { if(db!=null) db.close(); } </code>
    Database db = null;
    try {
     db = open_database();
     db.doSomething();
    } catch (DBIntegrityException e ) {
      return 7;
    } catch (DBIsADonkeyException e ) {
      return 11;
    } finally {
      if(db!=null)
        db.close();
    }
    

    vs:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>Database db = null;
    try {
    db = open_database();
    db.doSomething();
    } catch (DBIntegrityException e ) {
    if(db!=null)
    db.close();
    return 7;
    } catch (DBIsADonkeyException e ) {
    if(db!=null)
    db.close();
    return 11;
    }
    db.close();
    </code>
    <code>Database db = null; try { db = open_database(); db.doSomething(); } catch (DBIntegrityException e ) { if(db!=null) db.close(); return 7; } catch (DBIsADonkeyException e ) { if(db!=null) db.close(); return 11; } db.close(); </code>
    Database db = null;
    try {
     db = open_database();
     db.doSomething();
    } catch (DBIntegrityException e ) {
      if(db!=null) 
        db.close();
      return 7;
    } catch (DBIsADonkeyException e ) {
      if(db!=null)
        db.close();
      return 11;
    }           
    db.close();
    
  • You rethrow exceptions. Compare:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>Database db = null;
    try {
    db = open_database();
    db.doSomething();
    } catch (DBIntegrityException e ) {
    throw convertToRuntimeException(e,"DB was wonkey");
    } finally {
    if(db!=null)
    db.close();
    }
    </code>
    <code>Database db = null; try { db = open_database(); db.doSomething(); } catch (DBIntegrityException e ) { throw convertToRuntimeException(e,"DB was wonkey"); } finally { if(db!=null) db.close(); } </code>
    Database db = null;
    try {
     db = open_database();
     db.doSomething();
    } catch (DBIntegrityException e ) {
      throw convertToRuntimeException(e,"DB was wonkey");
    } finally {
      if(db!=null)
        db.close();
    }
    

    vs:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>Database db = null;
    try {
    db = open_database();
    db.doSomething();
    } catch (DBIntegrityException e ) {
    if(db!=null)
    db.close();
    throw convertToRuntimeException(e,"DB was wonkey");
    }
    if(db!=null)
    db.close();
    </code>
    <code>Database db = null; try { db = open_database(); db.doSomething(); } catch (DBIntegrityException e ) { if(db!=null) db.close(); throw convertToRuntimeException(e,"DB was wonkey"); } if(db!=null) db.close(); </code>
    Database db = null;
    try {
     db = open_database();
     db.doSomething();
    } catch (DBIntegrityException e ) {
      if(db!=null)
        db.close();
      throw convertToRuntimeException(e,"DB was wonkey");
    } 
    if(db!=null)
      db.close();
    

These examples don’t make it seem too bad, but often you have several of these cases interacting and more than one exception/resource type in play. finally can help keep your code from becoming a tangled maintenance nightmare.

Now in C++ these can be handled with scope based objects. But IMO there are two disadvantges to this approach 1. syntax is less friendly. 2. Order of construction being the reverse of order of destruction can make things less clear.

In Java you can’t hook the finalize method to do your cleanup since you don’t know when it will happen – (well you can but thats a path filled with fun race conditions – JVM has a lot of scope in deciding when it destroys things – often its not when you expect it – either earlier or later than you might expect – and that can change as the hot-spot compiler kicks in… sigh…)

All that is logicaly “necessary” in a programming language are the instructions:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>assignment a = b
subtract a from b
goto label
test a = 0
if true goto label
</code>
<code>assignment a = b subtract a from b goto label test a = 0 if true goto label </code>
assignment a = b
subtract a from b
goto label
test a = 0
if true goto label

Any algorithm can be implemented using only the instructions above, all other language constructs are there to make programs easier to write and more understandable to other programmers.

See oldie worldy computer for actual hardware using such a minimal instruction set.

2

Actually the bigger gap to me is usually in the languages that support finally but lack destructors, because you can model all the logic associated with “cleanup” (which I’ll separate into two categories) through destructors at a central level without manually dealing with cleanup logic in every relevant function. When I see C# or Java code doing things like manually unlocking mutexes and closing files in finally blocks, that feels outdated and kinda like C code when all of that is automated in C++ through destructors in ways that frees humans of that responsibility.

However, I would still find a mild convenience if C++ included finally and it’s because there’s two types of clean-ups:

  1. Destroying/freeing/unlocking/closing/etc local resources (destructors are perfect for this).
  2. Undoing/rolling back external side effects (destructors are adequate for this).

The second one at least doesn’t map so intuitively to the idea of resource destruction, though you can do it just fine with scope guards which automatically roll back changes when they’re destroyed prior to being committed. There finally arguably provides at least a slightly (just by a teeny bit) more straightforward mechanism for the job than scope guards.

However, an even more straightforward mechanism would be a rollback block which I’ve never seen in any language before. It’s kind of a pipe dream of mine if I ever designed a language that involved exception-handling. It would resemble this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>try
{
// Cause external side effects. These side effects should
// be undone if we don't finish successfully.
}
rollback
{
// Reverse external side effects. This block is *only* executed
// if the 'try' block above faced a premature return out
// of the function. It is different from 'finally' which
// gets executed regardless of whether or not the function
// exited prematurely. This block *only* gets executed if we
// exited prematurely from the try block so that we can undo
// whatever side effects it failed to finish making. If the try
// block succeeded and didn't face a premature exit, then we
// don't want this block to execute.
}
</code>
<code>try { // Cause external side effects. These side effects should // be undone if we don't finish successfully. } rollback { // Reverse external side effects. This block is *only* executed // if the 'try' block above faced a premature return out // of the function. It is different from 'finally' which // gets executed regardless of whether or not the function // exited prematurely. This block *only* gets executed if we // exited prematurely from the try block so that we can undo // whatever side effects it failed to finish making. If the try // block succeeded and didn't face a premature exit, then we // don't want this block to execute. } </code>
try
{
    // Cause external side effects. These side effects should
    // be undone if we don't finish successfully.
}
rollback
{
    // Reverse external side effects. This block is *only* executed 
    // if the 'try' block above faced a premature return out 
    // of the function. It is different from 'finally' which 
    // gets executed regardless of whether or not the function 
    // exited prematurely. This block *only* gets executed if we 
    // exited prematurely from  the try block so that we can undo 
    // whatever side effects it failed to finish making. If the try 
    // block succeeded and didn't face a premature exit, then we 
    // don't want this block to execute.
}

That would be the most straightforward way to model side effect rollbacks, while destructors are pretty much the perfect mechanism for local resource cleanups. Now it only saves a couple extra lines of code from the scope guard solution, but the reason I so want to see a language with this in there is that side effect rollback tends to be the most neglected (but trickiest) aspect of exception-handling in languages that revolve around mutability. I think this feature would encourage developers to think about exception-handling the proper way in terms of rolling back transactions whenever functions cause side effects and fail to complete and, as a side bonus when people see how difficult it can be to do rollbacks properly, they might favor writing more functions free of side effects in the first place.

There are also some obscure cases where you just want to do miscellaneous things no matter what upon exiting a function, regardless of how it exited, like maybe logging a time stamp. There finally is arguably the most straightforward and perfect solution for the job, since trying to instantiate an object only to use its destructor for the sole purpose of logging a timestamp just feels really weird (even though you can do it just fine and quite conveniently with lambdas).

Like so many other unusual things about the C++ language, the lack of a try/finally construct is a design flaw, if you can even call it that in a language that frequently appears to not have had any actual design work done at all.

RAII (the use of scope-based deterministic destructor invocation on stack-based objects for cleanup) has two serious flaws. The first is that it requires the use of stack based objects, which are an abomination that violate the Liskov Substitution Principle. There are plenty of good reasons why no other OO language before or since C++ has used them–within epsilon; D doesn’t count as it’s based heavily on C++ and has no market share anyway–and explaining the problems they cause is beyond the scope of this answer.

Second, what finally can do is a superset of object destruction. Much of what is done with RAII in C++ would be described in the Delphi language, which does not have garbage collection, with the following pattern:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>myObject := MyClass.Create(arguments);
try
doSomething(myObject);
finally
myObject.Free();
end;
</code>
<code>myObject := MyClass.Create(arguments); try doSomething(myObject); finally myObject.Free(); end; </code>
myObject := MyClass.Create(arguments);
try
   doSomething(myObject);
finally
   myObject.Free();
end;

This is the RAII pattern made explicit; if you were to create a C++ routine that contains only the equivalent to the first and third lines above, what the compiler would generate would end up looking like what I wrote in its basic structure. And because it’s the only access to the try/finally construct that C++ provides, C++ developers end up with a rather myopic view of try/finally: when all you have is a hammer, everything starts to look like a destructor, so to speak.

But there are other things that an experienced developer can do with a finally construct. It’s not about deterministic destruction, even in the face of an exception being raised; it’s about deterministic code execution, even in the face of an exception being raised.

Here’s another thing you might commonly see in Delphi code: A dataset object with user controls bound to it. The dataset holds data from an external source, and the controls reflect the state of the data. If you’re about to load a bunch of data into your dataset, you will want to temporarily disable the data binding so that it doesn’t do strange things to your UI, trying to update it over and over with every new record that’s entered, so you would code it like this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>dataset.DisableControls();
try
LoadData(dataset);
finally
dataset.EnableControls();
end;
</code>
<code>dataset.DisableControls(); try LoadData(dataset); finally dataset.EnableControls(); end; </code>
dataset.DisableControls();
try
   LoadData(dataset);
finally
   dataset.EnableControls();
end;

Clearly, there is no object being destroyed here, and no need for one. The code is simple, concise, explicit, and efficient.

How would this be done in C++? Well, first you would have to code up an entire class. It would probably be called DatasetEnabler or somesuch thing. Its entire existence would be as a RAII helper. Then you would need to do something like this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>dataset.DisableControls();
{
raiiGuard = DatasetEnabler(dataset);
LoadData(dataset);
}
</code>
<code>dataset.DisableControls(); { raiiGuard = DatasetEnabler(dataset); LoadData(dataset); } </code>
dataset.DisableControls();
{
   raiiGuard = DatasetEnabler(dataset);
   LoadData(dataset);
}

Yes, those apparently-superfluous curly braces are necessary to manage the proper scoping and ensure that the dataset gets re-enabled immediately and not at the end of the method. So what you end up with does not take less lines of code (unless you use Egyptian braces). It requires a superfluous object to be created, which has overhead. (Isn’t C++ code is supposed to be fast?) It is not explicit, but instead relies upon compiler magic. The code that gets executed is described nowhere in this method, but instead resides in an entirely different class, possibly in an entirely different file. In short, it is in no way a better solution than being able to write the try/finally block yourself.

This kind of problem is common enough in language design that there’s a name for it: abstraction inversion. It occurs when a high-level construct is built on top of a low-level construct, and then the low-level construct is not directly supported in the language, requiring those who wish to use it to re-implement it in terms of the high-level construct, often at steep penalties to both code readability and efficiency.

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật