Proposed Enhancement to select/case (yes, I know...)

James C Burley burley at world.std.com
Thu Aug 30 20:06:45 AEST 1990


After seeing some of the discussions about what can't (or shouldn't) be added
to C/C++ select/case construct capabilities, I'd like to post my thoughts on
something that might actually be useful and should be easy to implement.

First off, this proposal applies to both C++ and C.  I don't suggest adding
any new types; run-time expressions on cases; class types on selects/cases; or
anything like that.  Plenty of people have provided excellent explanations of
why those features would not be desirable.

But how about this: allow ranges (and, perhaps, lists) on case statements.
I'll pick a syntax for now -- using brackets, though perhaps someone has a
better idea.  Here's an example:

select(foo)  // Nothing new here.
  {
  case ALPHA:  // Nothing new here.
    ...

  case [BETA:GAMMA]:  // Matches any value for foo where BETA<=foo<=GAMMA.
    ...

  case [:MINIMUM,MAXIMUM:]:  // Matches foo<=MINIMUM or foo>=MAXIMUM.
    ...

  case [EPSILON,OMEGA]:  // like "case EPSILON: case OMEGA:".
    ...

  case [DELTA:PI,TAU]:  // like "case [DELTA:PI]: case TAU:".
    ...

  }

To summarize, a case statement may have a comma-separated list of
case-range-exprs (at least one item in the list) within brackets instead of
the usual integral constant expression.  Each case-range-expr is either an
integral constant expression (called "int-expr" subsequently), "int-expr:",
":int-expr", or "int-expr:int-expr".

Within a switch construct, only one case-range-expr with the form ":int-expr"
is permitted, and only one with the form "int-expr:" is permitted.  If two
case-range-exprs exist, one with the each of these forms, "default" is not
permitted (or, it could be interpreted as a null range, described below, if
people want).

If a given case-range-expr effectively specifies a null range, it is considered
a null case range.  Null case ranges are permitted.  A null range occurs if
the int-expr in ":int-expr" is less than the minimum value representable
by the type of the expression in the select statement; if the int-expr in
"int-expr:" is greater than the maximum value representable; or, for a range
of the form "lowest:highest", lowest>highest, lowest>maximum-value, or
highest<minimum-value.

Enough technotrivia: the only really useful new features are the ":i", "i:"
range forms to designate things "default" currently cannot, and the "i:j"
form to designate gaps in constants whose actual values are defined by
"someone else" (some #include file).  The ability to use commas to make
lists is purely for convenience.

I believe nothing about this proposal is at all difficult to implement in
terms of parsing or generating code.  Compilers generating tables would have
to specially handle the open-ended ranges (":i" and "i:"), but my guess is
their implementations of default with such tables are already very close.

Finally, we'd all be able to write (yeah, here's the good part):

switch(c)
  {
  case ['A':'Z','a':'z']:
    // letter

  case ['0':'9']:
    // digit

  case [:' '-1,'~'+1:]:
    // unprintable character

  }

This is easier than listing everything using lots of "case" statements, and
(usually) faster than using <ctype.h> functions (macros).  I'm not going to
say it's any more portable, however; in fact it is less portable than using
<ctype.h> or just listing all the letters (and digits?) individually.  It's
a "hacker's example" of the utility of case ranges; a more realistic example
is hinted at in the first sample in this posting (where the source code
containing the select is not under the same control as that defining the
constants in the case statements).

A thought: although I still shiver at the idea of allowing float or
double types on a select, the availability of ranges somewhat lessens the
arguments against it: the language could disallow any case specification
(other than, perhaps, the constant 0.) was not a range.  However, once one
has floats, one next wants ways to say "foo<0.", "foo==0.", "foo>0.",
for example, somehow extending the syntax to specify "<" or ">" comparisons
instead of "<=" or ">=".  And I think that suggests floats are going too far.

Anyway, the basic idea of case ranges (and lists of cases) comes from Fortran
90, as many of you already know.  Please don't assume that it therefore is a
bad idea!

Does anyone know any good reasons NOT to implement some or all of these
features in today's C++ and C compilers, with an eye towards codifying them
in the next ANSI standards for these languages?  I wouldn't suggest putting
them into the standards until people had had a couple of years to try them
out in real code...if they're not useful, let's not add the extra baggage; at
least that's my philosophy as a C programmer!

James Craig Burley, Software Craftsperson    burley at world.std.com



More information about the Comp.std.c mailing list