Hacker News new | past | comments | ask | show | jobs | submit login

>It's also true that with more experience, we've figured out that cleanup code is special.

In my experience the exact opposite is true. Error handling or "cleanup" code is in no way special. Errors are not exceptional and there is nothing we can say in general about what error handling code will or will not need to do.

Error handling code needs to be able to use the entire language and reuse all the regular code that is used elsewhere. A language should not have two modes, an error mode and a normal mode with completely different non-local semantics.

>And, as I asked earlier, if I throw an exception because I can't close a file, what do I expect the exception handler to do?

That depends entirely on the context of the program you're writing. It might want to do things like writing a record to a database that marks the file as invalid/corrupt. It may need to notify some other system about the failed action. It might want to roll back a transaction or initiate a compensating transaction. It may want to abort some session and schedule it to restart at a later time.

There is simply nothing we can know in general about what a caller of an action that failed to complete cleanly may want to do as a result of that failure.

Using exceptions for error states that may require a complex response is just not a good idea and in C++ it's an even worse idea.

[Edit] But to be clear, my initial thought wasn't about exception handling but rather about ubiquitous use of RAII for all sorts of stuff that needs to get done at the end of a scope. Much of that has nothing to do with errors at all. Maybe if you think of these situations it will become clearer why I think that arbitrary limitations of code that runs in a destructor is problematic. C++ has no finally block. Destructors is all we have.




I don't agree with much in this post, but in particular "Destructors is all we have": destructors + lambdas + templates allow you to write ScopeGuard, which is a pure superset of finally blocks. Modern C++ has zero need for finally.


ScopeGuard relies on destructors, so it inherits the no exceptions in destructors issue.


Throwing from a destructor in ScopeGuard is equivalent to calling a function that can throw in a catch or finally block, which you can do in most (any?) languages with exceptions. This no exceptions in destructors "issue" is not a C++ issue. It's a fundamental issue in error propagation. What do you do when propagating error correctly, causes a new error? You can't propagate the first error, because you can't do it correctly. You can't propagate the second error, because that would mean dropping the first.

Classic example is logging an error on failure. This means calling a logging function in the catch block, and then letting the exception propagate. But what if the call to the logging function fails? In Java, coded naively you'd simply drop the original exception. Usually that's not what you want.

You can examine the issue with error codes, it's not any better.


> But to be clear, my initial thought wasn't about exception handling but rather about ubiquitous use of RAII for all sorts of stuff that needs to get done at the end of a scope.

I agree with you on that. It turns out that, say, having a lock guard automatically release a lock when it falls out of scope can cause a ton of trouble when it falls out of scope in a place the programmer overlooked.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: