7 ms·
I feel that the "error" handling is one of those "core things" that people have rarely fully understood. Especially newbies starting are often confused and thin
by ensiferum 9y ago
I feel that the "error" handling is one of those "core things" that people have rarely fully understood. Especially newbies starting are often confused and things get muddled. In all honesty it took me +10 years myself to reach some kind of clarity on this. Anyway I find it that when you lack that clarity your code will be quite messy (isn't this always the case?) and things will get muddled. And since error handling is so precarious your implementation quality will suffer considerably.
So below is my take on this with 3 clear labels and guidelines on how to apply. Hope this helps.
There are 3 kinds of "errors".
1. Bugs.
- created by programmer.
- invalid state of the application - >it has transcended it's own logical realm and you can't reason about its behaviour anymore.
- null pointers, OOB, etc.
2. Errors that are "expected" part of the program execution.
- you need to write logic flow to deal with this
- it's expected and quite normal that this might happen
- incorrect (user) input, file not found, socket timed out etc.
- this is really just an error from the end user's perspective.
3. Errors that are "unexpected".
- some very unexpected error
- system resource allocation failed, out of memory, out of file handles etc.
- critical resource was not accessible (for example a "must have" config file was not found)
How to deal with these?
1. Abort and dump core. Yep seriously, just do it. Blow up with a bang and leave a stack trace that you can analyze in the post-mortem debugger and see what went wrong.
As a result your application will be simpler and more straightforward. Simply, don't try to write logic to deal with programmer failures. It will just clutter your program, mask the problem and make fixing it harder.
int divide(int x, int y) {
if (y == 0) {
throw std::string("Divide by zero");
}
return x / y;
}
passing y=0 the function is clearly a bug. It'd be much better to core dump here. Unless the function was designed with double purpose of validating the input and performing the actual function. I'd much rather split these into two different functions, since the core function may be called from different contexts, some of which might not require any input validation at all even. And the validation function clearly should not be using exceptions either since it's quite normal and expected that input from external sources (such as the user) can be malformed and you probably want to write logic that then bashes (sorry.. informs) the user about their wrong input.
2. Use error codes.
3. Use exceptions.
- fnl 9y agoAd #1: And bring down the whole process? Seriously, no, this is about the worse advice ever. Unless you are writing a tiny binary that works all on its own and on a single job/item, this is about as close as you can get to a mortal sin in any medium- or large-sized program. Figure out what the remaining viable state of the program is, report the error (yes, loudly!), and recover. This would be the far more correct advice for #1 (except for tiny binaries doing a single job only, as said).
- ensiferum 9y agoSo you're one of those people who try to weasel their way out and clutter program logic to try to deal with bugs instead of just fixing the bugs. Seriously, in some cases when you're going for example OOB, the only reasonable action is to dump core. Trust me. This will improve your program, not make it worse.
- fnl 9y agoWhilst your application is in shatters for minutes or hours, your customer hotline going crazy, and your CFO will hate you for having to return thousands of good $$$ to your company's clients for the outage, to make them happy again. Trust me, you don't want to bring down the whole house just to fix a pipe...
- ensiferum 9y agoTo me this is an orthogonal problem. Ultimately high availability (in this context) is about making your software correct. When your software is correct you won't have availability issues because of bugs. Meanwhile if your software does crash (or terminate in a controlled fashion) but you need high availability you'll need to restart it automatically.
- fnl 9y agoThere is no such thing as an "orthogonal problem" here, both things connect. That's why you (a) want to have your processes staying alive in about any software as long as possible (hence invalidating your argument for #1), and (b) as I clearly mentioned, you do need to report such unexpected errors to the developer of the program, to avoid that they get swept under the rug. But handling cases from #1 as you described is nonviable in (virtually) all cases (except as described: if the error prevents the binary from completing that single job it was run on). Just imagine any of the programs you are running on your machine right now would just crash because they are not resilient to an off-by-one fencing error or whatever other bug (and there will be issues, even in your three-liners). I bet you'd be pretty pissed off if your programs would crash on you every other day or so...