[comp.std.c++] case

krste@ICSI.Berkeley.EDU ( Krste Asanovic) (08/08/90)

The C/C++ switch statement is very limited as it only allows integer
expressions. I'd like to suggest a more general case statement.
The syntax would be,

    case (exp) {
        case val1 : s1;
        case val2 : s2;
        default : sOther;
    }

This uses the already reserved keyword case, followed by a
parenthesised expression, to introduce the construct. The standard
switch case and default labels would be used as before. The limitation
that case label expressions are compile-time constants would be
removed (although optimizing compilers could check for this case). The
limitation that case labels be unique would be removed (can't check
this at run time), but the order in which case expressions were tested
would be undefined. Comparisions would use the appropriate ==
operator, in the above example the tests would be

if (exp.operator==(val1)) ..s1...   \ in undefined order.
if (exp.operator==(val2)) ..s2...   /

henry@zoo.toronto.edu (Henry Spencer) (08/08/90)

In article <26842@pasteur.Berkeley.EDU> krste@ICSI.Berkeley.EDU ( Krste Asanovic) writes:
>The C/C++ switch statement is very limited as it only allows integer
>expressions. I'd like to suggest a more general case statement.
>The syntax would be,
>
>    case (exp) {
>        case val1 : s1;
>        case val2 : s2;
>        default : sOther;
>    }

Try this, which is already legal C++:

	if (exp == val1)
		s1;
	else if (exp == val2)
		s2;
	else
		sOther;

It is a bit less convenient to type, but does the job.  I greatly doubt
that X3J16 will sanction a new and untried feature which duplicates
an existing one with only a trivial variation in syntax.
-- 
The 486 is to a modern CPU as a Jules  | Henry Spencer at U of Toronto Zoology
Verne reprint is to a modern SF novel. |  henry@zoo.toronto.edu   utzoo!henry

bilmes@icsib.Berkeley.EDU (Jeff Bilmes) (08/09/90)

In article <26842@pasteur.Berkeley.EDU> krste@ICSI.Berkeley.EDU ( Krste Asanovic) writes:
>The C/C++ switch statement is very limited as it only allows integer
>expressions. I'd like to suggest a more general case statement.
>The syntax would be,
>
>    case (exp) {
>        case val1 : s1;
>        case val2 : s2;
>        default : sOther;
>    }
>
> ...

I think this is unnecessary. C++ is already a large language and new 
features which don't have important semantic advantages should 
be avoided. The case statement you mention above would only add
type checking and non compile time constants "switched" on in a (I
presume) syntactically pleasing way. This does not warrant
extending the language when you can do the semantic equivalent as
easily as:

    if (exp == val1) 
	s1 
    else if (exp == val2)
	s2
    else if (exp == val3 || exp == val4 || exp == val5 || ...)
	s3
    ...

----------------------------------------------------------
 Jeff Bilmes        arpa: bilmes@icsi.berkeley.edu
                    uucp: ...!ucbvax!icsi!bilmes

bobatk@microsoft.UUCP (Bob ATKINSON) (08/14/90)

In article <26857@pasteur.Berkeley.EDU> bilmes@icsib (Jeff Bilmes) writes:
>In article <26842@pasteur.Berkeley.EDU> krste@ICSI.Berkeley.EDU ( Krste Asanovic) writes:
>>The C/C++ switch statement is very limited as it only allows integer
>>expressions. 
...
>
>This does not warrant
>extending the language when you can do the semantic equivalent as
>easily as:
>
>    if (exp == val1) 
>	s1 
>    else if (exp == val2)
>	s2
>    else if (exp == val3 || exp == val4 || exp == val5 || ...)
>	s3
>    ...

By this logic, switch statements should not have been invented
in the first place.  Clearly in C a need was felt for this syntactic
sugar.  Krste was merely pointing out that one can argue that
the same needs can motivate a similar extension for non-integral
types, of which there are a significantly larger number in C++
(that have equality operators) than in C.

I guess I don't feel particularly strongly about this issue;
I just felt the reasoning being used was flawed.


	Bob Atkinson
	Microsoft

scott@bbxsda.UUCP (Scott Amspoker) (08/14/90)

In article <56515@microsoft.UUCP> bobatk@microsoft.UUCP (Bob ATKINSON) writes:
>In article <26857@pasteur.Berkeley.EDU> bilmes@icsib (Jeff Bilmes) writes:
>>This does not warrant
>>extending the language when you can do the semantic equivalent as
>>easily as:
>>
>>    if (exp == val1) 
>>	s1 
>>    else if (exp == val2)
>>	s2
>>    else if (exp == val3 || exp == val4 || exp == val5 || ...)
>>	s3
>>    ...
>
>By this logic, switch statements should not have been invented
>in the first place.  Clearly in C a need was felt for this syntactic
>sugar....

I disagree.  A series of 'if' statements implies a sequence of tests
to be performed.  A 'switch' implies a multi-way branch in which any
of the possible case values are equally likely to occur.  This can
be easily optimized by a compiler.  Although the standard does not 
mandate it, a switch statement is expected, in most cases, to be 
implemented as a quick indirect-jump table.

It is not unusual to have switches with over 100 cases which would
not perform acceptably as a series of 'if' statements.  Syntactical
sugar indeed!

It is difficult to expand the multiway-jump concept to include
non-integral values.  In those cases, a switch statement really is
nothing more than a series of 'if's.

-- 
Scott Amspoker
Basis International, Albuquerque, NM
(505) 345-5232
unmvax.cs.unm.edu!bbx!bbxsda!scott

xanthian@zorch.SF-Bay.ORG (Kent Paul Dolan) (08/14/90)

bobatk@microsoft.UUCP (Bob ATKINSON) writes:
>bilmes@icsib (Jeff Bilmes) writes:
>>krste@ICSI.Berkeley.EDU ( Krste Asanovic) writes:
>>>The C/C++ switch statement is very limited as it only allows integer
>>>expressions. 
>...
>>
>>This does not warrant
>>extending the language when you can do the semantic equivalent as
>>easily as:
>>
>>    if (exp == val1) 
>>	s1 
>>    else if (exp == val2)
>>	s2
>>    else if (exp == val3 || exp == val4 || exp == val5 || ...)
>>	s3
>>    ...
>
>By this logic, switch statements should not have been invented
>in the first place.  Clearly in C a need was felt for this syntactic
>sugar.  Krste was merely pointing out that one can argue that
>the same needs can motivate a similar extension for non-integral
>types, of which there are a significantly larger number in C++
>(that have equality operators) than in C.
>
>I guess I don't feel particularly strongly about this issue;
>I just felt the reasoning being used was flawed.

Perhaps, but there is a more important reason to leave things alone:
there are well known problems with testing equality with, explicitly,
floating point values, and an extension of the case statement, where
the test is unobvious, to allow, explicitly, floating point case
switches, would promote maintenance problems.

When the test is done with the "else if" paradigm, the use of the
equality test is explicit, obvious, and thus easier to spot as a
possible source of trouble during maintenance.

Just a thought.

Kent, the man from xanth.
<xanthian@Zorch.SF-Bay.ORG> <xanthian@well.sf.ca.us>

rpk@wheaties.ai.mit.edu (Robert Krajewski) (08/15/90)

In article <962@bbxsda.UUCP> scott@bbxsda.UUCP (Scott Amspoker) writes:
>I disagree.  A series of 'if' statements implies a sequence of tests
>to be performed.  A 'switch' implies a multi-way branch in which any
>of the possible case values are equally likely to occur.  This can
>be easily optimized by a compiler.  Although the standard does not 
>mandate it, a switch statement is expected, in most cases, to be 
>implemented as a quick indirect-jump table.

Let the compiler decide that, then. switch should just specify
semantics.

>It is not unusual to have switches with over 100 cases which would
>not perform acceptably as a series of 'if' statements.  Syntactical
>sugar indeed!

Well, there is one other benefit to switch: the switched thing is
an expression, it is evaluated only once, right ?  So you get a
temporary for free if you need it.

I would like to see switch be extended at least to cover data types
for which == holds.  It's unfortunate that case tags have to be constants,
but I can live with that.
-- 
Robert P. Krajewski
Internet: rpk@ai.mit.edu ; Lotus: robert_krajewski.lotus@crd.dnet.lotus.com

perry@key.COM (Perry The Cynic) (08/18/90)

In article <9907@rice-chex.ai.mit.edu> rpk@rice-chex.ai.mit.edu (Robert Krajewski) writes:
> In article <962@bbxsda.UUCP> scott@bbxsda.UUCP (Scott Amspoker) writes:
> >I disagree.  A series of 'if' statements implies a sequence of tests
> >to be performed.  A 'switch' implies a multi-way branch in which any
> >of the possible case values are equally likely to occur.  This can
> >be easily optimized by a compiler.  Although the standard does not 
> >mandate it, a switch statement is expected, in most cases, to be 
> >implemented as a quick indirect-jump table.
>
> Let the compiler decide that, then. switch should just specify
> semantics.

Exactly. A resonable compiler will compile a switch with two or three cases
as an if/then/else sequence, internally. Often compilers also break up
switches with large gaps between tag values.

> >It is not unusual to have switches with over 100 cases which would
> >not perform acceptably as a series of 'if' statements.  Syntactical
> >sugar indeed!
> 
> Well, there is one other benefit to switch: the switched thing is
> an expression, it is evaluated only once, right ?  So you get a
> temporary for free if you need it.
> 
> I would like to see switch be extended at least to cover data types
> for which == holds.  It's unfortunate that case tags have to be constants,
> but I can live with that.

The problem here is that the compiler has no guarantee that a user-defined
operator== provides the nice mathematical properties of true equality. For
all the compiler knows, for a user-defined type T, "a==b && b==c" does not
necessarily imply "a==c"; in fact it doesn't even guarantee "b==a". Yes, it's
bad coding to violate these expected properties, but a compiler can't rely
on "good form", only on the language standard.

Thus, you'd have to carefully define whether
	switch (x) { case a: mumble(); }
means
	if (x==a) mumble();
or
	if (a==x) mumble();
Neither interpretation strikes me as inherently more obvious. You don't really
want to add this kind of confusion to the language.


		About non-constant case tags:

The main problem with allowing non-constant case tags is precisely that the
"switch" statement is intended as a "simultaneous choice" operation, not 
a sequential scan. Consider this example:

	switch (expr) {
	case foo(): mumble(); break;
	case bar(): tumble(); break;
	}

How are foo() and bar() evaluated? Both, before a choice is made? In what
order? If you *require* both foo() and bar() to be always evaluated, the
compiler can't short-circuit things if it finds an early match, so the result
would never be more efficient than an if-cascade. And what happens if foo()
and bar() evaluate to the same value? Execute mumble() or tumble(), or both()
(in what order :-)? This isn't a can of worms, it's a whole truck load.
If you want a good laugh, try to interprete this:

	switch (n) {
	case n++: n--; mad(); break;
	case n++: n--; ness(); break;
	}

Just to beat the dead horse into pulp, imagine that expr (and foo and bar)
above are of a user-defined type with an operator== defined. Now the compiler
is completely clue-less. It is possible that "expr==foo() && expr==bar()"
but "foo() != bar()". To give well-defined semantics to this construct, we
would have to rigidly define one particular order of evaluation for things.
And that would indeed reduce this new construct to purely syntactic sugar on
top of an if/then/else cascade.
  -- perry

P.S.:	If your main concern is the visual ugliness and confusion of long
	if-cascades, you can use the preprocessor to make your own syntax.
	I'm not sure that I would recomment that, though.
-- 
--------------------------------------------------------------------------
Perry The Cynic (Peter Kiehtreiber)		       perry@arkon.key.com
** What good signature isn't taken yet? **  {amdahl,sgi,pacbell}!key!perry

rb@cc.ic.ac.uk (Robin Becker) (08/24/90)

There seems to be a fundamental reason why case/switch statements
with variable/expression tags are to be avoided and that is the
impossibility of guaranteeing that a unique tag will be selected.
This means that either some ordering of tag interrogation has to
be imposed which will kill optimisations (unless all tags are constant)
or we abandon determinism and let the compiler decide.  Of course
this construct has been discussed before by Hoare,  I seem to
remember something about programs shouldn't depend on the order
of guard evaluation.  Even worse in parallel processing two guards
may get evaluated to true so parallel languages like Occam must
do something about this, but I don't know what.