Style Case Studies: Construction Unions - Underhanded Names
(Page 7 of 9 )
There’s one mechanical problem I haven’t yet covered. This problem first rears its ugly, unshaven, and unshampooed head in the following line:
enum uniontype {NONE,_INT,_LIST,_STRING};
Never, ever, ever create names that begin with an underscore or contain a double underscore; they’re reserved for your compiler and standard library vendor’s exclusive use so that they have names they can use without tromping on your code. Tromp on their names, and their names might just tromp back on you!
Don’t stop! Keep reading! You might have read that advice before. You might even have read it from me. You might even be tired of it, and yawning, and ready to ignore the rest of this section. If so, this one’s for you, because this advice is not at all theoretical, and it bites and bites hard in this code.
The enum definition line happens to compile on most of the compilers I tried: Borland 5.5, Comeau 4.3.0.1, gcc 2.95.3 / 3.1.1 / 3.4, Intel 7.0, and Microsoft Visual C++ 6.0 through 8.0 (2005) beta. But under two of them—Metrowerks CodeWarrior 8.2 and EDG 3.0.1 used with the Dinkumware 4.0 standard library—the code breaks horribly.
Under Metrowerks CodeWarrior 8, this one line breaks noisily with the first of 52 errors (that’s not a typo). The 225 lines of error messages (again, that’s not a typo) begin with the following diagnostics, which point straight at one of the commas:
### mwcc Compiler:
# File: 36.cpp
# --------------
# 17: enum uniontype {NONE,_INT,_LIST,_STRING};
# Error: ^
# identifier expected
### mwcc Compiler:
# 18: uniontype currtype;
# Error: ^^^^^^^^^
# declaration syntax error
followed by 52 further error messages and 215 more lines. What’s pretty obvious from the second and later errors is that we should ignore them for now because they’re just cascades from the first error—because uniontype was never successfully defined, the rest of the code which uses uniontype extensively will of course break too.
But what’s up with the definition of uniontype? The indicated comma sure looks like it’s in a reasonable place, doesn’t it? There’s an identifier happily sitting in front of it, isn’t there? All becomes clear when we ask the Metrowerks compiler to spit out the preprocessed output… omitting many many lines, here’s what the compiler finally sees:
enum uniontype {NONE,_INT, , };
Aha! That’s not valid C++, and the compiler rightly complains about the third comma because there’s no identifier in front of it.
But what happened to _LIST and _STRING? You guessed it—tromped on and eaten by the ravenously hungry Preprocessor Beast. It just so happens that Metrowerks’ implementation has macros that happily strip away the names _LIST and _STRING, which is perfectly legal and legitimate because it (the implementation) is allowed to own those _Names (as well as other__names).
So Metrowerks’ implementation happens to eat both _LIST and _STRING. That solves that part of the mystery. But what about EDG’s/Dinkumware’s implementations? Judge for yourself:
“1.cpp”, line 17: error: trailing comma is nonstandard
enum uniontype {NONE,_INT,_LIST,_STRING};
^
“1.cpp”, line 58: error: expected an expression
if( currtype==_STRING) {
^
“1.cpp”, line 63: error: expected an expression
currtype=_STRING;
^
“1.cpp”, line 76: error: expected an expression
case _STRING: {
^
4 errors detected in the compilation of “36.cpp”.
This time, even without generating and inspecting a preprocessed version of the file, we can see what’s going on: The compiler is behaving as though the word _STRING just wasn’t there. That’s because it was—you guessed it—tromped on, not to mention thoroughly chewed up and spat out, by the still-peckish Preprocessor Beast.
I hope that this will convince you that when some of us boring writers natter on about not using _Names like__these, the problem is far from theoretical, far more than mere academic tedium. It’s a practical problem indeed, because the naming restriction directly affects your relationship with your compiler and standard library writer. Trespass on their turf, and you might get lucky and remain unscathed; on the other hand, you might not.
The C++ landscape is wide open and clear and lets you write all sorts of wonderful and flexible code and wander in pretty much whatever direction your development heart desires, including that it lets you choose pretty much whatever names you like outside of namespace std. But when it comes to names, C++ also has one big fenced-off grove, surrounded by gleaming barbed wire and signs that say things like “Employees__Only—Must Have Valid _Badge To Enter Here” and “Violators Might be Tromped and Eaten.” This is a stellar example of the tromping one gets for disregarding the _Warnings.
Guideline: Never use “underhanded names”—ones that begin with an underscore or that contain a double underscore. They are reserved for your compiler and standard library implementation.
This chapter is from Exceptional C++ Style, by Herb Sutter (ISBN 0201760428, copyright 2005. All rights reserved. It is reprinted with permission from Addison-Wesley Professional). Check it out at your favorite bookstore today.
Buy this book now. |
Next: Toward a Better Way: boost::any >>
More Code Examples Articles
More By Addison-Wesley/Prentice Hall PTR