break, continue, return, goto

BALDWIN mike at whuxl.UUCP
Wed Nov 13 16:49:48 AEST 1985


> Craig made good suggestions for not using "continue" and "break"
> especially for the examples of Michael. "Continue" goto the beginning
> of the loop. Replacing it with "else" would make the logic flow of the
> codes following the "break" more smoothly.
>  
>   "Break" is generally interpreted as an exception where logic flow 
> is disrupted.

But not disrupted in the sense of a goto; it is stricter.

> But for the searching problem, both found and not found
> are normal results. We can hardly interpret "not found" as an undesired
> result.

I said:  I use *continue* and *returns* for errors, and *break* for
search loops -- I never said that using break in that context was
meant to indicate an error.

> In general exception, like error in system call,  will lead to 
> program abnormal termination. Error recovery is hard to achieve, because
> logic flow is disrupted.

You're exactly right.  That's why continue and return are so nice.
They give a reasonably clean way of dealing with these kinds of
logic disruptions.

> Too many times, programmers are seduced by 
> the use of break for a quick solution without spending time to structure 
> their program more. That is the same lesson we learned from advocating 
> goto-less programs.

Oh, baloney!  I happen to think that my use of continue/return/break in
my code is perfectly well thought out and structured.  If you think it's
not just *BECAUSE* it uses continue/return/break, you're being too hasty.
BREAK, RETURN AND CONTINUE ARE NOT THE SAME AS GOTO, FOLKS.  IF THEY WERE,
THEY'D ALL BE CALLED "GOTO".

>   In addition, I recommend the use of for loop be restricted to 
> its original meaning in natural language, i.e. as a loop with simple 
> counter.

*Sigh*, not this again.  The generalized for loop is one of the better
things about C.  WHY do you want this silly restriction?  IF a for loop
is being used with a simple counter, it will have one of a few forms,
e.g., for (i = 0; i < MAX; i++).  If YOU don't like funny for loops, then
only use that form.  And if you or I see that generic form, we KNOW that
it's a simple for loop.  So what's the big problem?  If you don't have the
general for loop, you say

	expr1;
	while (expr2) {
		stmt;
		expr3;
	}

And now expr1, 2, and 3 are all split up.  There are cases where they
logically belong together but don't fit into the simple counter loop
model, and this is exactly what the for loop is for!

> With more complicate exit conditions, while loop fits better :
> 
>  	m = meeble;
>  	while ((m < meeble+NMEEBLE) && (m->glop==forp || m->zip==fweep)){
>           /* walk thru the array till we hit the end or
>            * find the right one */
>            ++m;
>         };
>  	if (m < meeble + NMEEBLE) {
>          /* found it */
>            printf("zeegle %2s", m->yorg);
>            m->blazzo += IGUAP;
>  	} else {
>          /* not found it */
>         }
> 

Sorry, I don't buy it.  Here's the original code, that to me
just plain looks simpler and better:

	for (m = meeble; m < meeble + NMEEBLE; m++)
		if (m->glop == forp || m->zip == fweep) {
			printf("zeegle %2s", m->yorg);
			m->blazzo += IGUAP;
			break;
		}

In *THIS* version, the for loop is immediately recognizable as a
simple for loop, and all the looping business with m is in one
place.

This really looks like another stupid religious style issue; which
one of the two versions is in an absolute sense "better" cannot be
determined.  I prefer the latter, but the former is also acceptable
to me.  But you go so far as to say that the mere *USE* of break
implies quick, hasty, poor design choices.  That's going too far.

> In some language like Pascal there is no conditional boolean operator, 
> we have to use boolean flages. With the availability of && and || in C,
> exit conditions can be coded more explicitly than with boolean flags.

Conditional and/or is another one of the great things C has.  This is
an aside, but most arguments against break/etc are that it isn't all
pretty and provable.  Well, && and || are much more of a pain to prove
right in code than Pascal-ish and/or, and assignments in expressions
wreak havoc.  But I'm trying to write a program, not a thesis.

In one of my courses, we used a very nifty language that was well-suited
to logical proofs.  The if stmt was like a lisp cond, and the easiest,
cleanest way to describe it was that it picked one of the true clauses
*at random*.  None of this annoying ordering (as in && and ||) and no
"else".  It really is a very elegant and beautiful language and you can
write proofs for programs easily, but *it's not supposed to be a real
language* (I mean, how would you implement a non-deterministic if?).
But a *real* language needs else, &&, ||, break, etc.

Can anyone suggest a recoding of the following example without using
multiple returns?  Of course it can be done, but in a clearer, simpler
way?  Remember, this is exactly the same as using loops with continue.

core(file)
char	*file;
{
	if ((fd = open(file, O_RDONLY)) < 0) {
		perror(file);
		return;
	}
	if ((n = read(fd, &u, sizeof u)) == 0) {
		puts("zero length");
		return;
	}
	if (n < sizeof u) {
		puts("too small");
		return;
	}
	if (BADMAG(u.u_exdata.ux_magic)) {
		puts("not a core dump");
		return;
	}

	/* process core dump */
	printf("%d/%d %s", u.u_uid, u.u_gid, ctime(&u.u_start));
	printf("$ %s\n", u.u_comm);
	/* ... etcetera */
}
-- 
						Michael Baldwin
						{at&t}!whuxl!mike



More information about the Comp.lang.c mailing list