[net.lang.c] generalized switch

kos@ernie.Berkeley.EDU.UUCP (08/02/86)

One of my only memories from a brief stint as a PL/I programmer years ago
was the pleasure of using a more general switch structure than C allows.
In addition to the standard
	switch (var) {
		case value:
		case value:
			etc...
		}		(translated to C because I don't remember
					any PL/I )

you also had the option of 
	switch() {
		case <boolean-expr>:
		    etc.
		}
if you wanted to test something other than the value of a particular variable.

I'm wondering whether any netland gurus have elegant suggestions for ways
of dummying up such a construct. The particular case at hand involves some
macros that look like:

#define IS_TYPE_A(c)	(c==this||c==that)
#define	IS_TYPE_B(c)	((c==the_other||c==your_mother) && c != rambo)
and so on. Now what I need is
	switch () {
		IS_TYPE_A(c):
			do_type_a(c);
			break;
		IS_TYPE_B(c):
			do_type_b(c);
			break;
		}

But it's something I've wanted in the past in other contexts as well.
Any ideas?


	Joshua Kosman
	kos@ernie.berkeley.EDU

	"When I was young people used to tell me, 'When you're 50 you'll
	understand.' Well, now I'm 50. I don't understand a thing."
				-- Erik Satie

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

In article <15093@ucbvax.BERKELEY.EDU> kos@ernie.Berkeley.EDU
(Joshua Kosman) writes:
>One of my only memories from a brief stint as a PL/I programmer years ago
>was the pleasure of using a more general switch structure than C allows.

[In particular, the compiler allowed `cases' that might have to be
determined at run time, or at any rate were not simple constants.]

>#define IS_TYPE_A(c)	(c==this||c==that)
>#define IS_TYPE_B(c)	((c==the_other||c==your_mother) && c != rambo)
>and so on. Now what I need is
>	switch () {
>		IS_TYPE_A(c):
>			do_type_a(c);
>			break;
>		IS_TYPE_B(c):
>			do_type_b(c);
>			break;
>		}

One of the key `features' in C is that most constructs have a very
simple relationship to the machine code that will be generated for
a given statement.  switch `wants' to become a computed branch,
much like the old FORTRAN

	GOTO (l1, l2, l3, ..., ln), var

`switch' wins readability points over the computed GOTO, but not
much else: it still requires constant expressions, so that the
compiler can convert it back to one.  In C, when one wants a run-time
test, one must write a run-time test.

In your particular example, you probably do not care how the test
is implemented.  Unfortunately (?), C requires you to care.  This
example appears to require run-time evaluation, but in another case
(pardon the pun) you might be able to get away with this:

	#define IS_TYPEA(x) ((x) > 3 && (x) < 7)
	#define CASES_TYPEA	case 4: case 5: case 6:
	#define IS_TYPEB(x) (!IS_TYPEA(x))
	#define CASES_TYPEB	default:

You could then use

		if (IS_TYPEA(n)) {
			statements;
		} else if (IS_TYPEB(n)) {
			morestatements;
		}

and

		switch (n) {

		CASES_TYPEA:
			statements;
			break;

		CASES_TYPEB:
			morestatements;
			break;
		}

but not

		switch (n) {

		CASES_TYPEB:
			morestuff;
			break;
		/* default is to ignore */
		}

So this approach too has its pitfalls.
-- 
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

gwyn@brl-smoke.ARPA (Doug Gwyn ) (08/03/86)

In article <15093@ucbvax.BERKELEY.EDU> kos@ernie.Berkeley.EDU (Joshua Kosman) writes:
>	switch() {
>		case <boolean-expr>:
>		    etc.
>		}
>...
>Any ideas?

In C, such code is written:

	if ( bool_expr_1 )
		action_1
	else if ( bool_expr_2 )
		action_2
	else if ...
	else
		default_action

You could come up with some CPP macros for this, but why bother?

kos@ernie.Berkeley.EDU (Joshua Kosman) (08/04/86)

In article <2765@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>In article <15093@ucbvax.BERKELEY.EDU> kos@ernie.Berkeley.EDU (Joshua Kosman) writes:
>>	switch() {
>>		case <boolean-expr>:
>>		    etc.
>>		}
>>...
>>Any ideas?
>
>In C, such code is written:
>
>	if ( bool_expr_1 )
>		action_1
>	else if ( bool_expr_2 )
>		action_2
>	else if ...
>	else
>		default_action
>
>You could come up with some CPP macros for this, but why bother?

Sure, that's the way I have been doing it. But you can do that with
any choice among cases.
As I understand it, a switch/case setup compiles exactly the same as
	if (var == const1) {.....};
	else if (var == const2) {.....};
	else  {default_action};
anyway. (Or am i wrong?). In any case, it can be rewritten that way.
But the switch promotes comprehensibility. The situation I
find (mildly) frustrating is when I have a choice among cases, a
setup which is conceptually akin to a switch, but is not
syntactically equivalent because I want to use a slightly different test
than simple equality.


Joshua Kosman		||  "When I was young people used to tell me,
kos@ernie.berkeley.EDU	||	'When you're 50 you'll understand.' Well,
Dept. of Music		||	now I'm 50. I don't understand a thing."
UC Berkeley		||		-- Erik Satie

barmar@mit-eddie.MIT.EDU (Barry Margolin) (08/04/86)

In article <15120@ucbvax.BERKELEY.EDU> kos@ernie.Berkeley.EDU.UUCP (Joshua Kosman) writes:
>As I understand it, a switch/case setup compiles exactly the same as
>	if (var == const1) {.....};
>	else if (var == const2) {.....};
>	else  {default_action};
>anyway. (Or am i wrong?). In any case, it can be rewritten that way.
>But the switch promotes comprehensibility. The situation I
>find (mildly) frustrating is when I have a choice among cases, a
>setup which is conceptually akin to a switch, but is not
>syntactically equivalent because I want to use a slightly different test
>than simple equality.

One of the features of the switch statement is that you don't have to
write the variable being tested repeatedly.  This helps avoid errors (a
rare safety feature in C).  Also, if your switch is over an expression
the compiler takes care to evaluate it once, so that the programmer
doesn't have to use an explicit temporary.  And, as someone else already
pointed out, since the cases are required to be constants the construct
can be optimized into a jump table.

The generalized switch statement you ask for has none of these features.
All it does is allow you to type "case <exp>:" instead of "else if
<exp>".  A saving of two characters per case seems like a silly reason
to complicate the language.

It might, however, be reasonable to extend the case statement to not
require all the cases to be constants.  This would still provide the
first two features I listed; the compiler would have to do a bit more
work to determine if the construct can be translated into a jump table.
-- 
    Barry Margolin
    ARPA: barmar@MIT-Multics
    UUCP: ..!genrad!mit-eddie!barmar

dant@tekla.UUCP (Dan Tilque) (08/04/86)

In article <15120@ucbvax.BERKELEY.EDU>, kos@ernie.Berkeley.EDU (Joshua Kosman) writes:
>In article <2765@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>>In article <15093@ucbvax.BERKELEY.EDU> kos@ernie.Berkeley.EDU (Joshua Kosman) writes:
>>>	switch() {
>>>		case <boolean-expr>:
>>>		    etc.
>>>		}
>>>...
>>>Any ideas?
>>
>>In C, such code is written:
>>
>>	if ( bool_expr_1 )
>>		action_1
>>	else if ( bool_expr_2 )
>>		action_2
>>	else if ...
>>	else
>>		default_action
>>
>>You could come up with some CPP macros for this, but why bother?
>
>Sure, that's the way I have been doing it. But you can do that with
>any choice among cases.
>As I understand it, a switch/case setup compiles exactly the same as
>	if (var == const1) {.....};
>	else if (var == const2) {.....};
>	else  {default_action};
>anyway. (Or am i wrong?). In any case, it can be rewritten that way.
>But the switch promotes comprehensibility. The situation I
>find (mildly) frustrating is when I have a choice among cases, a
>setup which is conceptually akin to a switch, but is not
>syntactically equivalent because I want to use a slightly different test
>than simple equality.
>
>
In PL/I this is probably how it is done, but many (if not most) C compilers
convert the switch-case statement to a branch table.  (There are also
statements in FORTRAN and COBOL which also convert to branch tables.)  A branch 
table is just a series of assembler branch instuctions in a row.  The
first of these branches jumps to a location within the branch table
based on the switch value times the length of the branch instruction. 
The rest of the branches are jumps to code to be executed if the switch
value is 0, 1, 2...  The default case must be handled before the branch
table is entered.

If you followed the above explanation, you should understand why the
switch value (as it is currently implemented) has to be an integral
type expression.  It's likely that the designer(s) of this statement
had a branch table in mind when the statement was designed.

Branch tables are very efficient if the case values have small gaps
between them, but can be somewhat inefficient otherwise.

=========================================================================
Dan Tilque		UUCP:		tektronics!dadla!dant
			CSnet:		dant%dadla@tektronix
			ARPAnet:	dant%dadla%tektronix@csnet-relay
I can't think of anything clever to put here.
=========================================================================

tainter@ihlpg.UUCP (Tainter) (08/05/86)

> Sure, that's the way I have been doing it. But you can do that with
> any choice among cases.
> As I understand it, a switch/case setup compiles exactly the same as
> 	if (var == const1) {.....};
> 	else if (var == const2) {.....};
> 	else  {default_action};
> anyway. (Or am i wrong?). In any case, it can be rewritten that way.
> Joshua Kosman
> kos@ernie.berkeley.EDU

You are wrong.
switch (a) {
    case 'a': hi();
    case 'b': ho(); break;
    case 'c': he();
    case 'd': ha(); break;
}
.  .  .

can be written as:
if (a == 'a') {	
    hi(); goto do2; /* skip the test on 2 */
}
if (a == 'b') {
do2:
    ho(); goto done;	/* do a break */
}
if (a == 'c') {
    he(); goto do4; /* skip the test on 4 */
}
if (a == 'd') {
do4:
    ha(); goto done; /* do a break */
}
done:
.  .  .

A bit different than the simple if else block, ja?
The switch statement can also be coded as a jump table with generaly better
performance than the if else block.

It might be feasable to fold if else blocks testing the same variable repeatedly
into a jump table, but I'll wager it's unusual.
--j.a.tainter

u557676751ea@ucdavis.UUCP (Mark Nagel) (08/05/86)

In article <15093@ucbvax.BERKELEY.EDU> Joshua Kosman writes:
> As I understand it, a switch/case setup compiles exactly the same as
> 	if (var == const1) {.....};
> 	else if (var == const2) {.....};
> 	else  {default_action};
> anyway. (Or am i wrong?). In any case, it can be rewritten that way.

This may be correct on some machines, however, I was under the impression that
the switch'ed variable is only accessed once and the code address is computed
from a vector table created during the compilation.  It thus cuts down on
a lot of comparisons.  This may mean nothing in a one shot switch, but it sure
will be more efficient in a loop.

> But the switch promotes comprehensibility. The situation I
> find (mildly) frustrating is when I have a choice among cases, a
> setup which is conceptually akin to a switch, but is not
> syntactically equivalent because I want to use a slightly different test
> than simple equality.

If you need to test for greater-than or less-than or the like, why not use
an expression in the switch statement that produces the sign of the
difference between the two things you are testing?  If there are more than
two things, use imbedded switches or go ahead and use if-then-else.

> 
> 
> Joshua Kosman		||  "When I was young people used to tell me,
> kos@ernie.berkeley.EDU	||	'When you're 50 you'll understand.' Well,
> Dept. of Music		||	now I'm 50. I don't understand a thing."
> UC Berkeley		||		-- Erik Satie



- Mark Nagel

ucdavis!u557676751ea@ucbvax.berkeley.edu               (ARPA)
...!{dual|lll-crg|ucbvax}!ucdavis!deneb!u557676751ea   (UUCP)


"Ever since I gave up hope, I've felt much better!"
				- a bumper sticker somewhere

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

... > Generalized switch

Agreed, a cascade of ifs is the way to implement a generalized
alternative statement in C:
	if( C1 ) 
		S1;
	else if( C2 )
		S2;
	else
		...

However, in a higher level language than C there are many potential
advantages to a generalized switch (I prefer to say alternative)
statement.

If the expressions are complicated, eg. (in my preferred syntax
- the ::s would be blocks `a la Dijkstra if I had them)

	IF C1 AND C2 THEN ...
	:: C1 AND NOT C2 AND C3 THEN ...
	:: NOT C1 AND NOT C2 AND C3 THEN ...
	ELSE ...
	ENDIF

you probably would not want to implement them as a cascade of IFs
- you would probably want to use some sort of tree structure
	if( C1 ) 
		if( C2 ) ...
		else ...
	else if( !C2 && C3 ) ...
	else ...
as the expressions get more complicated so does the tree, obscuring
the original branching at one point nature of the original code.
A compiler that understood a bit about logical expressions could
generate a good tree for you, automatically.

In fact, if you can ascribe probabilities to each of the conditions
or branches, an optimum tree from the point of view of speed can
be easily generated automatically. I apply this Huffman algorithm
myself in my hand coding, when I have to worry about speed.


Also, the generalized alternative is not, strictly speaking, a cascade.
Ie. no two of the alternatives should simultaneously hold, in a 
deterministic language (in an undeterministic language multiple
alternatives may be valid, of which one or more at random may be
taken). In this example
	IF C1 AND C2 THEN ...
	:: C1 AND C3 THEN ...
	ELSE ...
	ENDIF
C2 and C3 should not simultaneously hold if C1, for a deterministic 
language. A compiler can easily generate checks for this.


Anyway, enough of that. Returning to the language I have to work in,
I have found a similar construct useful in C. Coming from an 
engineering background, I am used to working in truth tables -
I like laying out functions
	Inputs		Outputs
	-----------------------
	TTT		S1
	TFT		S2
	F**		S3
In computational geometry I've gone 5 inputs deep (with lots of
don't care conditions). Laying these out as a tree of IFs obscures
the tabular nature of my understanding of the problem, but this
can be remedied with a few #defines in C:

	switch( boolvec(C1,C2,C3) ) {
		case TTT:	S1; break;
		case TFT:	S2; break;
		case Fxx:	S3; break;
	}

OK, folks, tell me I'm ...


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

karl@haddock (08/07/86)

barmar@mit-eddie.MIT.EDU (Barry Margolin) writes:
>It might, however, be reasonable to extend the case statement to not
>require all the cases to be constants.  This would still provide the
>first two features I listed; the compiler would have to do a bit more
>work to determine if the construct can be translated into a jump table.

But switch as currently implemented always matches exactly one case
(assuming an implicit "default: break;" if necessary).  I like switch to be
commutative, i.e. case blocks to be interchangeable; I think this idea is a
step in the wrong direction.  (I realize that switch is not quite
commutative now, because of fallthrough.  I'd like to see this "feature"
phased out, too.  "Warning: case label entered from above"?)

Now, some constructive counterproposals.

I think one should be able to specify a list.  "case 1,4,10:" is neater than
"case 1: case 4: case 10:", and shoots down the obvious objection to my
comment about fallthrough.  (Yes, I know there are more subtle objections.
I'm willing to use a goto for them, if switch gets cleaned up.)

Better yet would be a list of ranges.  "case 'a' to 'z', 'A' to 'Z':"
requires 52 labels in the current syntax; this is where I normally rewrite
as if-else.  (Yes, I know that's better anyway because I can use the more
portable test isletter().  But there are other uses for range cases, and
one could always "#define UPPER 'A' to 'I', 'J' to 'R', 'S' to 'Z'" for
EBCDIC systems, to retain portability.)  It should also be possible to
specify open-ended ranges, to allow things like "switch (strcmp(s, t)) {
case LT: ... case EQ: ... case GT: ... }" where LT and GT are #define'd as
intervals extending to minus and plus infinity.

Syntactic issues: I introduced a new keyword "to" in the above.  This should
be a punctuation mark instead, but "-" already has meaning in this context.
(If backward compatibility were not a problem, "case 'a'-'z':" could still
be interpreted as a range, and expression containing minus would have to be
enclosed in parens -- but that would be too confusing.)  The ellipsis mark
"..." could be used, I suppose; I don't see any confusion with the varargs
function prototype notation.  Interval notation like "['a','z']" is another
interesting possibility*; it allows for both open "()" and closed "[]"
intervals, as well as mixed: "case [0,N): return a[i];".  But I don't think
the user community is ready for misbalanced hooklets**.

Btw, note that the use of comma is not a problem since the comma operator is
not permitted in constant expressions***.  (Nor would it be useful.)

Karl W. Z. Heuer (ihnp4!ima!haddock!karl), The Walking Lint
*   "[a,b)" is the American notation for a half-open interval.  The European
    notation is "[a,b[", which would be even worse.
**  hooklet: generic bracket.  See discussion in net.lang.
*** According to X3J11 draft of May, 1986 (page 48, line 12).

mouse@mcgill-vision.UUCP (08/09/86)

[Discussion about switch versus if/elseif]
> As I understand it, a switch/case setup compiles exactly the same as
> 	if (var == const1) {.....};
> 	else if (var == const2) {.....};
> 	else  {default_action};
> anyway. (Or am i wrong?).

In a way.  They are the same in the sense that i=i+j and i+=j are the
same.  The switch expression is evaluated only once, which can be
important:

	switch (*bufp++)
-- 
					der Mouse

USA: {ihnp4,decvax,akgua,utzoo,etc}!utcsri!mcgill-vision!mouse
     think!mosart!mcgill-vision!mouse
Europe: mcvax!decvax!utcsri!mcgill-vision!mouse
ARPAnet: utcsri!mcgill-vision!mouse@uw-beaver.arpa

"Come with me a few minutes, mortal, and we shall talk."
			- Thanatos (Piers Anthony's Bearing an Hourglass)

franka@mmintl.UUCP (Frank Adams) (08/11/86)

In article <2600072@ccvaxa> aglew@ccvaxa.UUCP writes:
>C2 and C3 should not simultaneously hold if C1, for a deterministic 
>language. A compiler can easily generate checks for this.

A compiler can easily generate checks for certain simple cases of this.  It
cannot generate checks which are guaranteed to work; the problem is
undecidable in general.

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

dave@inset.UUCP (Dave Lukes) (08/13/86)

FLAME WARNING:
this article contains statements of a possibly insulting/inflammatory nature:
no further warnings will be given.

In article <86900006@haddock> karl@haddock.UUCP writes:
>I think one should be able to specify a list.  "case 1,4,10:" is neater than
>"case 1: case 4: case 10:",

Sure, but
a)	is ``neatness'' the only criteria for a language feature??
	What about usefulness??
b)	I never actually type large case lists,
	I just type the constants then use an editor to insert
	the ``case''s and the ``:''s.

>Better yet would be a list of ranges.  "case 'a' to 'z', 'A' to 'Z':"
>requires 52 labels in the current syntax; this is where I normally rewrite
>as if-else.  (Yes, I know that's better anyway because I can use the more
>portable test isletter().  But there are other uses for range cases, and
		 ^^^^^
One would have thought that someone proposing extensions to C would know
the correct name: isalpha().
Also: what ``other uses''?
First you suggest a way of using something which you admit can be done better
in other ways, then you suggest it has ``other uses'' without saying what
they are!!
>one could always "#define UPPER 'A' to 'I', 'J' to 'R', 'S' to 'Z'" for
>EBCDIC systems, to retain portability.)  It should also be possible to
		    ^^^^^^^^^^^^^^^^^^

So that's your definition of ``portability''??
``It works on ASCII and EBCDIC''.
This is a worldwide network (not all of us speak ``English''
and spend $).

What happens when we introduce more (i.e. international) character sets??
(-:Don't you care, or do you make your money by porting non-portable code? :-)

>specify open-ended ranges, to allow things like "switch (strcmp(s, t)) {
>case LT: ... case EQ: ... case GT: ... }" where LT and GT are #define'd as

What's wrong with ``if''??

>intervals extending to minus and plus infinity.
				       ^^^^^^^^
What is ``infinity''?
This just seems like another encouragement to non-portability.

In summary:
the suggested ``feature(s) are useful only if you intend to write non-portable
code or save a few seconds typing and thought:
we have enough problems already with non-portabilities in C code without
adding more rope for turkeys to hang themselves with.

>Karl W. Z. Heuer (ihnp4!ima!haddock!karl), The Walking Lint
					    ^^^^^^^^^^^^^^^^
(-:(-: From what you have said, I think you should be forced to withdraw your
.signature on the grounds of misrepresentation!
:-):-):-):-):-):-):-):-):-):-)

>*   "[a,b)" is the American notation for a half-open interval.  The European
>    notation is "[a,b[", which would be even worse.

Actually: the ``European'' (by no means universally European) notation is a
LOT better: you don't have to stare at the equation trying to disambiguate
different kinds of parenthesis (especially useful if your printer's
character set is lousy, or the copy is badly handwritten),
although I'm used to the ``American'' notation, which ``looks nicer''.
-- 

		Dave Lukes. (...!inset!dave)

``Fox hunting: the unspeakable chasing the inedible'' -- Oscar Wilde

mike@enmasse.UUCP (Mike Schloss) (08/14/86)

->[Discussion about switch versus if/elseif]
->> As I understand it, a switch/case setup compiles exactly the same as
->> 	if (var == const1) {.....};
->> 	else if (var == const2) {.....};
->> 	else  {default_action};
->> anyway. (Or am i wrong?).
->
->In a way.  They are the same in the sense that i=i+j and i+=j are the
->same.  The switch expression is evaluated only once, which can be
->important:
->
->	switch (*bufp++)

One other difference is that case statements are optimized by some compilers
to use jump tables and such so they can be much more efficient than repeated
if/else statements.

simon@einode.UUCP (Simon Kenyon) (08/14/86)

>>*   "[a,b)" is the American notation for a half-open interval.  The European
>>    notation is "[a,b[", which would be even worse.
> 
> Actually: the ``European'' (by no means universally European) notation is a
> LOT better: you don't have to stare at the equation trying to disambiguate
> different kinds of parenthesis (especially useful if your printer's
> character set is lousy, or the copy is badly handwritten),
> although I'm used to the ``American'' notation, which ``looks nicer''.

since when has [a,b[ been the european notation for a half open interval?
i was taught [a,b) thank you very much
ireland is a tadge more european that britain :-)
-- 
Simon Kenyon			The National Software Centre, Dublin, IRELAND
simon@einode.UUCP						+353-1-716255
EEEK /dev/mouse escaped (Glad to see my competition went down well at USENIX)

stuart@BMS-AT.UUCP (Stuart D. Gathman) (08/19/86)

In article <1083@inset.UUCP>, dave@inset.UUCP (Dave Lukes) writes:

> >specify open-ended ranges, to allow things like "switch (strcmp(s, t)) {
> >case LT: ... case EQ: ... case GT: ... }" where LT and GT are #define'd as
> 
> What's wrong with ``if''??

'if' requires the result of strcmp() to be stored in a register or else
evaluated twice.  i.e.  { if ((r = strcmp(s,t)) < 0) less(); else if (r == 0)
same(); else more(); }  Try writing a balanced binary tree routine.  Storing
the result in a register is certain to be at least as efficient as any
implementation of open ended ranges, however.  The switch does look a lot
neater; of course, if people restricted their compares to return -1,0,1
there would be no problem.  Also, open ended ranges need not be implemented
in the compiler since macros like MAXINT are available.  Ranges should
not be a problem, though; many compilers already convert adjacent cases
to ranges so that a jump table can be used.

karl@haddock (08/20/86)

inset!dave (Dave Lukes) writes:
>FLAME WARNING:

I have resisted the urge to make this a counter-flame.

>In article <86900006@haddock> karl@haddock.UUCP writes:
>>I think one should be able to specify a list.  "case 1,4,10:" is neater than
>>"case 1: case 4: case 10:",
>
>Sure, but
>a)	is ``neatness'' the only criteria for a language feature??
>	What about usefulness??

I thought I explained why I thought it would be useful.  I'll try again below.

>b)	I never actually type large case lists,
>	I just type the constants then use an editor to insert
>	the ``case''s and the ``:''s.

That makes it easier to write, but it doesn't help the person who has to
read the code later.  "The editor can fix it" doesn't wash.

>>Better yet would be a list of ranges.  "case 'a' to 'z', 'A' to 'Z':"
>>requires 52 labels in the current syntax; this is where I normally rewrite
>>as if-else.  (Yes, I know that's better anyway because I can use the more
>>portable test isletter().  But there are other uses for range cases, and
>		 ^^^^^
>One would have thought that someone proposing extensions to C would know
>the correct name: isalpha().

Oops, a Freudian slip.  I've always thought it *should* have been called
isletter(), since I prefer to use "alpha" for "alphanumeric".

>Also: what ``other uses''?
>First you suggest a way of using something which you admit can be done better
>in other ways, then you suggest it has ``other uses'' without saying what
>they are!!

("The obvious is often left unsaid in favor of brevity" -- UPM.)  Okay, how
about "case '0' to '7'" for octal, or "case '0' to '9', 'A' to 'F'" for
uppercase hexadecimal?  (Yes, I know about isxdigit().  But "dc", for
example, reserves lowercase a-f for commands.)  If the isascii() function
goes away (as in X3J11), "case 0 to 0x7f" may be useful on ASCII systems.
Moreover (lest you flame about portability again), the switch value need not
be a character; I've written programs that wanted to test some integral
expression against one or more ranges.  (Sorry, I can't give enough context
to prove the program was useful.)

>>one could always "#define UPPER 'A' to 'I', 'J' to 'R', 'S' to 'Z'" for
>>EBCDIC systems, to retain portability.)  It should also be possible to
>                    ^^^^^^^^^^^^^^^^^^
>
>So that's your definition of ``portability''??
>``It works on ASCII and EBCDIC''.

Oh, come on.  You define it as "'A' to 'Z'" on ASCII systems, the mess above
on EBCDIC, and *whatever it needs to be* on other systems!  If your machine
has the brain-damaged collating sequence "AaBbCc...Zz", you have to define it
one letter at a time, but the *use* of the macro is portable.  (The macro
itself can be defined in a standard header file.)

>What happens when we introduce more (i.e. international) character sets??
>(-:Don't you care, or do you make your money by porting non-portable code? :-)

Assuming the character set is known at compile-time, you add the national
characters to the macro.  Otherwise, you use an "if".  I am *not* trying to
make "switch" into a glorified "if-else"; my proposal simply generalizes the
*constant comparisons* already handled by "switch".  *This is important*.

>>specify open-ended ranges, to allow things like "switch (strcmp(s, t)) {
>>case LT: ... case EQ: ... case GT: ... }" where LT and GT are #define'd as
>
>What's wrong with ``if''??

It requires a temporary variable.  Also, with "if" you make two of the three
tests, and the third case falls into "else"; with "switch" there is a nice
symmetry among the three cases, making it more readable.  (And it's likely
to be more efficient, if you care.)

>>intervals extending to minus and plus infinity.
>                                       ^^^^^^^^
>What is ``infinity''?
>This just seems like another encouragement to non-portability.

I don't understand your misunderstanding.  Assume a bracket notation with an
empty string denoting infinity.  "(a,b)" would match any value x such that
a < x && x < b.  "GT" would be defined as "(0,)" which (suppressing the upper
limit) would match any value x such that 0 < x.  What's nonportable?

>In summary:
>the suggested ``feature(s) are useful only if you intend to write non-
>portable code or save a few seconds typing and thought:
>we have enough problems already with non-portabilities in C code without
>adding more rope for turkeys to hang themselves with.

I've already answered the portability question.  As for saving time and
thought, that's what computers are for.  (Not to imply that one shouldn't
think, just that one shouldn't need to worry about details the compiler can
handle easily.)

>(-:(-: From what you have said, I think you should be forced to withdraw your
>.signature on the grounds of misrepresentation!
>:-):-):-):-):-):-):-):-):-):-)

Well, this discussion has very little to do with "lint", so there's not much
to misrepresent.  Anyway, it's not a .signature (file); I type my signature
and attribution-markings by hand (with assistance from an editor).  This is
partly because of some braindamaged software, and also because it helps me
resist the urge to include a cute quote or other such nonsense.  Also, I
like postscripts and footnotes to come after the signature.  I'm explaining
all this because I realize I'm contradicting the spirit of the last clause
in my previous paragraph.

>>*   "[a,b)" is the American notation for a half-open interval.  The European
>>    notation is "[a,b[", which would be even worse.
>
>Actually: the ``European'' (by no means universally European) notation is a

Well, I didn't mean to imply that all American/European sources follow this
convention, but there does seem to be a correlation, and I had to call them
something.

>LOT better: you don't have to stare at the equation trying to disambiguate
>different kinds of parenthesis (especially useful if your printer's
>character set is lousy, or the copy is badly handwritten),
>although I'm used to the ``American'' notation, which ``looks nicer''.

Don't have to disambiguate?  "[ ... [ ... ] ... ]" could denote either nested
brackets, or a left-closed and a right-closed interval.  In the C context,
when the string "[a,b[" has been scanned, the last character could be either
a terminator for the half-open interval, or the beginning of a subscript for
the array "b".  I guess one character of lookahead will resolve it, but it
may still be a problem for the user.  Anyway, unless and until the semantics
are agreed on, the syntax is a moot issue.

Now, in case you missed this point in my previous posting: this proposal can
be implemented in an upward compatible way, and it would eliminate the need
for most fall-through cases.  This *may* make it possible to phase out the
switch-break.  (I believe one of the authors of the language has acknowledged
that this was a botch.)

Karl W. Z. Heuer (ihnp4!ima!haddock!karl), The Walking Lint