The lack of a foreach command is not the only thing that has been bothering me in my quest for C++ code that is easy to follow: The inconsistent switch() { case: ... default: } keywords. Although the C++ language allows you to use operator overloading to perform equivalency checks on two objects, the switch keyword only accepts a type that can be represented as an integer and the case keyword only accepts an integer equivalent to check against. This is highly annoying if, for instance, you're building a command parser and want to check for a number of specific command strings, for instance:
void handleCommand (const string &command)
{
switch (command)
{
case "greet" :
printf ("Hello, world"\n");
break;
case "quit" :
exit (1);
default :
printf ("Error\n");
break;
}
}
The compiler will complain (unless if it's on crack and starts testing against the pointers for the const strings in the case clause). Instead, you will have to do it the tedious way:
void handleCommand (const string &command)
{
if (command == "greet")
{
printf ("Hello, world\n");
}
else if (command == "quit")
{
exit (1);
}
else
{
printf ("Error\n");
}
}
In Grace, you can now meet in the middle using the caseselector, incaseof and defaultcase macros. This is what they currently look like:
#define caseselector(varname) \
for (bool __cflip=true; __cflip; __clip=false) \
for (typeof (varname) &__cref = varname; \
__clip; __clip=false) {
#define incaseof(val) \
} for (; __cflip && __cref == val; __cflip=false) \
switch (true) { case true
#define defaultcase \
} if (! __cflip) break; switch (true) default
So now, in Grace, you can use the following construct:
void handleCommand (const string &command)
{
caseselector (command)
{
incaseof ("greet") :
printf ("Hello, world"\n");
break;
incaseof ("quit") :
exit (1);
defaultcase :
printf ("Error\n");
break;
}
}