[comp.lang.c] Case fall throughs

dant@tekla.TEK.COM (Dan Tilque;1893;92-789;LP=A;60HC) (08/14/87)

I (Dan Tilque) say that it's bad programming to have this kind of thing:
> 
> 	case 'a':
> 		a = b + count;
> 	case 'b':
> 		count += 2;
>
> Lint should definitely give warning since it's almost always the case that
> what's desired is a break before case 'b':

I expected a number of people to respond saying "I often write these kind of 
fall throughs".  So far only one person has done so.  I admire everyone
else's restraint (or else because of net lag I haven't seen the articles yet).

You might notice that, unlike Karl Heuer, I do not advocate removing this
feature completely from the language and substituting goto case labels
instead.  The reason is that a fall through is the fastest possible transfer
of control and there are some time critical routines which use fall through
for that very reason.

However, in the common ordinary program, I think it's cleaner to do something
like this:

 	case 'a':
 		a = b + count;
		common_statements();
		break;
 	case 'b':
		common_statements();
		break;

In those cases which have to have fall throughs, the /*FALLTHROUGH*/
comment to lint (as suggested by Karl Heuer) would also be a good thing to
put in even if lint didn't check for it.  It tells any maintenance
programmer that the break was deliberately left out and is not the cause
of the hard to track down bug.

) = Karl Heuer:
)In article <2182@zeus.TEK.COM> dant@tekla.UUCP (Dan Tilque) writes:
)>[If switch statements had automatic break instead of fall-through, the
)>current idiom "case CR: case LF: ..." wouldn't work.]  One possibility is
)>separating them with commas: "case CR, LF, TAB, ' ':" which changes the
)>meaning of the comma operator.  Probably not a good idea.
)
)The comma operator is neither necessary nor useful in a constant expression,
)and is explicitly disallowed by ANSI.

I checked in K&R and it's not allowed there either (by omission rather than
explicitely).


] = David Collier-Brown.
]	...
]	switch (foo) {
]	case 'f' | 'e':		-- one possible syntax...
]		/* whatever */
]	}

I thought of using | also.  Unfortunately, | is already legal here
and has a different meaning.  Looks like a comma is the better notation.
Actually, I like things the way they are except to have all lints check
for fall through.

---
Dan Tilque
dant@tekla.tek.com  or dant@tekla.UUCP

chris@mimsy.UUCP (Chris Torek) (08/14/87)

In article <2201@zeus.TEK.COM> dant@tekla.TEK.COM (Dan Tilque) writes:
>... In those cases which have to have fall throughs, the /*FALLTHROUGH*/
>comment to lint (as suggested by Karl Heuer) would also be a good thing to
>put in even if lint didn't check for it.  It tells any maintenance
>programmer that the break was deliberately left out and is not the cause
>of the hard to track down bug.

That it was intentional does not indicate that it is not the cause
of some bug.  Or, put more simply, it may be intentional and wrong.
Still, I consider /*FALLTHROUGH*/ good programming practise.

On the topic of syntaxes to consider for a language with switches
with built-in breaks, another possibility (in addition to `case X,
Y, Z:' and a few other suggestions) is C's current syntax, but with
a semantic twist:  A built-in break occurs only *after* an executable
statement.  Hence

	switch (expr) {

	case A:
	case B:
		ab();

	case C:
		c();

	default:
		def();
	}

would do the `obvious thing'.

This has a disadvantage:

	switch (expr) {

	case A:
	#ifdef	somedef
		code;
	#endif

	case B:
		morecode;
		...
	}

Here case A would fall into case B iff `somedef' were not defined.

There are also `tricks' like

	case 1:
		{ int i; }	/* no exectable code? */

	case 2:
		...

Is there a fall through from case 1 to case 2?  Either way is
arguable, and the code is probably wrong anyway.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690)
Domain:	chris@mimsy.umd.edu	Path:	seismo|p el: Lbuilt

john@chinet.UUCP (John Mundt) (08/15/87)

In article <2201@zeus.TEK.COM> dant@tekla (Dan Tilque) writes:
>
>I (Dan Tilque) say that it's bad programming to have this kind of thing:
>> 	case 'a':
>> 		a = b + count;
>> 	case 'b':
>> 		count += 2;
>I expected a number of people to respond saying "I often write these kind of 
>fall throughs".  So far only one person has done so.  I admire everyone
>else's restraint (or else because of net lag I haven't seen the articles yet).

I often write that sort of thing, but I always add a comment to the
effect that I meant to do it

	case 'a' :
		do_something_wonderful();	/* fallthrough intended */
	case 'b' :
		do_something_marvelous();
		break;

It saves time and space and is readable as long as the comment
remains.
--------------------------------------------------------------
John Mundt
Teachers' Aide    ...ihnp4!chinet!john
								 !teachad![john|fred]

karl@haddock.ISC.COM (Karl Heuer) (08/20/87)

In article <2201@zeus.TEK.COM> dant@tekla (Dan Tilque) writes:
>... I do not advocate removing this [fallthrough] feature completely from the
>language and substituting goto case labels [because fallthrough is faster].

Any good optimizer will recognize that "goto foo; foo:" is elidable.

>However, in the common ordinary program, I think it's cleaner to do something
>like this: [statements common to more than one case factored out to a
>subprocedure]

I just had this situation occur.  I haven't yet factored it out (the code in
question modifies register variables), but I'll probably either do that or
emulate Zahn exits.

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

root@hobbes.UUCP (John Plocher) (08/21/87)

>>> lots of people writing about falling thru a case inside a switch() <<<

A trick I use (as seen in some BSD code :-) is:
	
#define when	break; case

	switch( ch ) {
	    case 'A':	doa();
	    when 'B':   dob();
	    when 'C':   seenc = 1;
	    /* FALLTHROUGH */
	    case 'D':	doocd( seenc );
         }

It cleans up the code a bit, I think.

-- 
John Plocher uwvax!geowhiz!uwspan!plocher  plocher%uwspan.UUCP@uwvax.CS.WISC.EDU