分 The else switch C/C++ idiom
In C and derived programming languages, break keyword is overloaded.
It’s used to break out of loops and switch (multi-way branch).
This means that you can’t break out of a loop while in a multi-way
branch, just in a simple binary branch (if/else). But there’s a
nice, yet largely unknown, goto-less idiom to circumvent that.
Breakout
It’s a well known quirk of C syntax, but to illustrate, say you’re looking for end of line while doing some parsing:
while (!done) {
c = fgetc(f);
switch (c) {
case '(':
...
break;
...
case '\n':
done = false; // need the flag, because
break; // only breaks out of switch
}
// here be dragons, not to be executed on end-of-line
if (!done) {
...
}
}
As you can see, we need to “jump through hoops” because of this
quirk. Not to mention that one might forget the quirk and think
that break in switch would actually break out of the loop.
The usual way to overcome this is to use goto:
for () {
c = fgetc(f);
switch (c) {
case '(':
...
break;
case '\n':
goto done;
}
// here be dragons, not to be executed on end-of-line
...
}
// <--- creepy place
done:
There are many bad things about goto. One of them is that during
maintenance, some code might creep in between the end of the loop and
the label, with unwanted consequences.
There are also various macro based tricks, which we won’t even show here.
else switch to the rescue
It’s best just to show it:
for (;;) {
c = fgetc(f);
if ('\n' == c) {
break;
}
else switch (c) {
case '(':
...
break;
}
}
We’re exploiting another quirk of the C syntax - after else comes
just any code to be executed, so it might as well be a switch, and
there’s nothing stopping us from switch-ing on the same value.
This avoids issues with goto or some crazy macro. It also looks
quite “C natural”, once you get the hang of it.
In C++ it can be a little nicer:
for (;;) {
if (auto c = fgetc(f); '\n' == c) {
break;
}
else switch (c) {
case '(':
...
break;
}
}
It’s also a great idiom to use to persuade people to avoid using
throw/catch for such things.
Your coding standards may say that the “body” of the else has to
be enclosed in braces. Burn them. Standards and braces.
Yes, it’s great, but don’t over-do it
There’s at least one legitimate reason not to use this idiom.
Performance. If on a very hot path, this separate handling of one (or
few) values outside of the switch might have measurable negative
effect on performance. Measure, if goto performance gain is
important in your case, go for it.
Device
I haven’t seen this idiom in the wild before I stumbled upon it while refactoring some of my code and had an “hey, that actually looks ok, solves a problem and gets the point across nicely” moment.
In the tradition of calling C switch tricks “devices”, and until
somebody shows cause that it shouldn’t be named that way, I dub this
“Srdjan’s device”.
Moral of the story
Thinking outside of the box (or a Coding Standard) might lead you to interesting/elegant, if unorthodox, solutions. It’s just code, experiment and see what works well; if it doesn’t work out, just throw the code away.
