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

J

JoelKatz

In what way would your altered switch be superior to an if/else tree?

Two ways:

1) An if/else tree hides the fact that the same variable is being
tested in each branch. A switch/case makes it clear that the same
expression is being compared in each case.

2) In some cases, it would make truly atrocious code look better. For
example, consider cases where you need to fall through from one case
to another or where you would otherwise need a temporary to avoid
multiple evaluations of the switch variable.
The primary reason to use a switch is that it may be translated at
compile-time into a jump table, but that benefit goes away if the
statements are not known until run-time.  Languages like Ruby have
switches with run-time case expressions because they delay the
translation until run-time, anyway; such languages are using the syntax
to mean something very different from what the C switch means.  IOW,
languages that provide case statements of the form you've suggested do
so only because they *can't* do what C and C++ do.

But they don't provide what he's asking for, and it's a natural
extension of the semantics of the switch/case statement. We could have
a special 'if' that allowed the implementation to cycle a specified
constant, either by counting up, down, or sideways if that was most
efficient. But we don't. We expect the optimizer to figure out how our
code can be micro-optimized.

Why do we have do/while, while, and for? You can make any code ugly by
choosing the wrong one, but you can make a lot of code nice by
choosing the best one.

The biggest argument against this proposal is that it's not really all
that useful. There really just aren't that many places where you could
use something like this.

In a 500,000 C++ line project I'm very familiar with, there are three
places where this could actually be useful. For comparison, it has 818
switch statements.

In two of those cases, it cleans up some ugliness where you need an if/
else tree before a switch/case statement.

What will be next? "case >=7:"?

DS
 
J

James Kanze

How about:
cond {
(foo == bar): ...; break;
(!bar && (baz == boo)): ...; /* fallthru */
default: ...; break;
}
In pseudo-grammar:
cond { [<expr>|default: <stmt>*]* }

I once designed a language with something like that, many, many
years back. In fact, the grammar was a bit more complete,
something like:

cond_stmt := 'cond' [<expr1>] '{' case_list '}'
case_list := /* empty */ | case_list case_clause
case_clause := 'case' [<op>] expr2 ':' stmt
| 'default' ':' stmt

If expr1 was absent, <op> was forbidden, and it worked exactly
like your suggestion (except that there was no fall through---a
case controlled exactly one statement). If expr1 was present,
it was the equivalent of having written "case <expr1> <op>
<expr2>" for each case, except that expr1 was only evaluated
once; if you omitted the <op> in this case, it defaulted to ==,
so you could write things like:

cond x {
case > 0 : ... ;
case == 0 : ... ;
case < 0 : ... ;
}

or

cond c {
case 'a' : ... ;
case 'b' : ... ;
case 'c' : ... ;
}

(IIRC, the keyword was actually select, and not cond, and I used
OF .. END instead of {..}. But the basic idea was the same.)

The idea was basically that there are only four basic structured
constructs: a loop, a choice, a sequence, and a procedure call,
and thus, there were only four basic execution statements.
 
R

robertwessel2

What will be next? "case >=7:"?


Frankly I think ranges on the case constant expressions would be a
more useful addition while staying with the basic philosophy of the C
switch statement. IOW, "case 2...5:", or something along those
lines. But still not something I'm loosing sleep over...
 
K

Keith Thompson

Frankly I think ranges on the case constant expressions would be a
more useful addition while staying with the basic philosophy of the C
switch statement. IOW, "case 2...5:", or something along those
lines. But still not something I'm loosing sleep over...

Then programmers will inevitably write

case 'A' ... 'Z':

which is non-portable (under EBCDIC it matches '\' and '}').
 
W

Willem

Keith Thompson wrote:
) Then programmers will inevitably write
)
) case 'A' ... 'Z':
)
) which is non-portable (under EBCDIC it matches '\' and '}').

In which case, it would be relatively easy to add syntax similar to:

case [A-Z]:

Which would, of course, be portable.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
N

Nate Eldredge

Frankly I think ranges on the case constant expressions would be a
more useful addition while staying with the basic philosophy of the C
switch statement. IOW, "case 2...5:", or something along those
lines. But still not something I'm loosing sleep over...

GCC provides this as an extension, FWIW. You can write

case 2 ... 5:

The spaces are required to keep the parser from thinking it's some
malformed floating point constant.
 
K

Keith Thompson

Willem said:
Keith Thompson wrote:
) Then programmers will inevitably write
)
) case 'A' ... 'Z':
)
) which is non-portable (under EBCDIC it matches '\' and '}').

In which case, it would be relatively easy to add syntax similar to:

case [A-Z]:

Which would, of course, be portable.

It could be, if you defined it *very* carefully.

Lexically, you have 7 tokens:
case (a keyword)
[ (a punctuator)
A (an identifier)
- (a punctuator)
Z (an identifier)
] (a punctuator)
: (a punctuator)

Do you really intend the identifier A here to refer to the character
'A', ignoring any declared entity called A? Do you really intend to
specify a range of literal character values without using the "'"
symbol? Which characters would be allowed? Does [A-Z] refer only to
the 26 uppercase letters of the Latin alphabet? Could this notation
be used for non-Latin letters? Digits? Punctuation symbols?

Properly defined, it could make it easier to work with Latin letters
-- which is both good and bad, since it would further encourage
programmers to ignore the fact that other alphabets exist. Sometimes
you really do want to determine whether a character matches one of the
26 uppercase Latin letters, but more often what you *really* want is
the locale-sensitive behavior of isupper().
 
W

Willem

Keith Thompson wrote:
)> In which case, it would be relatively easy to add syntax similar to:
)>
)> case [A-Z]:
)>
)> Which would, of course, be portable.
)
) It could be, if you defined it *very* carefully.
)
) <snip>
)
) Do you really intend the identifier A here to refer to the character
) 'A', ignoring any declared entity called A?

Well, no. That's why I stated 'similar to'. It's just an idea after all.

) programmers to ignore the fact that other alphabets exist. Sometimes
) you really do want to determine whether a character matches one of the
) 26 uppercase Latin letters, but more often what you *really* want is
) the locale-sensitive behavior of isupper().

Well, then how about

case [:upper:]:

Which, to be honest, is half-borrowed from Perl syntax.
What the exact syntax is, isn't really relevant, I guess.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
H

Hallvard B Furuseth

Keith said:
Then programmers will inevitably write

case 'A' ... 'Z':

They do anyway. #define ISUPPER(c) ('A' <= (c) && (c) <= 'Z'). E.g. to
check for the ASCII (or 7-bit Unicode) letters regardless of locale.
 
K

Keith Thompson

Hallvard B Furuseth said:
They do anyway. #define ISUPPER(c) ('A' <= (c) && (c) <= 'Z'). E.g. to
check for the ASCII (or 7-bit Unicode) letters regardless of locale.

Sure, but there's not much that can be done to discourage dumb macros.
Actually, there is: <ctype.h> already has the locale-sensitive
isupper() function.

The problem with the proposed "..." notation is that it makes it easy
to do the wrong thing (assuming that the uppercase letters have
contiguous codes and run from 'A' to 'Z') *without* making it any
easier to do the right thing (using isupper() to determine whether a
character is an uppercase letter).

On the other hand, there are certainly times when case ranges would be
handy for numeric ranges, as opposed to character ranges, and using
them wouldn't cause any problems. Other languages do provide similar
constructs. And I suppose compilers could warn about 'A' ... 'Z'.

Caveat: Sometimes ('A' <= c && c <= 'Z') *is* exactly what you want,
if you're writing deliberately non-portable code.
 
S

Sjouke Burry

Frankly I think ranges on the case constant expressions would be a
more useful addition while staying with the basic philosophy of the C
switch statement. IOW, "case 2...5:", or something along those
lines. But still not something I'm loosing sleep over...

That was already included in microsoft fortran 5.1 (extension)
in 1990 :) :)
 
K

Keith Thompson

Hendrik Schober said:
And why exactly would that be worse than an 'if'-'else' chain
relying on ASCII?

It wouldn't. The problem (as I think I've already said in this
thread) is that adding this syntax makes it much easier to check for
characters in the range 'A' to 'Z' *without* making it any easier to
check for characters that are uppercase letters.

It's not the least bit difficult to write bad code in C or C++ (this
is cross-posted), even with their current features, but let's not make
it even easier.
 
H

Harald van Dijk

Caveat: Sometimes ('A' <= c && c <= 'Z') *is* exactly what you want, if
you're writing deliberately non-portable code.

It doesn't need to be *deliberately* non-portable. If you were
implementing your own C library, on an ASCII-based machine with minimal
locale support, this could be the best way to write isupper.
 
K

Keith Thompson

Harald van Dijk said:
It doesn't need to be *deliberately* non-portable. If you were
implementing your own C library, on an ASCII-based machine with minimal
locale support, this could be the best way to write isupper.

I'd call that deliberately non-portable, at least if you know what
you're doing.
 
H

Harald van Dijk

I'd call that deliberately non-portable, at least if you know what
you're doing.

I read your message as suggesting non-portable had to be a goal for 'A'<=c
&& c<='Z' to be the right thing. If you meant that non-portable can be
okay, just that you need to be aware of it, then agreed.
 
K

Keith Thompson

Harald van Dijk said:
I read your message as suggesting non-portable had to be a goal for 'A'<=c
&& c<='Z' to be the right thing. If you meant that non-portable can be
okay, just that you need to be aware of it, then agreed.

Exactly. Portability is good, all else being equal, but all else is
not always equal.
 
K

Keith Thompson

Hendrik Schober said:
Keith said:
Hendrik Schober said:
Keith Thompson wrote: [...]
Then programmers will inevitably write
case 'A' ... 'Z':
which is non-portable (under EBCDIC it matches '\' and '}').
And why exactly would that be worse than an 'if'-'else' chain
relying on ASCII?
It wouldn't. [...]

Then I don't see how your above argument is valid.

Since you snipped my argument, I have no idea why you disagree with
it.
 
K

Keith Thompson

Hendrik Schober said:
Keith said:
Hendrik Schober said:
Keith Thompson wrote:
Keith Thompson wrote: [...]
Then programmers will inevitably write
case 'A' ... 'Z':
which is non-portable (under EBCDIC it matches '\' and '}').
And why exactly would that be worse than an 'if'-'else' chain
relying on ASCII?
It wouldn't. [...]
Then I don't see how your above argument is valid.
Since you snipped my argument, I have no idea why you disagree with
it.

Funny. My newsreader still shows it.

I was referring to the text you replaced with "[...]".
 

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,995
Messages
2,570,226
Members
46,815
Latest member
treekmostly22

Latest Threads

Top