Re: Breaking from the middle of a loop (C++)
On Jan 31, 3:56 am, "Daniel T." <danie...@earthlink.net> wrote:
"Alf P. Steinbach" <al...@start.no> wrote:
The subject of how to best express a logical
"loop-and-a-half" has popped up in a number of recent
[clc++] threads.
The language, C++, is a bit important because in C++ all
code must be prepared for exceptions at any point, so that
in this language the possibility of missed cleanup due to
early exit is not an issue.
There is a long history in both C and C++ of a "single-entry,
multiple exit" style of programming, whether the extra exits
are return, break, or sometimes even goto statements.
IMHO, there are two issues involved, and Alf very carefully
crafted his example to address just one. His code does NOT
break the single entry/single exit mold. The only difference is
that his exit point is in the middle of the loop---he has, in
fact, two sets of invariants: a weak set (no valid command has
been entered) which holds for the first half of the loop, and a
stronger set (an invalid command has been entered) for the
second half. If I understand Alf correctly, this is the issue
he wants to address---he's not trying to argue that you can
write just anything, or leave the loop in any old way.
Note that there is a radical difference between the two. I find
it notably simpler to reason about a loop if there is only one
invariant involved---I explained this in my response to Alf.
But there is still a single exit. Multiple exits from a loop
cause problems not only with reasoning about the code, but make
it almost impossible to read.
[...]
Of course C++'s exception system has practically canonized the
multiple exit style.
Throw is just a goto, all dressed up:-). There's a sense in
which that's true, but...
So are exit(), or abort(), or assert( cond ), when the assertion
fails. There are cases where you want to say: things have
gotten so bad that I can't reason about it anymore. All bets
are off. If the program only does one thing, then abort or exit
with an error message is fully appropriate. But a lot of
programs (including almost all I write), do do more than one
thing---just because all bets are off for one client request
doesn't mean that I can crash the server, and not handle other,
more reasonable requests. Exceptions are a good mechanism for
aborting some sub-processing.
Obviously, they shouldn't be abused. Throwing an exception for
something that should be handled by the algorithm (and thus
making the exception path part of the algorithm's execution
path) is just another way of creating spaghetti, and very
quickly leads to unreadable (and unverifiable) code.
Even if I have no wish to program in that style, a library
provider can force it on me so I have to always be prepared...
Several prominent authors in the C++ community have commented
on the difficulty of writing code that is correct in the face
of exceptions. It seems to be quite a big stumbling block.
I tend to favor something like variant 2 above, avoiding both
conditionals with side-effects and premature exits from blocks
of code. I am in such a habit of using that particular
variant that my functions usually have a variable labeled
"result" and take on a characteristic:
T func() {
T result = default;
// computation
return result;
}
That's easily the best idiom when you have a reasonable default.
Alf's example didn't.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34