[net.lang.c] C-STYLE

ARPAVAX:UNKNOWN:G:elect (10/25/82)

For my two cents worth, I think the formatting

		if (<condition>) {
			<statements>;
			      :
			      :
			}

is the most aesthetically pleasing.  It does not seem that there's
any difference between this and the format where the closing brace
is lined up with the `if' as far as telling which block goes with
which conditional, as long as one sticks to one format throughout
a program.  For this reason, I think putting rules like this into
a `style manual' is unnecessary.  What do people think about some
people's practice of writing structure/union expressions like

		structure . member = struct_pointer - > member;

with all the spaces?  All of this discussion about style is probably
not going to have a hell of a lot of impact -- programmers as a 
lot are rather headstrong.  People are going to stick to whatever
style they like.  As long as the programmer is consistent and
documents his style conventions (to the extent that, say, identifiers
with all majuscule characters are `defined' constants and so on),
which means he's probably half-way serious about making his code
readable and maintainable, I don't see any problem with style.  If
someone is simply messy, no style manual is going to change things.
As far as big projects, of course, some convention should be
established for the sake of communication and productivity among
the many programmers who may be involved.

						Harry
				       ARPAnet:	G.antares@Berkeley
						LBLG!Harry#pdm@LBL-Unix
					  UUCP: ...!ucbvax!G:antares

jeff@isi-vaxa.ARPA (Jeffery A. Cavallaro) (08/23/86)

I am sure that this case of style has been brought up before.  It has been
bothering me for awhile.

Support a particular routine is supposed to perform N steps, where each step
is performed dependent on the success of the previous step, i.e., if any
step fails, then you want to clean up and return.

I realize that:

	if (
	    ( (status = step_1()) == SUCCESS) &&
	    ( (status = step_2()) == SUCCESS) &&
			.
			.
			.
	    ( (status = step_3()) == SUCCESS)
	);
	cleanup();
	return (status);

accomplishes this, but significantly ups the routine count.  Some refer to this
as good programming practice, but I tend to think of it as overkill for simple
jobs - especially when each routine requires a long header block as may be
required by various programming standards imposed upon (but maybe not accepted
by) the programmer.

Of course, there is the massively nested "if" string, but I can't stand that
style.  I tend to really get lost in such bird nests.

The way I like to do it is:

	setup_step_1;
	if ( (status = step_1()) == FAILURE )
	    goto abort_operation;

	setup_step_2;
	if ( (status = step_2()) == FAILURE )
	    goto abort_operation;

		.
		.
		.

	setup_step_n;
	if ( (status = step_n()) == FAILURE )
	    goto abort_operation;

abort_operation:

	cleanup();
	return (status);

Now, I know a lot of people detest this because of the use of goto's, but this
seems the nicest way to perform this function.  I really have nothing against
goto's if they are directed to the same spot (i.e., don't jump back and forth)
and enhance the readability of the code.

Any comments?  I am willing to adapt to another reasonable style for such
cases (if anyone really cared).

Thanx for any and all responses (even rude ones),
Jeff

toma@killer.UUCP (Tom Armistead) (08/27/86)

In article <3253@brl-smoke.ARPA>, jeff@isi-vaxa.ARPA writes:
> I am sure that this case of style has been brought up before.  It has been
> bothering me for awhile.
> 
> The way I like to do it is:
> 
> 	setup_step_1;
> 	if ( (status = step_1()) == FAILURE )
> 	    goto abort_operation;
> 
> 	setup_step_2;
> 	if ( (status = step_2()) == FAILURE )
> 	    goto abort_operation;
> 
> 		.
> 		.
> 		.
> 
> 	setup_step_n;
> 	if ( (status = step_n()) == FAILURE )
> 	    goto abort_operation;
> 
> abort_operation:
> 
> 	cleanup();
> 	return (status);
> 
> Now, I know a lot of people detest this because of the use of goto's, but this
> seems the nicest way to perform this function.  I really have nothing against
> goto's if they are directed to the same spot (i.e., don't jump back and forth)
> and enhance the readability of the code.
> 
> Any comments?  I am willing to adapt to another reasonable style for such
> cases (if anyone really cared).

There is always the use of setjmp and longjmp to acomplish this task,
sometging like this:

#include <setjmp.h>
#define FAILURE	1	/* cannot == 0, due to setjmp conventions */

routine()
{
	jmp_buf		env;	/* envireoment for setjmp,lonjmp */
	int		val,	/* used in return to setjmp */
			status;

	if (setjmp(env) == FAILURE)	/* if abort return, cleanup and exit */
		{
		cleanup();
		return(status);
		}
	/* setup_step_1 */
	if ((status = step_1()) == FAILURE)
		longjmp(env,FAILURE);	/* return to setjmp call w/FAILURE */

	/* setup_step_2 */
	if ((status = step_2()) == FAILURE)
		longjmp(env,FAILURE);	/* return to setjmp call w/FAILURE */

		.
		.
		.

	/* setup_step_n */
	if ((status = step_n()) == FAILURE)
		longjmp(env,FAILURE);	/* return to setjmp call w/failure */

		.
		.
		.

	/* continue on from here ... */
}

This will accomplish the same thing and possibly not affend the goto haters,
although it is somewhat harder to follow if you are no farmiliar with 
setjmp() and lonjmp().

Tom
---
UUCP:
                          ihnp4\
                                \killer!toma
                                /
  drillsys!infoswx!convex!dj3b1/

Tom Armistead

chris@umcp-cs.UUCP (Chris Torek) (08/30/86)

>In article <3253@brl-smoke.ARPA> jeff@isi-vaxa.ARPA writes:
>>	setup_step_1;
>>	if ( (status = step_1()) == FAILURE )
>>	    goto abort_operation;
	...
>>	setup_step_n;
>>	if ( (status = step_n()) == FAILURE )
>>	    goto abort_operation;
>>
>>abort_operation:
>>
>>	cleanup();
>>	return (status);

>>Now, I know a lot of people detest this because of the use of goto's ....

In article <264@killer.UUCP> toma@killer.UUCP (Tom Armistead) replies:
>There is always the use of setjmp and longjmp to acomplish this task ....
[example deleted]
>This will accomplish the same thing and possibly not affend the goto haters,
>although it is somewhat harder to follow if you are no farmiliar with 
>setjmp() and lonjmp().

Alas, longjmp() is nothing more than goto in disguise.  Indeed,
this is a far more powerful version of goto than the `plain C'
goto, and should by rights be correspondingly more offensive to
goto haters.  In general, when choosing between two existing
primitives, if one is less powerful but does what you need, use
that.  When designing primitives, the choice is more difficult:
something that does less is easier to understand, but you may need
too many of those things, making the whole harder to comprehend.

As to a specific solution to the original problem above, I think
there is no `best' answer, at least not without more information.
I happen to like the pointer table method proposed by grt@twitch;
it can be expanded in a useful way for recovery and/or error
explanation:

	int	dostep1(), dostep2(), dostep3(), dostep4();
	int	fix1or3(), fix2();

	struct step {
		char	*s_name;	/* name of this step */
		int	(*s_func)();	/* function that implements it */
		int	(*s_fixup)();	/* repair after error */
	} steps[] = {
		{ "step1",	dostep1,	fix1or3 },
		{ "step2",	dostep2,	fix2 },
		{ "step3",	dostep3,	fix1or3 },
		{ "step4",	dostep4,	0 },
		0			/* marks end of table */
	};

	f()
	{
		register struct step *s;
		int status;

		for (s = steps; s->s_func != NULL; s++) {
			if ((status = (*s->s_func)()) != SUCCESS) {
				if (s->s_fixup == NULL ||
				    (*s->s_fixup)(status) != SUCCESS) {
					fprintf(stderr, "\
	Unrecoverable failure in %s, code %d\n",
						s->s_name, status;
					break;
				}
			}
		}
		return (status);
	}

There may be cases, however, where a direct-coded state machine
with a `switch' statement would be better; and there may be cases
where the original code runs fastest and/or is clearest (whichever
is more important to the coder/maintainer and user).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu

cjl@iuvax.UUCP (09/02/86)

> /* ---------- "C-STYLE (goto?)" ---------- */
> ....
> 
> Now, I know a lot of people detest this because of the use of goto's, but this
> seems the nicest way to perform this function.  I really have nothing against
> goto's if they are directed to the same spot (i.e., don't jump back and forth)
> and enhance the readability of the code.
> 
> Any comments?  I am willing to adapt to another reasonable style for such
> cases (if anyone really cared).

The principle of exception handling in software engineering is
well accepted and practiced today, especially through the direct support of
Ada language. You shall find more and more people start to feel
comfortable with this disciplined use of goto.


C.J.Lo
Dept. of CIS, IUPUI
UUCP : ...!iuvax!cjl
ARPA : cjl@Indiana@CSNet-Relay

karl@haddock (09/11/86)

killer!toma (Tom Armistead) writes:
>In article <3253@brl-smoke.ARPA>, jeff@isi-vaxa.ARPA writes:
>>[code deleted]
>>Now, I know a lot of people detest this because of the use of goto's, but
>>this seems the nicest way to perform this function.
>
>There is always the use of setjmp and longjmp ...: [code deleted]
>This will accomplish the same thing and possibly not affend the goto haters,

Mother of swapper!  A longjmp is *worse* than a goto.  It's just a goto that
doesn't respect function boundaries!  Anyone who disapproves of goto but
considers longjmp acceptable is objecting to the keyword rather than the
concept ("I know goto is bad because my teacher said so").  (I'm not flaming
Tom; his posting did not imply approval.)

Lest you misunderstand me -- I am not a "goto hater".  There are three valid
uses of goto, one of which is error handling.  Jeff, your program is a good
example of proper goto usage.  Leave it that way, but learn why it's right.

Karl W. Z. Heuer (ima!haddock!karl; karl@haddock.isc.com), The Walking Lint