Glad you posted this as a question. :)
I was trying to say that destructors and finally
are conceptually different:
- Destructors are for releasing resources (data)
finally
is for returning to the caller (control)
Consider, say, this hypothetical pseudo-code:
try {
bar();
} finally {
logfile.print("bar has exited...");
}
finally
here is solving entirely a control problem and not a resource management problem.
It wouldn't make sense to do that in a destructor for a variety of reasons:
- No thing is being "acquired" or "created"
- Failure to print to the log file will not result in resource leaks, data corruption, etc. (assuming that the logfile here is not fed back into the program elsewhere)
- It is legitimate for
logfile.print
to fail, whereas destruction (conceptually) cannot fail
Here's another example, this time like in Javascript:
var mo_document = document, mo;
function observe(mutations) {
mo.disconnect(); // stop observing changes to prevent re-entrance
try {
/* modify stuff */
} finally {
mo.observe(mo_document); // continue observing (conceptually, this can fail)
}
}
mo = new MutationObserver(observe);
return observe();
In the above example, again, there are no resources to be released.
In fact, the finally
block is acquiring resources internally to achieve its goal, which could potentially fail. Hence, it doesn't make sense to use a destructor (if Javascript had one).
On the other hand, in this example:
b = get_data();
try {
a.write(b);
} finally {
free(b);
}
finally
is destroying a resource, b
. It's a data problem. The problem is not about cleanly returning control to the caller, but rather about avoiding resource leaks.
Failure is not an option, and should (conceptually) never occur.
Every release of b
is necessarily paired with an acquisition, and it makes sense to use RAII.
In other words, just because you can use either to simulate either that doesn't mean both are one and the same problem or that both are appropriate solutions for both problems.