Like a lot of black-and-white articles, there's a grain of truth there, but you're going too far.
Let’s start with the cost of exceptions.
Yes, exceptions cost — but all error handling is expensive, if it’s an actual error.
I was in a codebase where exceptions were prohibited — but there were deep chains of calls that returned JSON structures, and because there were no exceptions, at each level we had to check the returned structure to see if there were an error and if so return it.
This was C++ and that meant that the Return Value Optimization did not occur, but more, this meant these little repetitive scribbles of error handling all over the code, in almost a hundred places — and more, as I audited the code, there were places where we should have checked the error codes and were not.
And without exceptions, you have no choice. Every time you call a function that might go wrong, you need to check an error code. More, if a function suddenly starts having the possibility of error, you need to check everywhere it is called to make sure you are checking that error, and propagating it up.
The result is that your code pays for the constant cost of checking error codes but in regular operation these codes might never be set!
In C++, a try/catch block where the exception is never thrown is free. In Python, such try/catch blocks aren’t totally free, but cost less than an if
statement.
So by eschewing raise
or throw
statements, you are making exceptions and errors a little faster, at the cost of making regular operation a little slower.
If exceptions are rare, as they should be, then this is a net loss to your program.
—
The other issue with error handling through return codes or the like is that it makes debugging much harder.
An exception keeps all the information about where it was caused and where it was caught. If you drop this into your log file, then you can see the entire train of events that lead to the problem. Some systems will even let you print the local variables at the point that the exception occurred.
But many’s the time I get a call that there’s a problem and I find out that at the top level, the program got an return code of 1
or -1
. This is useless to me. I have to go sifting through the logs. It’s quite likely that there’s nothing useful — so now I have to guess where the issue might be, instrument the program considerably, and run it again and hope the issue happens again.
I would add that again, those copious logs you now need are a cost that you pay during normal operation, in order to deal with a tiny number of exceptional conditions — but a system that catches exceptions near the top and saves them costs nothing or almost nothing in normal operation.