A while back I switched the way I handled c style errors.
I found a lot of my code looked like this:
int errorCode = 0;
errorCode = doSomething();
if (errorCode == 0)
{
errorCode = doSomethingElse();
}
...
if (errorCode == 0)
{
errorCode = doSomethingElseNew();
}
But recently I've been writing it like this:
int errorCode = 0;
do
{
if (doSomething() != 0) break;
if (doSomethingElse() != 0) break;
...
if (doSomethingElseNew() != 0) break;
} while(false);
I've seen a lot of code where nothing gets executed after there's an error, but it has always been written in the first style. Is there anyone else who uses this style, and if you don't, why?
Edit: just to clarify, usually this construct uses errno
otherwise I will assign the value to an int
before breaking. Also there's usually more code than just a single function call within the if (error == 0 )
clauses. Lots of good points to think on, though.
Your method isn't really bad and it's not unreadable like people here are claiming, but it is unconventional and will annoy some (as you noticed here).
The first one can get REALLY annoying after your code gets to a certain size because it has a lot of boilerplate.
The pattern I tended to use when I couldn't use exceptions was more like:
Your second function should be inlined into the first if you put the correct magic incantations in the signature, and each function should be more readable.
This is functionally identical to the while/bail loop without the unconventional syntax (and also a bit easier to understand because you separate out the concerns of looping/error handling from the concerns of "what does your program do in a given loop".
I've used the technique in a few places (so you aren't the only one who does it). However, I don't do it as a general rule, and I have mixed feelings about it where I have used it. Used with careful documentation (comments) in a few places, I'm OK with it. Used everywhere - no, generally not a good idea.
Relevant exhibits: files sqlstmt.ec, upload.ec, reload.ec from SQLCMD source code (not, not Microsoft's impostor; mine). The '
.ec
' extension means that the file contains ESQL/C - Embedded SQL in C which is pre-processed to plain C; you don't need to know ESQL/C to see the loop structures. The loops are all labelled with:Honestly the more effective C/C++ programmers I've known would just use a gotos in such conditions. The general approach is to have a single exit label with all cleanup after it. Have only one return path from the function. When the cleanup logic starts to get complicated/have conditionals, then break the function into subfunctions. This is pretty typical for systems coding in C/C++ imo, where the APIs you call return error codes rather than throw exceptions.
In general, gotos are bad. Since the usage I've described is so common, done consistently I think its fine.
I think the first one gives you more control over what to do with a particular error. The second way only tells you that an error occurred, not where or what it was.
Of course, exceptions are superior to both...
Make it short, compact, and easy to quickly read?
How about:
Why not replace the do/while and break with a function and returns instead?
You have reinvented goto.