C style

preece at ccvaxa.UUCP preece at ccvaxa.UUCP
Thu Oct 24 13:31:00 AEST 1985


> LOOP-EXIT-END constructs is aimed to warn explicitly the existence of
> multi-exit points in a loop in modern languages. They are harder to
> understand and reason. Enforcing the use of LOOP-EXIT-END to replace
> the break statement means the simple, natural meaning of for,while and
> do loops is recovered. Therefore the program is more readable because
> loops of different complexity are exposed as they should be.  /*
> Written  3:27 pm  Oct 21, 1985 by cjl at iuvax in ccvaxa:net.lang.c */
----------
I read that (admittedly with some difficulty and room for error) as
saying "Complicated loops ought to look complicated."  It is not
hard to produce an example of a loop which is much more readable
with breaks than with the use of many levels of nesting to
reflect a sequence of computations followed by tests for loop
terminating conditions.  I'll try:

Here's a nice, but deeply nested loop:

    checkreturn = OK;
    for (i=0; i<100 && checkreturn==OK; i++) {
        checkreturn = function1(x);
	if (checkreturn == OK) {
	    checkreturn = function2(x);
	    if (checkreturn == OK) {
	        checkreturn = function3(x);
		if (checkreturn == OK) {
		    checkreturn = function4(x);
		    if (checkreturn == OK) {
		        checkreturn = function5(x);
			if (checkreturn == OK) {
			    result[i] = function6(x);
			}
		        else {
		            result[i] = 0;
		    	}
		    }
		}
	    }
	}
    }

The idea is that the functions are applied in sequence and that
an error can abort computation at any point in the sequence,
stopping execution of the loop.

Now consider the same loop coded with the break statement:

    for (i=0; i<100; i++) {
        checkreturn = function1(x);
	if (checkreturn == BAD) break;

	checkreturn = function2(x);
	if (checkreturn == BAD) break

	checkreturn = function3(x);
	if (checkreturn == BAD) break;

	checkreturn = function4(x);
	if (checkreturn == BAD) break;

	checkreturn = function5(x);
	if (checkreturn == BAD)
	    result[i] = 0;
	else
	    result[i] = function6(x);
    }

Now I'll agree that the nested form better models function with form,
and I'm a great admirer of Louis Sullivan, but in this case I think
the break form is more READABLE to a HUMAN observer.  I think it
better shows that a SEQUENCE of tests is being applied and I think
that the use of the break statement makes it MUCH clearer that
failure of any function leads to termination of the loop, especially
in a real-world example where the nested code may cover several
pages or many screens.

I confess, though (and the faint-hearted might want to skip this
example), I'd probably prefer to see it like this:

    for (i=0; i<100; i++) {
        if ((checkreturn = function1(x)) == BAD) break;

	if ((checkreturn = function2(x)) == BAD) break;

	if ((checkreturn = function3(x)) == BAD) break;

	if ((checkreturn = function4(x)) == BAD) break;

	if ((checkreturn = function5(x)) == BAD) 
	    result[i] = 0;
	else
	    result[i] = function6(x);
    }

FOR ME, vertical whitespace is the enemy of comprehension.  I want
to see a logical unit presented as densely as possible, so long as
things are done in a comprehensibly systematic and orderly way.
In my last example all the constructions are parallel; once you
recognize the pattern, the whole is clearly exposed as a sequence.

The nested example hides the semantic structure in syntactic
structure and is a real pain in the ass when the work done at each
level is even moderately complicated.  The simple, mechanical
application of structuring rules produces a representation that
is perfectly accurate but visually cluttered.  That clutter makes
the representation much harder to work with, especially in a
small-window environment.

-- 
scott preece
gould/csd - urbana
ihnp4!uiucdcs!ccvaxa!preece



More information about the Comp.lang.c mailing list