C/C++ language proposal: Change the 'case expression' from "integral constant-expression" to "integr

A

Adem

C/C++ language proposal:
Change the 'case expression' from "integral constant-expression" to "integral expression"

The C++ Standard (ISO/IEC 14882, Second edition, 2003-10-15)
says under 6.4.2(2) [see also 5.19]:

case constant-expression :

I propose that the case expression of the switch statement
be changed from "integral constant-expression" to "integral expression".
This opens up many new possibilities since then also function calls
would be permitted in the case expression.
The old case case would continue to function since
it is a subset of the new case case.

Example usage:

//...
int f()
{
//...
return BLA1;
}

int g()
{
//...
return BLA2;
}

int h()
{
//...
return BLA3;
}

int y, x = f();
switch (x)
{
case 123 : y = g(); break;
case g() : y = 456; break; // using new case feature, ie. func-call
case h() : y = 789; break; // ditto
default : y = -1; break;
}
 
L

Lew Pitcher

C/C++ language proposal:
Change the 'case expression' from "integral constant-expression" to
"integral expression"

The C++ Standard (ISO/IEC 14882, Second edition, 2003-10-15)
says under 6.4.2(2) [see also 5.19]:
[snip]

Sorry, but your proposal is off-topic for the comp.lang.c newsgroup. I
suspect that it is also off-topic for comp.lang.c++.

As C and C++ are two separate languages, each defined by their own
standards, I suggest that you break your "C/C++" proposal into a "C
proposal" and a separate "C++ proposal", and submit each to their
respective standards bodies.

For C, you /might/ post your proposal to the comp.std.c newsgroup, as that
is the group that discusses the ramifications of and enhancements to the C
language standard.

--
Lew Pitcher

Master Codewright & JOAT-in-training | Registered Linux User #112576
http://pitcher.digitalfreehold.ca/ | GPG public key available by request
---------- Slackware - Because I know what I'm doing. ------
 
K

Keith Thompson

Eric Sosman said:
Adem said:
C/C++ language proposal: Change the 'case expression' from
"integral constant-expression" to "integral expression"
The C++ Standard (ISO/IEC 14882, Second edition, 2003-10-15)
says under 6.4.2(2) [see also 5.19]:
case constant-expression : I propose that the case expression
of the switch statement
be changed from "integral constant-expression" to "integral expression".

switch (rand()) {
case rand(): puts ("What's"); break;
case rand(): puts ("wrong"); break;
case rand(): puts ("with"); break;
case rand(): puts ("this"); break;
case rand(): puts ("picture?"); break;
}

Well, it *could* be defined to be equivalent to the following:

{
const int __tmp = rand();
if (__tmp == rand() puts("What's");
else if (__tmp == rand() puts("wrong");
else if (__tmp == rand() puts("with");
else if (__tmp == rand() puts("this");
else if (__tmp == rand() puts("picture?");
}

That's intended to be equivalent code just for this example, not a
definition; other transformations would be required when one case
falls through to the next. And I refuse to think about how this would
affect Duff's Device.

The point of C's switch statement is that it can be implemented
efficiently as a jump table, in contrast to an if/else chain where the
conditions have to be evaluated sequentially.

If you want to do something like a switch statement, but where the
case values aren't constant, you can always just write an if/else
chain. If you want to support this kind of thing in the language, so
that you only have to specify the LHS of the comparison once, I think
I'd prefer to introduce a new construct rather than adding this
functionality to the existing switch/case construct. With this
proposal, changing a single expression from a constant to a
non-constant could have substantial effects on the generated code, and
depending on how it's defined, subtle effects on the code's behavior.
 
C

CBFalconer

Lew said:
Adem said:
C/C++ language proposal:
Change the 'case expression' from "integral constant-expression"
to "integral expression"

The C++ Standard (ISO/IEC 14882, Second edition, 2003-10-15)
says under 6.4.2(2) [see also 5.19]:

[snip]

Sorry, but your proposal is off-topic for the comp.lang.c
newsgroup. I suspect that it is also off-topic for comp.lang.c++.

As C and C++ are two separate languages, each defined by their
own standards, I suggest that you break your "C/C++" proposal
into a "C proposal" and a separate "C++ proposal", and submit
each to their respective standards bodies.

For C, you /might/ post your proposal to the comp.std.c newsgroup,
as that is the group that discusses the ramifications of and
enhancements to the C language standard.

In addition, it is a BAD IDEA. Eliminating the constant provision
prevents making efficient transfer tables. It even prevents
discovering that such tables are feasible (or not).
 
L

lovecreatesbeauty

Eric Sosman said:
Adem said:
C/C++ language proposal: Change the 'case expression' from
"integral constant-expression" to "integral expression"
The C++ Standard (ISO/IEC 14882, Second edition, 2003-10-15)
says under 6.4.2(2) [see also 5.19]:
case constant-expression : I propose that the case expression
of the switch statement
be changed from "integral constant-expression" to "integral expression".
switch (rand()) {
case rand(): puts ("What's"); break;
case rand(): puts ("wrong"); break;
case rand(): puts ("with"); break;
case rand(): puts ("this"); break;
case rand(): puts ("picture?"); break;
}
Wonderful!


Well, it *could* be defined to be equivalent to the following:

{
const int __tmp = rand();
if (__tmp == rand() puts("What's");
else if (__tmp == rand() puts("wrong");
else if (__tmp == rand() puts("with");
else if (__tmp == rand() puts("this");
else if (__tmp == rand() puts("picture?");

}

If rand() generates equal random numbers frequently, is it meaningful?
 
B

Bartc

Eric Sosman said:
Adem said:
C/C++ language proposal: Change the 'case expression' from "integral
constant-expression" to "integral expression"

The C++ Standard (ISO/IEC 14882, Second edition, 2003-10-15)
says under 6.4.2(2) [see also 5.19]:

case constant-expression : I propose that the case expression of
the switch statement
be changed from "integral constant-expression" to "integral expression".

switch (rand()) {
case rand(): puts ("What's"); break;
case rand(): puts ("wrong"); break;
case rand(): puts ("with"); break;
case rand(): puts ("this"); break;
case rand(): puts ("picture?"); break;
}

What's wrong with it that you're just injecting garbage. You can use the
same rand() trick with any statement:

for (i=rand(); i<=rand(); i=rand())...

But there's nothing really wrong with the OP's proposal, except it should be
a new statement type to keep the switch semantics clean. Then, it could also
use non-integer types.

C likes it's rather austere syntax however so I doubt this change will ever
be made.
 
A

anon

Bartc said:
Eric Sosman said:
Adem said:
C/C++ language proposal: Change the 'case expression' from "integral
constant-expression" to "integral expression"

The C++ Standard (ISO/IEC 14882, Second edition, 2003-10-15)
says under 6.4.2(2) [see also 5.19]:

case constant-expression : I propose that the case expression
of the switch statement
be changed from "integral constant-expression" to "integral expression".

switch (rand()) {
case rand(): puts ("What's"); break;
case rand(): puts ("wrong"); break;
case rand(): puts ("with"); break;
case rand(): puts ("this"); break;
case rand(): puts ("picture?"); break;
}

What's wrong with it that you're just injecting garbage. You can use the
same rand() trick with any statement:

for (i=rand(); i<=rand(); i=rand())...

But there's nothing really wrong with the OP's proposal, except it
should be a new statement type to keep the switch semantics clean. Then,
it could also use non-integer types.

There is something wrong. Try to compile this example, and I hope you
figure whats wrong with his proposal :

int main()
{
int a = 3;
switch( a )
{
case 3:
a = 1;
break;
case 3:
a = 2;
break;
case 3:
a = 3;
break;
default:
a = 4;
}
}
 
B

Bartc

anon said:
There is something wrong. Try to compile this example, and I hope you
figure whats wrong with his proposal :

int main()
{
int a = 3;
switch( a )
{
case 3:
a = 1;
break;
case 3:
a = 2;
break;
case 3:
a = 3;
break;
default:
a = 4;
}
}

The OP was talking about /expressions/ for case values. But because normal
switch likes it's values to be unique, I suggested a different statement.
This way duplicate case values can still be picked up instead of being
quietly converted to the new semantics:

a=x=y=z=3;

newswitch (a)
{
case x: ...
case y: ...
case z: ...
...
This would just select the first matching expression. No different from a
series of if/else statements as already noted, but more eloquent.
 
B

Bo Persson

Bartc said:
The OP was talking about /expressions/ for case values. But because
normal switch likes it's values to be unique, I suggested a
different statement. This way duplicate case values can still be
picked up instead of being quietly converted to the new semantics:

a=x=y=z=3;

newswitch (a)
{
case x: ...
case y: ...
case z: ...
...
This would just select the first matching expression. No different
from a series of if/else statements as already noted, but more
eloquent.

Yes, it would work, just as it does for COBOL's EVALUATE statement - a
multiway if-statement

http://www.fluffycat.com/COBOL/Evaluate/


Wanna be more like COBOL? :)


Bo Persson
 
L

lovecreatesbeauty

Eric Sosman said:
Adem said:
The C++ Standard (ISO/IEC 14882, Second edition, 2003-10-15)
says under 6.4.2(2) [see also 5.19]:
case constant-expression : I propose that the case expression of
the switch statement
be changed from "integral constant-expression" to "integral expression".
switch (rand()) {
case rand(): puts ("What's"); break;
case rand(): puts ("wrong"); break;
case rand(): puts ("with"); break;
case rand(): puts ("this"); break;
case rand(): puts ("picture?"); break;
}
What's wrong with it that you're just injecting garbage. You can use the
same rand() trick with any statement:

for (i=rand(); i<=rand(); i=rand())...

The statements following each case lable in a switch are intended to
be diffrent, while the body of for statement is the same for each
loop. Eric's trick illustrates that how bad an idean could that
proposal be.
 
K

Keith Thompson

Eric Sosman said:
Adem wrote:
The C++ Standard (ISO/IEC 14882, Second edition, 2003-10-15)
says under 6.4.2(2) [see also 5.19]:
case constant-expression : I propose that the case expression of
the switch statement
be changed from "integral constant-expression" to "integral expression".
switch (rand()) {
case rand(): puts ("What's"); break;
case rand(): puts ("wrong"); break;
case rand(): puts ("with"); break;
case rand(): puts ("this"); break;
case rand(): puts ("picture?"); break;
}
What's wrong with it that you're just injecting garbage. You can use the
same rand() trick with any statement:

for (i=rand(); i<=rand(); i=rand())...

The statements following each case lable in a switch are intended to
be diffrent, while the body of for statement is the same for each
loop. Eric's trick illustrates that how bad an idean could that
proposal be.

The expressions (not statements) are intended (required, in fact) to
be integer constant expressions. The proposal is to change that
requirement. It's moderately obvious that the requirement that no two
of the case expressions would also have to be relaxed, since it's not
possible in general to determine at compilation time whether two
non-constant expressions have the same value.

Defining consistent semantics for a modified switch statement is not
all that difficult. Presumably existing switch statements would have
to behave as they do now. Beyond that, there are several possible
ways to define the semantics and constraints for switch statements
that are currently invalid.

Eric's example demonstrates the need to define the semantics of this
proposed new feature. I don't think it demonstrates, by itself, that
it's a bad idea. If non-constant switch expressions were allowed, it
would be possible to write perfectly sensible code using the new
feature. It would also, as Eric demonstrated, be possible to write
very silly code using the new feature -- or using any of the
language's existing features.

I do agree that the proposed feature is a bad idea, but not because of
Eric's example. I think it's a bad idea because it would have to
define new semantics for an existing construct. Currently, if you
accidentally use a non-constant case expression, the compiler will
diagnose it as an error (and probably reject your program). Under the
proposal, the code would be valid, and would likely behave in a subtly
wrong manner and/or with poor performance. Evaluating the switch
expression and branching to the right case label is typically an O(1)
operation, if the compiler is able to generate a jump table. Add a
single non-constant expression, and it becomes O(N), where N is the
number of cases.

I wouldn't object as strongly to a new feature, with a distinct
syntax, that implements the proposed functionality, but I'd still
oppose it -- not because it's an inherently bad idea, but because the
benefit is IMHO outweighed by the cost of adding a new feature to the
language. There's nothing you could do with the proposed new feature
that you can't already do fairly straightforwardly using existing
features, namely an if/else chain and, if the switch expression is
complicated or has side effects, a temporary variable.
 
C

CBFalconer

anon said:
.... snip ...

There is something wrong. Try to compile this example, and I hope
you figure whats wrong with his proposal :

int main()
{
int a = 3;
switch( a )
{
case 3:
a = 1;
break;
case 3:
a = 2;
break;
case 3:
a = 3;
break;
default:
a = 4;
}
}

Your code works better if it is made legal:

int main(void) {
int a = 3;

switch( a ) {
case 3: a = 1;
break;
case 2: a = 2;
break;
case 1: a = 3;
break;
default: a = 4;
}
return 0;
}

Also, cross posting to c.l.c++ is not cool.
 
B

Bartc

Eric Sosman said:
This has well-defined semantics, albeit not very useful.
The purpose of my example wasn't to claim that it is impossible
to invent semantics for the O.P.'s `switch', but to show that
the proposal as it stands is not even close to adequate.

Let's try another one:

switch (x) {
case f(x): puts("f"); break;
case g(x): puts("g"); break;
}
...
int f(int x) { puts("in f"); return x & 1; }
int g(int x) { puts("in g"); return x & 2; }

What output do you desire when `x == 16'? Two lines?
Three? Four? In what order?

When x is 16, both f() and g() return 0, which does not equal x so matches
neither case.

You're thinking in terms of the current switch semantics which likes unique
case values and can take them in any order. That's why I suggested a
different statement (or just a different keyword).

(I tried this code in a language of mine that accepts expressions for case
expressions. The output was "in f" followed by "in g".

In this language there are two distinct statements: switch-when for integer
values over a small range,expected to be implemented as a jump table (ie. C
switch); and case-when for anything else: large integers or other types.
Although I don't think I've ever used a non-const expression for a
switch/case value. Until now)
 
K

Keith Thompson

CBFalconer said:
Your code works better if it is made legal:

int main(void) {
int a = 3;

switch( a ) {
case 3: a = 1;
break;
case 2: a = 2;
break;
case 1: a = 3;
break;
default: a = 4;
}
return 0;
}

Which completely and utterly misses the point.

The article that started this thread was a proposal to allow
non-constant case expressions. anon's point was that it would then
become impossible (or nearly so) to maintain the property that all
case expressions in a switch statement must have distinct values.
Your "correction" is valid C, but pointless; you might as well have
posted "int main(void) { }".
Also, cross posting to c.l.c++ is not cool.

Perhaps, but the topic of the thread is a proposed change to both C
and C++. Arguably the comp.std.* groups would have been better, but I
think comp.std.c++ is more or less dead these days. Since switch
statements have the same syntax and semantics in C and C++, it's not
entirely unreasonable to discuss a proposed change in both.
 
J

Jerry Coffin

[email protected] says... said:
int y, x = f();
switch (x)
{
case 123 : y = g(); break;
case g() : y = 456; break; // using new case feature, ie. func-call
case h() : y = 789; break; // ditto
default : y = -1; break;
}

This has a number of ramifications that could make definition difficult.
For a few examples, how often would g() be evaluated in the switch
statement above? If both g() and h() returned the same value, which leg
would be taken?
 
K

Keith Thompson

Jerry Coffin said:
This has a number of ramifications that could make definition difficult.
For a few examples, how often would g() be evaluated in the switch
statement above? If both g() and h() returned the same value, which leg
would be taken?

The person proposing the feature did not give enough information to
answer those questions. If the proposed feature were to be added to
the language, then the semantics would have to be worked out first;
doing so shouldn't be too difficult. Once that's done, the answers to
your questions become obvious rather than indeterminate. (Possibly in
some cases the execution would be implementation-defined, or
unspecified, or even undefined, but I'd prefer a simpler definition
that avoids that.)

In my preferred semantics, the above would be exactly equivalent to:

int y, x = f();
int __tmp = x;
if (__tmp == 123) y = g();
else if (__tmp == g()) y = 456;
else if (__tmp == h()) y = 789;
else y = -1;

The number of times g() is evaluated depends on the value of x and the
value returned by g(), which you haven't specified. If both g() and
h() return the same value, and that happens to be the value of x, then
y would be set to 456.

But, as I said, I think the whole thing is a bad idea.
 
M

Matthias Buelow

Adem said:
C/C++ language proposal:
Change the 'case expression' from "integral constant-expression" to "integral expression"

How about:

cond {
(foo == bar): ...; break;
(!bar && (baz == boo)): ...; /* fallthru */
default: ...; break;
}

In pseudo-grammar:

cond { [<expr>|default: <stmt>*]* }
 
K

Keith Thompson

Matthias Buelow said:
Adem said:
C/C++ language proposal:
Change the 'case expression' from "integral constant-expression"
to "integral expression"

How about:

cond {
(foo == bar): ...; break;
(!bar && (baz == boo)): ...; /* fallthru */
default: ...; break;
}

In pseudo-grammar:

cond { [<expr>|default: <stmt>*]* }

One advantage of the switch statement is that the expression only has
to be written once; it's implicitly compared to each of the case label
expressions without being re-evaluated.

Your proposed "cond" statement lacks this advantage, and differs from
an if/else chain only in the ability to fall through from one case to
the next. The latter can easily be done with a goto statement. (Yes,
gotos are ugly; so is falling through from one case to the next. And
you can always restructure the code to avoid gotos.)

As for the grammar, I think you'd want to require a keyword, probably
"case", for each expression:

cond {
case foo == bar: ... break;
case !bar && (baz == boo): ...; /* fallthrough */
default: ...; break;
}

Otherwise the compiler doesn't know until it sees the ':' whether the
expression is part of the cond statement or just an ordinary
expression statement.

And of course it would break every existing program that uses "cond"
as a keyword, but that's easily solved by using "_Cond".
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top