[net.lang.c] An amusing piece of code

tim@ism780c.UUCP (Tim Smith) (04/05/86)

Here is an amusing piece of code that someone who wants to remain
annonymous invented.

The situation is that we have something that, if written with if-then-else
would be

	if ( thing == A )
		A-code;
	else
	if ( thing == B || thing == C || thing == D ) {
		switch ( thing ) {
	case B:         B-code; break;
	case C:         C-code; break;
	case D:         D-code; break;
		}
		BCD-common-code;
	} else
	if ( thing == E )
		E-code;

A, B, C, D, and E are constant expressions, so this is not elegant.
We would like to use a switch for everything.  Here is a solution:

	switch ( thing ) {
case A:         A-code; break;
case B:         B-code; if ( 0 ) {
case C:         C-code; if ( 0 ) {
case D:         D-code; }}
		BCD-common-code; break;
case E:         E-code;
	}

Noone here has been able to come up with a reasonable style for this.  The
example above is not to bad, but if B-code, C-code, etc, are complicated,
then it starts to get ugly.


-- 

Tim Smith       sdcrdcf!ism780c!tim || ima!ism780!tim || ihnp4!cithep!tim

PS: I bet you were relieved that I didn't say you invented this, right Darryl?

geoff@desint.UUCP (Geoff Kuenning) (04/06/86)

In article <1370@ism780c.UUCP> tim@ism780c.UUCP (Tim Smith) writes:

> The situation is that we have something that, if written with if-then-else
> would be
> 
> 	if ( thing == A )
> 		A-code;
> 	else
> 	if ( thing == B || thing == C || thing == D ) {
> 		switch ( thing ) {
> 	case B:         B-code; break;
> 	case C:         C-code; break;
> 	case D:         D-code; break;
> 		}
> 		BCD-common-code;
> 	} else
> 	if ( thing == E )
> 		E-code;
> 
[followed by code that makes me puke]

(1)	switch (thing)
	    {
	    case A:
		A-code;
		break;
	    case B:
		B-code;
		BCD-common-code ();
		break;
	    case C:
		C-code;
		BCD-common-code ();
		break;
	    case D:
		D-code;
		BCD-common-code ();
		break;
	    case E:
		E-code;
		break;
	    }

(2)	switch (thing)
	    {
	    case A:
		A-code;
		break;
	    case B:
	    case C:
	    case D:
		switch (thing)
		    {
		    case B:
			B-code;
			break;
		    case C:
			C-code;
			break;
		    case D:
			C-code;
			break;
		    }
		BCD-common-code ();
		break;
	    case E:
		E-code;
		break;
	    }

(3)	switch (thing)
	    {
	    case A:
		A-code;
		break;
	    case B:
		B-code;
		goto common;
	    case C:
		C-code;
		goto common;
	    case D:
		D-code;
common:
		BCD-common-code;
		break;
	    case E:
		E-code;
		break;
	    }

Moral:  don't be so rabid about avoiding goto's that you wind up with
something even uglier.  It makes you look foolish.
-- 

	Geoff Kuenning
	{hplabs,ihnp4}!trwrb!desint!geoff

aglew@ccvaxa.UUCP (04/06/86)

>/* Written 10:10 pm  Apr  4, 1986 by tim@ism780c.UUCP in ccvaxa:net.lang.c */
>[Describes a code structure that looks reasonably ugly with if-then-elses]
>[I'll include it at the bottom of this letter for reference]
>We would like to use a switch for everything.  Here is a solution:
>
>	switch ( thing ) {
>case A:         A-code; break;
>case B:         B-code; if ( 0 ) {
>case C:         C-code; if ( 0 ) {
>case D:         D-code; }}
>		BCD-common-code; break;
>case E:         E-code;
>	}
>
>Noone here has been able to come up with a reasonable style for this.  The
>example above is not to bad, but if B-code, C-code, etc, are complicated,
>then it starts to get ugly.

I find it amusing to now be in the position of advocating `unstructured' 
goto code, since in my last job I was the evangelist of structured programming.
Oh, well, into the fray...

May I make a modest suggestion? The above code is a classic example of 
converging flows of control. Write it:

   switch ( thing ) {
       case A:	   A-code;     break;

       case B:	   B-code;     goto BCDcode;
       case C:	   C-code;     goto BCDcode;
       case D:	   D-code;     goto BCDcode;

         BCDcode:  BCD-common-code; break;

       case E:	   E-code;     break;
   }

Notes: (1) DO NOT cut out the goto BCDcode after D-code. Fall through should 
never be used in this type of situation, since it can cause awkward bugs
if the D case gets moved around. (2) I have tried to use the indentation 
above to indicate that BCDcode is subordinate to cases B, C, and D.
(3) Try to choose a reasonably meaningful name for the label.

Now, I ask you: which is more easily readable? The goto code, or those if(0) {
abominations in the example above? Or the original if-then-else code, which
I include here?

>	if ( thing == A )
>		A-code;
>	else
>	if ( thing == B || thing == C || thing == D ) {
>		switch ( thing ) {
>	case B:         B-code; break;
>	case C:         C-code; break;
>	case D:         D-code; break;
>		}
>		BCD-common-code;
>	} else
>	if ( thing == E )
>		E-code;
>
>A, B, C, D, and E are constant expressions, so this is not elegant.
>We would like to use a switch for everything.  Here is a solution:

A last word - gotos are often the most elegant means of implementing
complicated structures. Whether you should be using such complicated
structures is another question - for me, finding that I can code 
something more cleanly with gotos than with conventional structures
sets the flag <There is probably something wrong with this algorithm>.
As well it should. But gotos should not be thrown out.

Structured programming != gotoless programming

(Does anybody know Dr. Goto from Japan? I believe he's now a motor behind
the Fifth Generation Computer Project.)

Andy "Krazy" Glew. Gould CSD-Urbana.    USEnet:  ihnp4!uiucdcs!ccvaxa!aglew
1101 E. University, Urbana, IL 61801    ARPAnet: aglew@gswd-vms

chris@umcp-cs.UUCP (Chris Torek) (04/06/86)

In article <1370@ism780c.UUCP> tim@ism780c.UUCP (Tim Smith) writes:
>The situation is that we have something that, if written with if-then-else
>would be
>
>	if ( thing == A )
>		A-code;
>	else
>	if ( thing == B || thing == C || thing == D ) {
>		switch ( thing ) {
>	case B:         B-code; break;
>	case C:         C-code; break;
>	case D:         D-code; break;
>		}
>		BCD-common-code;
>	} else
>	if ( thing == E )
>		E-code;
>
>A, B, C, D, and E are constant expressions, so this is not elegant.
>We would like to use a switch for everything.

[followed by code using `if (0) {', which works, since case labels
are just that---*labels*---and are effectively `goto'ed.]

Beware!  Here is yet another opportunity for us `goto-ists' to come
out of the woodwork.  I include here an actual example from a piece
of my own code.  (I should probably change the gotos to be forward
references, rather than backward, though I am not certain it would
help.)

	/*
	 * Now that we have the parameter, perform the
	 * command.
	 */
	switch (DVI_DT(c)) {
	.
	.	[some material deleted]
	.

	case DT_DOWN:
move_down:
		dvi_v += p;
		/*
		 * `Vertical motion is done similarly, but
		 * with the threshold between ``small'' and
		 * ``large'' increased by a factor of 5.  The
		 * idea is to make fractions like $1\over2$
		 * round consistently, but to absorb
		 * accumulated rounding errors in the
		 * baseline-skip moves.'
		 */
		if (ABS(p) >= CurrentFont->vspace)
			vv = SPtoDEV(dvi_v);
		else {
			vv += SPtoDEV(p);
			p = SPtoDEV(dvi_v);
			FIXDRIFT(vv, p);
		}
		break;

	case DT_Y:
		dvi_y = p;
		goto move_down;

	case DT_Z:
		dvi_z = p;
		goto move_down;

	.
	.
	.
	}
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1415)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu

david@ukma.UUCP (David Herron, NPR Lover) (04/06/86)

In article <1370@ism780c.UUCP> tim@ism780c.UUCP (Tim Smith) writes:
>Here is an amusing piece of code that someone who wants to remain
>annonymous invented.

Good idea :-).

> ...
>        switch ( thing ) {
>case A:         A-code; break;
>case B:         B-code; if ( 0 ) {
>case C:         C-code; if ( 0 ) {
>case D:         D-code; }}
>                BCD-common-code; break;
>case E:         E-code;
>        }
>
>Noone here has been able to come up with a reasonable style for this.  The
>example above is not to bad, but if B-code, C-code, etc, are complicated,
>then it starts to get ugly.

I don't like this either... it's not very straightforward, but ALSO,
there's a potential problem I think.  "case D:" exits TWO levels
of context and never entered ANY, case C: exits TWO but only entered ONE.
(Is this ever a problem?  I can see that it "might" be, but I'm also
sure that the PCC will run it fine.)

What about:

	switch(thing) {
	case A:	A-code; break;
	case B: B-code; goto BCD-common;
	case C: C-code; goto BCD-common;
	case D: D-code;
	BCD-common: BCD-code; break;
	case E: E-code;
	}

I know, EVIL NASTY goto statements.  But this is a limited local use
of goto's and surely that should be allowable except for the most
rabid of structurists.  Especially if there is commentation pointing
the reader toward BCD-common:.
-- 
David Herron,  cbosgd!ukma!david, david@UKMA.BITNET, david@uky.csnet

LINNDR%VUENGVAX.BITNET@wiscvm.ARPA (04/06/86)

In posting<1370@ism780c.UUCP>, Tim Smith asks about a switch with common
code for some cases. I have seen two solutions.

1) put the common code in a subroutine
        switch(thing) {
        case A: A-code; break;
        case B: B-code; BCD-common-code(); break;
        case C: C-code; BCD-common-code(); break;
        case D: D-code; BCD-common-code(); break;
        case E: E-code; break;
        }

2) use the much abused goto statment
        switch(thing) {

        case A: A-code; break;

        case B: B-code; goto BCD_common;

        case C: C-code; goto BCD_common;

        case D: D-code;

    BCD_common: BCD-common-code;
                break;

        case E: E-code; break;
        }


Hope one of these helps you.

David Linn
----------------------------------------------------------
BITNET:         LINNDR@VUEngVAX.BITNET or PEARL@VANDVMS1.BITNET
MAILNET:        LINN_D_R    \
                David_R_Linn >@VANDERBILT.MAILNET
                David_Linn  /
CSNET:          drl@vanderbilt.csnet
SnailMail:      P.O. 3241-B Vanderbilt
                Nashville, TN   37235

robertv@tekla.UUCP (Robert Vetter) (04/07/86)

In article <1370@ism780c.UUCP> tim@ism780c.UUCP (Tim Smith) writes:
>Here is an amusing piece of code that someone who wants to remain
>annonymous invented.
>
>The situation is that we have something that, if written with if-then-else
>would be
>
>	if ( thing == A )
>		A-code;
>	else
>	if ( thing == B || thing == C || thing == D ) {
>		switch ( thing ) {
>	case B:         B-code; break;
>	case C:         C-code; break;
>	case D:         D-code; break;
>		}
>		BCD-common-code;
>	} else
>	if ( thing == E )
>		E-code;
>
>A, B, C, D, and E are constant expressions, so this is not elegant.
>We would like to use a switch for everything.  Here is a solution:
>
>	switch ( thing ) {
>case A:         A-code; break;
>case B:         B-code; if ( 0 ) {
>case C:         C-code; if ( 0 ) {
>case D:         D-code; }}
>		BCD-common-code; break;
>case E:         E-code;
>	}
>
>Noone here has been able to come up with a reasonable style for this.  The
>example above is not to bad, but if B-code, C-code, etc, are complicated,
>then it starts to get ugly.
>
>
>-- 
>
>Tim Smith       sdcrdcf!ism780c!tim || ima!ism780!tim || ihnp4!cithep!tim
>
>PS: I bet you were relieved that I didn't say you invented this, right Darryl?



	Why not : 


	switch ( thing ) {
            case A:         A-code;
                            break;

            case B:         B-code;
		            BCD-common-code();
                            break;

            case C:         C-code;
		            BCD-common-code();
                            break;

            case D:         D-code;
		            BCD-common-code();
                            break;

            case E:         E-code;
	}
	

	It's structured and readable.


Rob Vetter
(503) 629-1291
[ihnp4, ucbvax, decvax, uw-beaver]!tektronix!tekla!robertv

"Waste is a terrible thing to mind" - NRC
  (Well, they COULD have said it)

darryl@ism780c.UUCP (Darryl Richman) (04/07/86)

I'd appreciate it if you didn't drag my good name throught the mud, just
because *your* code is embarassing to its author.
									  XX
XX          --Darryl Richman, INTERACTIVE Systems Corp.                     XX
	    ...!cca!ima!ism780!darryl XXXXX                                 XX
XX          The views expressed above are my opinions only.                 XX
									  XX
P.S.  I've told you before that, in my opinion, it's disgusting, not amusing.

tim@ism780c.UUCP (Tim Smith) (04/07/86)

In article <1377@ism780c.UUCP> darryl@ism780c.UUCP (Darryl Richman) writes:
>
>I'd appreciate it if you didn't drag my good name throught the mud, just
>because *your* code is embarassing to its author.

Note that I didn't mention any last names.  How do you know I meant you?
-- 
Who knows what evil lurks in the hearts of men?

Tim Smith       sdcrdcf!ism780c!tim || ima!ism780!tim || ihnp4!cithep!tim

darryl@ism780c.UUCP (Darryl Richman) (04/07/86)

In article <1379@ism780c.UUCP> tim@ism780c.UUCP (Tim Smith) writes:
>Note that I didn't mention any last names.  How do you know I meant you?

At this site, there is precisely one Darryl, regardless of variations in
the spelling.   Don't you think enough net resources have been used for
this conversation?  Why don't we settle this with honor:  meet me with your
second in the main west corridor at sunrise tomorrow.  I suggest sabres.
									  XX
XX          --Darryl Richman, INTERACTIVE Systems Corp.                     XX
	    ...!cca!ima!ism780!darryl   XXXXX                               XX
XX          The views expressed above are my opinions only.                 XX
									  XX
>Who knows what evil lurks in the hearts of men?
I intend to find out.  :-)

rbj@icst-cmr (Root Boy Jim) (04/07/86)

	A, B, C, D, and E are constant expressions, so this is not elegant.
	We would like to use a switch for everything.  Here is a solution:
	
		switch ( thing ) {
	case A:         A-code; break;
	case B:         B-code; if ( 0 ) {
	case C:         C-code; if ( 0 ) {
	case D:         D-code; }}
			BCD-common-code; break;
	case E:         E-code;
		}
	
	Noone here has been able to come up with a reasonable style for this. 
	The example above is not to bad, but if B-code, C-code, etc, are
	complicated, then it starts to get ugly.
	
	Tim Smith       sdcrdcf!ism780c!tim || ima!ism780!tim || ihnp4!cithep!tim
	
Great! You also discovered how to remove all break's from swithces too!
But this method will comlain about non-conditional conditionals as well.
I can recommend several solutions in my order of preference:

	1) Use Goto's. After case B & C, goto BCD-common

	2) Use a flag:
		flag = 0;
		switch(thing) {
		case A: A-code; break;
		case B: B-code; ++flag; break;
		case C: C-code; ++flag; break;
		case D: D-code; ++flag; break;
		case E: E-code; break;
		} if (flag) BCD-code;

	3) If the switch is isolated in it's own function:
		switch(thing) {
		case A: A-code; return;
		case B: B-code; ++flag; break;
		case C: C-code; ++flag; break;
		case D: D-code; ++flag; break;
		case E: E-code; return;
		} BCD-code;
		
	4) Use a switch within a switch
		switch(thing) {
		case A: A-code; break;
		case B: 
		case C: 
		case D: switch(thing) {
			case B: B-code; break;
			case C: C-code; break;
			case D: D-code; break;
			} BCD-code;
			break;
		case E: E-code; break;
		}
	...
	99) Use your solution

	(Root Boy) Jim Cottrell		<rbj@cmr>

tim@ism780c.UUCP (Tim Smith) (04/07/86)

In article <1380@ism780c.UUCP> darryl@ism780c.UUCP (Darryl Richman) writes:
>
> Why don't we settle this with honor: meet me with your second in
> the main west corridor at sunrise tomorrow.  I suggest sabres.

Sunrise?!?  But, but, but, that's in the *morning*!  How about noon?
And forget the sabres.  Pinball machines are the true test of honor.

Me and my Mac will be there.
-- 
Tim Smith       sdcrdcf!ism780c!tim || ima!ism780!tim || ihnp4!cithep!tim

jsdy@hadron.UUCP (Joseph S. D. Yao) (04/08/86)

In article <1370@ism780c.UUCP> tim@ism780c.UUCP (Tim Smith) writes:
>	switch ( thing ) {
>case A:         A-code; break;
>case B:         B-code; if ( 0 ) {
>case C:         C-code; if ( 0 ) {
>case D:         D-code; }}
>		BCD-common-code; break;
>case E:         E-code;
>	}

Assuming that you can't put BCD-common-code into a function, I
agree with everyone else that you should use [forward-referencing!]
goto's here, and [again] cite Prof. Knuth's _Structured_Programming_
_with_Goto's_.  One major problem is that this code jumps into blocks
[the effect of case C: and case D: ].  This is something that X3J11
warns about.  I thought K&R did, too; but I can't find it.  It is
generally a bad practice, although most compilers seem to allow it
without too much trouble.

chris@toram.UUCP (Chris Robertson) (04/08/86)

In article <1370@ism780c.UUCP> tim@ism780c.UUCP (Tim Smith) writes:
>Here is an amusing piece of code ...  that, if written with if-then-else
>would be
>
>	if ( thing == A )
>		A-code;
>	else
>	if ( thing == B || thing == C || thing == D ) {
>		switch ( thing ) {
>	case B:         B-code; break;
>	case C:         C-code; break;
>	case D:         D-code; break;
>		}
>		BCD-common-code;
>	} else
>	if ( thing == E )
>		E-code;
>
>A, B, C, D, and E are constant expressions, so this is not elegant.
>We would like to use a switch for everything.  Here is a solution:
>
	[ VERY inelegant switch code deleted ]

Why not just use:

	BCD-flag=FALSE;
	if (thing == A)
		A-code;
	else if (thing == E)
		E-code;
	else {
		switch (thing) {
			case B:
				B-code;BCD-flag=TRUE;break;
			case C:
				C-code;BCD-flag=TRUE;break;
			case D:
				D-code;BCD-flag=TRUE;break;
		}
		if (BCD-flag)
			BCD-common-code;
	}

This tests all your stuff, in a fairly straightforward way, and only costs
1 measly flag.
-- 

	Christine Robertson  {ihnp4,linus,decvax}!utzoo!toram!chris

	An apple a day keeps the doctor away, especially if aimed well.

thoth@tellab1.UUCP (Marcus Hall) (04/08/86)

In article <1370@ism780c.UUCP> tim@ism780c.UUCP (Tim Smith) writes:
>Here is an amusing piece of code that someone who wants to remain
>annonymous invented.
...
>	switch ( thing ) {
>case A:         A-code; break;
>case B:         B-code; if ( 0 ) {
>case C:         C-code; if ( 0 ) {
>case D:         D-code; }}
>		BCD-common-code; break;
>case E:         E-code;
>	}
>
>Noone here has been able to come up with a reasonable style for this.  The
>example above is not to bad, but if B-code, C-code, etc, are complicated,
>then it starts to get ugly.
>
>Tim Smith       sdcrdcf!ism780c!tim || ima!ism780!tim || ihnp4!cithep!tim

I always do this kind of things with gotos.  Controlled use of gotos don't
present serious readability problems, and in comparison to the code above
it seems much clearer to me.

	switch ( thing ) {
case A:         A-code; break;
case B:         B-code; goto BCDcommon;
case C:         C-code; goto BCDcommon;
case D:         D-code; goto BCDcommon; /* This goto is optional... */
BCDcommon:
		BCD-common-code; break;
case E:         E-code;
	}

Note that if BCD-common-code isn't very complex, most optimizers will combine
the common tail code if it's given this input:

	switch ( thing ) {
case A:         A-code; break;
case B:         B-code; BCD-common-code; break;
case C:         C-code; BCD-common-code; break;
case D:         D-code; BCD-common-code; break;
case E:         E-code;
	}


marcus hall
..!ihnp4!tellab1!thoth

greg@utcsri.UUCP (Gregory Smith) (04/08/86)

In article <1370@ism780c.UUCP> tim@ism780c.UUCP (Tim Smith) writes:
>Here is an amusing piece of code that someone who wants to remain
>annonymous invented.
>
>The situation is that we have something that, if written with if-then-else
>would be
>
>	if ( thing == A )
>		A-code;
>	else
>	if ( thing == B || thing == C || thing == D ) {
>		switch ( thing ) {
>	case B:         B-code; break;
>	case C:         C-code; break;
>	case D:         D-code; break;
>		}
>		BCD-common-code;
>	} else
>	if ( thing == E )
>		E-code;
>
>A, B, C, D, and E are constant expressions, so this is not elegant.
>We would like to use a switch for everything.  Here is a solution:
>
>	switch ( thing ) {
>case A:         A-code; break;
>case B:         B-code; if ( 0 ) {
>case C:         C-code; if ( 0 ) {
>case D:         D-code; }}
>		BCD-common-code; break;
>case E:         E-code;
>	}
>
>Noone here has been able to come up with a reasonable style for this.  The
>example above is not to bad, but if B-code, C-code, etc, are complicated,
>then it starts to get ugly.
>
Many points for creative use of if-statements... do you know about the
obfuscated C contest..? :-)

My $0.02:

	switch ( thing ) {
case A:         A-code; break;
case B:         B-code; BCD_common();	break;
case C:         C-code; BCD_common();	break;
case D:         D-code; BCD_common();	break;
case E:         E-code;
	}
...
BCD_common(){
	BCD-common-code;
}

The function call is very cheap if it has no parameters. I have done the
above many times.

If you must do nasty things, at least be honest about it:

	switch ( thing ) {
case A:         A-code; break;
case B:         B-code; goto BCD;
case C:         C-code; goto BCD;
case D:         D-code; 
	BCD:	BCD-common-code; break;
case E:         E-code;
	}

Despite the fact that this contains 2 more ( pardon my language )
`goto's I feel it is much clearer than the example using castrated
`if's, which after all are just `goto's in disguise. At least *real*
`goto's are easily recognizable as such. There is another thing you can
do, but only if the switch is to be followed by a return:

	switch ( thing ) {
case A:         A-code; return;		/* skip BCD-common */
case B:         B-code; break;		/* do BCD-common */
case C:         C-code; break;
case D:         D-code; break;
case E:         E-code; return;
	}
	BCD-common-code;
}	/* end of function */

This may look a little iffy but I would rank it above the goto solution
in clarity. I think it is less clear than the function call, and probably
less maintainable, but it would be faster. I have also done this one many
times.

-- 
"If you aren't making any mistakes, you aren't doing anything".
----------------------------------------------------------------------
Greg Smith     University of Toronto      UUCP: ..utzoo!utcsri!greg

vince@fluke.UUCP (Craig Johnson) (04/09/86)

In posting<1370@ism780c.UUCP>, Tim Smith asks about a switch with common
code for some cases.

While not necessarily the most efficient method, I think nested switches
are prefered in this situation over goto's.  Notice the inner switch need
not be concerned with 'case A', 'case E', or 'default' since 'thing' has
already been tested in the outer switch.

	switch(thing) {
	case A: A-code; break;
	case B:
	case C:
	case D: switch(thing) {
	        case B: B-code; break;
	        case C: C-code; break;
	        case D: D-code; break;
	        }
                BCD-common-code;
                break;
	case E: E-code; break;
	}

				Craig V. Johnson
				John Fluke Mfg. Co., Inc.
				Everett, WA

wcs@ho95e.UUCP (#Bill_Stewart) (04/10/86)

In article <2600044@ccvaxa> aglew@ccvaxa.UUCP writes:
>>/* Written 10:10 pm  Apr  4, 1986 by tim@ism780c.UUCP in ccvaxa:net.lang.c */
>>[Describes a code structure that looks reasonably ugly with if-then-elses]
>>[I'll include it at the bottom of this letter for reference]
>>We would like to use a switch for everything.  Here is a solution:
[ugly switch statement]
>>Noone here has been able to come up with a reasonable style for this.  The
>>example above is not to bad, but if B-code, C-code, etc, are complicated,
>>then it starts to get ugly.
>
[Back to Andy Glew:]
>May I make a modest suggestion? The above code is a classic example of 
>converging flows of control. Write it:
>
>   switch ( thing ) {
>       case A:	   A-code;     break;
>
>       case B:	   B-code;     goto BCDcode;
>       case C:	   C-code;     goto BCDcode;
>       case D:	   D-code;     goto BCDcode;
>
>         BCDcode:  BCD-common-code; break;
>
>       case E:	   E-code;     break;
>   }
>
[Some notes on making it clean and maintainable]
>Now, I ask you: which is more easily readable? The goto code, or those if(0) {
>abominations in the example above? Or the original if-then-else code, which
>I include here?
[I'm leaving it out; it really was ugly]
>A last word - gotos are often the most elegant means of implementing
>complicated structures. Whether you should be using such complicated
>structures is another question - for me, finding that I can code 
>something more cleanly with gotos than with conventional structures
>sets the flag <There is probably something wrong with this algorithm>.
>As well it should. But gotos should not be thrown out.
>

While I agree with Andy that his goto-code was at least as clean and
maintainable as either of the original switch-an-if versions, it's
possible to write a relatively clean gotoless version.
	(Disclaimer: I'm not a purist about gotos, and generally use
	them when they're cleaner than flag-based code.)

	/* maybe set BCD_later_flag=FALSE here instead of later */
switch ( thing ) {
case A:	   A-code; BCD_later_flag = FALSE; break
case B:	   B-code; BCD_later_flag = TRUE; break
case C:	   C-code; BCD_later_flag = TRUE; break
case D:	   D-code; BCD_later_flag = TRUE; break
case E:	   E-code; BCD_later_flag = FALSE; break
default:   default-code; BCD_later_flag = FALSE;
}
if (BCD_later_flag) {
	whetever();
}
-- 
# Bill Stewart, AT&T Bell Labs 2G-202, Holmdel NJ 1-201-949-0705 ihnp4!ho95c!wcs

gemini@homxb.UUCP (Rick Richardson) (04/10/86)

The ongoing debate (?):

>   switch ( thing ) {
>       case A:	   A-code;     break;
>       case B:	   B-code;     goto BCDcode;
>       case C:	   C-code;     goto BCDcode;
>       case D:	   D-code;     goto BCDcode;
>         BCDcode:  BCD-common-code; break;
>       case E:	   E-code;     break;
>   }

	- VERSUS -

> switch ( thing ) {
> case A:	   A-code; BCD_later_flag = FALSE; break
> case B:	   B-code; BCD_later_flag = TRUE; break
> case C:	   C-code; BCD_later_flag = TRUE; break
> case D:	   D-code; BCD_later_flag = TRUE; break
> case E:	   E-code; BCD_later_flag = FALSE; break
> default:   default-code; BCD_later_flag = FALSE;
> }
> if (BCD_later_flag) {
> 	whetever();
> }

Essentially, both pieces of code are equivalent in "confusion factor".
The goto version leaves the reader wondering "goto WHERE?",  the
BCD_later version leaves the reader wondering "BCD how much LATER?".

Six one way, half a dozen the other.  Me? I'll either put BCD in
a function, or, if I don't think I want to incur the function call
overhead, will use the goto version.  After all, if I didn't want
to do a function call then I'm probably after every last cycle I can
squeeze out of the code, in which case its cheaper to just jump to
where I want to go, rather than setting a flag.  Then again, there's
always MACRO's to make it look like the function call version without
the subroutine call overhead...  ...I'm easy, as long as it works.

Rick Richardson, PC Research, Inc. (201) 922-1134, (201) 834-1378 @ AT&T-CP
..!ihnp4!castor!{rer,pcrat!rer} <--Replies to here, not to homxb!gemini, please.

rab@well.UUCP (Bob Bickford) (04/10/86)

,,,,

  How about this:


    Switch (thing)
        case A:
            A-code;
            break;
        case B:
        case C:
        case D:
            BCD common code
            switch (thing)
                case B: B code; break;
                case C: C code; break;
                case D: D code; break;
            break;
        case E:
            E code;
            break;


  Of course, the inner switch and the BCD common code can be swapped if
the order of execution is crucial.

  I didn't like your example code because I found it too hard to follow
the logic, with the brackets placed in that way, which I gather is what you
were looking for a solution for....


-- 
Robert Bickford     {lll-crg,hplabs}!well!rab

franka@mmintl.UUCP (Frank Adams) (04/14/86)

In article <195@desint.UUCP> geoff@desint.UUCP (Geoff Kuenning) writes:
>	    case B:
>		B-code;
>		goto common;
>	    case C:
>		C-code;
>		goto common;
>	    case D:
>		D-code;
>common:
>		BCD-common-code;
>		break;

A quibble: I would put a goto common; between the D-code; and the common:.
That way, when someone maintaining the program adds a case F which wants to
execute the BCD-common-code, they can't accidently let D-code fall through to
F-code.

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Multimate International    52 Oakland Ave North    E. Hartford, CT 06108

tim@ism780c.UUCP (Tim Smith) (04/15/86)

In article <360@hadron.UUCP> jsdy@hadron.UUCP (Joseph S. D. Yao) writes:
>
>Assuming that you can't put BCD-common-code into a function, I
>agree with everyone else that you should use [forward-referencing!]
>goto's here, and [again] cite Prof. Knuth's _Structured_Programming_
>_with_Goto's_.  One major problem is that this code jumps into blocks
>[the effect of case C: and case D: ].  This is something that X3J11
>warns about.  I thought K&R did, too; but I can't find it.  It is
>generally a bad practice, although most compilers seem to allow it
>without too much trouble.

At least in one case, jumping into blocks has been blessed by DMR,
so I am not too worried about that.

The problem with the goto versions is that one then has to think of a
name for the label, and make sure one uses the same name in two places.
Yuck-o!

Here is a suggested form that should satisfy the goto supporters, and
still not make me have to think of a name for the label:

#define GOTO_THERE      if(0){
#define THERE           }

	switch(v) {
case A; A-code; break;
case B; B-code; GOTO_THERE;
case C: C-code;   GOTO_THERE;
case D: D-code;
		  THERE;        /* the ; looks sort of like a : */
		THERE;
		BCD-common-code; break;
case E: E-code; break;
	}

In real programs, one might have several groups of cases, each with
different common code.  Most of the methods suggested can get kind of
ugly, with gotos all over the place.  I think the best way is to probably
have two switches, one after the other:

	switch(v) {
case A:         A-code; break;
case B:         B-code; break;
case C:         C-code; break;
case D:         D-code; break;
case E:         E-code; break;
	}
	/*
	 * handle common code
	 */
	switch(v) {
case B:
case C:
case D:         BCD-common-code(); break;
	}

This can be easily expanded, and I think it is pretty readable.  Not that
it can be expanded with a third switch to handle a third level of common
code, etc.
-- 
Tim Smith       sdcrdcf!ism780c!tim || ima!ism780!tim || ihnp4!cithep!tim

kenny@uiucdcsb.CS.UIUC.EDU (04/16/86)

/* Written  4:26 pm  Apr 12, 1986 by stevesu@copper.UUCP in uiucdcsb:net.lang.c */
Most people agree that goto's are pretty acceptable for handling
error conditions.  For instance:

	if(stbuf.st_uid != getuid())
		{
nope:		printf("I don't think you want to delete this file.\n");
		return;
		}

	if(strcmp(name, "vmunix") == 0)
		goto nope;

	unlink(name);

	return;

                                         Steve Summit
                                         tektronix!copper!stevesu
/* End of text from uiucdcsb:net.lang.c */
You've chosen a pretty bad example.  It's more sensible to code what you're
writing as:

	if (stbuf.st_uid != getuid ()
	 || strcmp (name, "vmunix") == 0) {
		printf ("I don't think you want to delete this file.\n");
		}
	else {
		unlink (name);
		}

The real use of goto's as error exits is as a panic exit from a set of 
deeply nested control structures; this is generally a goto *out* of a block
and not *into* one:

	while (something)
		while (something else)
			if (something terrible happens) goto quit;
			....

	return;

quit:
	(handle the error here)

with as many goto's as are necessary to handle all the error conditions.
In many cases this panic exit actually has to cross function boundaries;
a reason that I insist (over some of my more academically minded colleagues'
loud objections) that setjmp/longjmp pairs are a necessary evil.

In short, the use of goto as an error exit is a red herring when discussing
whether goto into blocks is permissible.  My $.02 says that it isn't necessary,
ever, and it really messes up any serious attempt to optimize, so why not trash
it?

Kevin Kenny
University of Illinois at Urbana-Champaign
UUCP: {ihnp4,pur-ee,convex}!uiucdcs!kenny 
CSNET:	kenny@UIUC.CSNET
ARPA:	kenny@B.CS.UIUC.EDU	(kenny@UIUC.ARPA)

"Yes, understanding today's complex world is a bit like having bees live in
your head, but there they are."

aglew@ccvaxa.UUCP (04/19/86)

>At least in one case, jumping into blocks has been blessed by DMR,
>so I am not too worried about that.
Knuth too - converting a recursive program into a non-recursive one, ending
up with a jump into a the middle of a while loop. If this kind of thing
became common it would militate against architectures that have hardwired
loop-control stacks, etc.

>The problem with the goto versions is that one then has to think of a
>name for the label, and make sure one uses the same name in two places.
>Yuck-o!
If you were going to use a function, you wouldn't have to invent a name for
it? But, in general, I agree with you. The problem is that most languages
have very limited ways of generating names and scopes. I've always been
found of the label techniques Knuth uses in MIX, which was also used by at
least one UNIX assembler:
	1h: /* john */
	    goto 1f;	/* goes to mary */
	    goto 1b;	/* goes to john */
	1h: /* mary */
Ie. jumps can be designated as being either forward or back to the next
label `here' of the appropriate name in that direction. This makes reusing
names a lot easier (alphanumeric names should be allowed). However, funny
bugs can come in if you move code around, and suddenly find you're jumping
to the wrong label of the same name. Your editor should warn you if this
happens.

>Here is a suggested form that should satisfy the goto supporters, and
>still not make me have to think of a name for the label:
>
>#define GOTO_THERE      if(0){
>#define THERE           }
Please, no! If you look at this all you're doing is generating an anonymous
label.

Your switch solution is good, but might require extra variables,
particularly if the value of the switch variable is being changed. It also
requires extra switches. Now, I know it's not fashionable to worry about
speed, but some people do have to because their programs quite simply
stretch the most expensive machine that they can buy to its limits. I don't
want to condemn these people to having to code in assembler simply because a
high level language doesn't give them the clean, easy to implement
construct, like a goto, that they need to run that extra bit faster.

>-- ....
>Tim Smith       sdcrdcf!ism780c!tim || ima!ism780!tim || ihnp4!cithep!tim
>/* End of text from ccvaxa:net.lang.c */

Andy "Krazy" Glew. Gould CSD-Urbana.    USEnet:  ihnp4!uiucdcs!ccvaxa!aglew
1101 E. University, Urbana, IL 61801    ARPAnet: aglew@gswd-vms