The Proposed C++ Standard: Evolution, Revolution, Innovation, Invention, Convolution

Al's scratching his head over what's going on with the proposed C++ standardization.


September 01, 1997
URL:http://www.drdobbs.com/cpp/the-proposed-c-standard-evolution-revolu/184410282

Dr. Dobb's Journal September 1997: The Proposed C++ Standard: Evolution, Revolution, Innovation, Invention, Convolution

Al is a DDJ contributing editor. He can be contacted at [email protected].


We C++ programming writers have been in a quandary for some time now. The problem is rapid language evolution. If you write about the language the way that current compilers support it, your work is obsolete even as you write. If you write about the language the way the committee has defined it, few, if any, contemporary compilers can compile the programs in your work (because virtually no compiler complies with the current proposed standard).

As an author, do I publish code that readers can compile, or do I publish to meet the latest proposed Standard? If readers can't compile the code, then neither, obviously, did I, and the credibility of the work is compromised. On the other hand, if the code conforms to older conventions and thus does not represent bleeding-edge language innovation, the work is likely to be scoffed at by readers and reviewers alike as being about "old-style C++," even "deprecated C++." On the third hand -- if you have a third hand -- the proposed Standard could change by the time my bleeding-edge code is published, and then my code would bleed no more and be obsolete. What to do?

Case in point. Over two years ago, just as P.J. Plauger was about to publish his book, The Draft Standard C++ Library (Prentice Hall, 1995), the committee voted to include Alexander Stepanov's Standard Template Library (STL) of generic container classes. Then, lolling in the afterglow of generic programming, the committee overhauled the rest of the Standard Library with templates that support wide and narrow character versions of the string and iostream classes. Plauger's book, which provided and documented an implementation of the 1994 version of the proposed library, was out-of-date even as it went to the printer. Plauger, who has rewritten his library and licenses it to compiler vendors, is now wisely sitting on a book about STL, waiting for things to settle down.

Library Implementations

If you want to see a reasonably complete version of the proposed Standard C++ Library, given the unsettled nature of the standard activity, check out Visual C++ 5.0. Microsoft licensed Plauger's library, which includes a comprehensive implementation of STL. Plauger's software company, Dinkumware Ltd., can be found at http://www.dinkum.com/.

Alexander Stepanov, who created STL and introduced it to the committee, now works at Silicon Graphics Inc., which has released an enhanced STL with more containers than the proposed Standard STL (based on Stepanov's earlier work at Hewlett-Packard). The SGI version of STL has been ported to several compilers. You can download it from http://www.sgi.com /Technology/STL/. (For more information, see "The SGI Standard Template Library" by Matthew H. Austern, DDJ, August 1997.) With a meeting of the committee scheduled for July 1997, some factions will probably push again to add the SGI containers to the library. That push was made last year, and it was voted down.

Neither STL implementation fully complies with the proposed Standard because no compiler has implemented all the template features that STL requires. Microsoft implements default template arguments and member templates, but its STL does not yet use member templates. None of the compilers has implemented partial specialization.

The "Standard"

I have in hand -- on hard disk, actually -- the December 1996 ANSI/ISO publication titled, "Working Paper for Draft Proposed International Standard for Information Systems -- Programming Language C++," document numbers X3J16/96-0225 (for ANSI) and WG21/N1043 (for ISO). This document is the current proposed Standard. The cover sheet sternly warns us that we may not refer to this document "...as a Standard until approved by an accredited standards body." The First Amendment to the Constitution not having been repealed yet, I wonder how the committee and its overseeing organizations have the authority to enforce that rule. (Unless, of course, some of them exercise their Second Amendment rights and find out where I live.)

The 1996 document was the second draft that the committee has released for public review and comment. The first was the February 1994 draft. Reliable sources have assured me that the 1996 draft represents the Standard C++ language as it is expected to be approved. Yeah, right. Reliable sources assured me that the 1994 draft was technically on the mark, with only editorial changes expected. The drastic technical changes came only a few months later. I called the offices of the ISO/IEC JTC1/SC22 Secretariat and learned that they have received over 300 pages of comments from the public following review of the December 1996 draft. The committee convenes again in July 1997 to consider this abundance of comments. Who knows where it goes from here? (You can download the December 1996 draft document from http://www.setech .com /x3.html in three formats: plain text, which you can view with a text editor; HTML, which requires a web browser to read; and PDF, which requires Adobe Acrobat Reader, which you can also download for free. The document is an insomnia cure. Don't wait for the movie.)

X3J16: Out of Control?

I trust the committee to specify the best C++ possible. I trust them because I know that people like Bjarne, Alexander, and P.J. are careful, intelligent people who have the interests of the language, the library, and the programmers at heart even when they disagree with one another. But some of this innovation gets interesting, to say the least.

The Standard document specifies not only the innovations of the language but identifies traditional language features that the committee "deprecates" because the features are replaced by innovations. The document's Appendix D says:

These are deprecated features, where deprecated is defined as: Normative for the current edition of the Standard, but not guaranteed to be part of the Standard in future revisions.

Come on guys. It's okay to redefine C++, but leave English alone. "Deprecate" means, "To express disapproval of...depreciate, belittle...to ward off by prayer."

Sometimes things just get funny. Sometimes the committee deprecates its own innovations. How so? The committee invents something. Compiler vendors implement the feature. Programmers use the feature and learn about its strengths and weaknesses. The committee, observing the usages, deprecates the weaknesses. For example, the committee invented the bool data type and all its behavior. Now they deprecate the use of auto increment and decrement operators with bool variables. An innovation becomes legacy and is then warded off by prayer.

Then they introduce constructs that not only break existing code but require you to use deprecated practices. The istream:: read and ostream::write functions can be called only with pointers to character arrays. Yet many programmers use these functions to read and write binary data to and from structure buffers, which means that you must use a typecast, a practice that is not formally deprecated but is traditionally disapproved of -- as in "deprecated," Appendix D notwithstanding. Some legacy compilers provide a simple pair of overloaded functions that use void pointers to obviate casts in user code. The proposed Standard definition, therefore, breaks existing code.

The Standard does not include the overloaded read and write functions. istream and ostream are now to be implemented as specialized templates basic_istream<char> and basic_ostream<char>. This approach permits the same template code to be used to specialize wistream and wostream as basic_istream<wchar_t> and basic_ ostream< wchar_t>, which is a good thing, and which, I suppose, permits you to build streaming input/output template instantiations for other types. I suggested that the Standard include the overloaded void* functions. The answer was that they would not do that because the change would break existing code. I am not sure why that would be so.

Many legacy compilers include overloaded istream::read and ostream::write functions with unsigned and signed character pointers, too. Those are not in the Standard for reasons related to the template mechanism now being proposed. More broken code needing more casts.

The Plight of the Kleenex

All this rapid transition is enough to bring tears to my eyes. Mind you, I'm not being critical of the process. I find it interesting and constructive. Eventually, this seeming melee leads to a solid, well-defined Standard. I'm just reacting to the precarious balance that an author maintains in order to write about technology in an era of such widely and wildly shifting technology.

There are three problems: First, an author must also be a developer to stay current not only with the changes, but with their impact -- how well they work and where they might be applied. Author and developer -- two full-time jobs if you do either one properly. Second, the length of time it takes to write and publish a serious work about technology exceeds the time it takes for the technology to make major paradigm shifts. Third, the specification of new technology, about which readers are curious, leads the implementation of that technology by months and, sometimes, years.

No wonder compilers are slow to comply. Compiler vendors are reluctant to implement drastic changes to proposed standards; their substantial development investments can be negated in a single moment by a random, unanticipated vote from the floor.

All this gets forgotten some day when the committee's work is done and all the compilers are compliant and all the books reflect the latest and greatest ways to write code. The problem is today. There is no tradition to tell us what to do. Prior committees wisely chose to only codify existing practice. X3J16/WG21 bravely chose to invent language and standardize the inventions as part of the same effort.

Perhaps, by the time the committee is finished, another language will be at the forefront getting all the attention, and no one will remember. History will no doubt repeat itself with Java.

In the meantime, what do we write about? Should we write about C++ at all? Should we just drop out and wait for the Standard to become approved and implemented?

I can hear the reaction: "Quit whining, Al. You're making a good living from all this chaos." No, that's not my imagination; I can really hear it. It's Judy saying it. She has her eye on some new living room furniture. We need those royalty checks. Every now and then she walks by and mutters, "Paper or plastic?" and "Do you want fries with that?" just to remind me how things could be.

Misery's Company

I'm not the only one. I asked P.J. Plauger about it. He is active on the library subcommittee, has been a victim of this phenomenon, and understands the issue from both sides. He mentioned that another C++ author, Herb Schildt, has a similar concern.

Herb and I both have books titled Teach Yourself C++, and we are both writing new editions. (Just to keep the record straight, mine came first.) You can easily tell them apart. Mine includes a CD-ROM. Herb's publisher is too cheap to give you any digital media with the book, not even a crummy diskette. You have to go to the web to get Herb's code. There is another book called Teach Yourself C++ in 14 Days, or maybe it's ...21 Days. I forget which, but in either case, it's a laughable notion. Most people couldn't learn all of C++ in a year, not even with a Vulcan Mind Meld. Most of the experts are still learning. I suggested that the three authors get together, go on QVC like Joan Rivers, and offer a TYC++ Collector's Edition boxed set, but the publishers failed to see the commercial potential in that idea.

Namespaces

I called Herb to discuss the problem. Turns out we are of a single mind and have wrestled with the problem as it relates to one specific technical issue -- namespaces.

The committee has decreed that all Standard Library functions, classes, and objects are to be shrouded in a namespace named std. They also specified that the header entities that declare the Standard C++ Library classes, functions, and objects have names without extensions, like this:

#include <iostream>

The committee further specified that Standard C functions and headers retain their original file names with no extension and a 'c' prefix like this:

#include <cstdlib>

But, because the C++ Standard includes the C Standard, the C++ Standard specifies that an implementation should also support the original C-style header files, which declare the Standard C functions and global variables in the global namespace, like this:

#include <stdlib.h>

Guess what? The document deprecates the use of the traditional C library headers, which, according to their definition of "deprecate," means that someday the headers might not be supported.

The proposed draft Standard does not acknowledge the old-style C++ headers, which declared everything in the global namespace, and which most compiler vendors still support. Assuming that the current proposed Standard is as golden as my sources insist, it will be possible for a vendor to release a fully compliant compiler that does not compile any of the millions of lines of legacy code in use today. No vendor in its right mind would do that, but some notable compiler vendors have been known to take leave of their senses in the past.

So, for whatever reason, the C++ committee has paid deprecated homage to all that legacy C code and completely ignored all that legacy C++ code.

Listing One is a traditional C++ program that most legacy and all 1996-compliant compilers (of which there are none) would compile. All the C++ books in my bookcase, including some fairly recent ones, use this style of code. However, if a brand new book uses this style of code, that book gets labeled "old fashioned" before it goes out the door. Furthermore, it uses header files that are either not in the Standard or are deprecated. The code might not work in next year's compilers.

Current compilers support the style of code that Listing One uses because, even if they wrap everything in the std namespace, they still support the legacy C and C++ header files. Listings Two and Three show how they might typically do this.

Listing Four is a fully compliant (with the current proposed Standard) C++ program that a legacy C++ compiler would not compile but that a compliant C++ compiler -- if one was available -- would compile. Herb and I have been told by reputable authority that this is how C++ programmers should be taught to program. Listing Four is politically correct. I am not ready, however, to tell a generation of established C and C++ programmers that they have to prefix everything with the std:: qualifier when before they did not. I agree that this usage is safer at least as far as the C++ stuff goes. The usage helps to ensure that a program is portable no matter what external and file scope identifiers the programmer and the library use. I am not so sure that Standard C functions need to be in a Standard C++ namespace. The C language has no concept of namespaces. In any event, Listing Four will not compile on the latest Borland, GNU, or Microsoft C++ compilers. The compilers have not implemented libraries with all the standard stuff in the std namespace.

There are two factions on the committee who disagree about some of this namespace behavior. One faction wants to leave the Standard C functions out of the std namespace, which would change the proposed Standard and make Listing Four incorrect. The other faction wants all standard components to remain in the std namespace as the 1996 draft specifies. Complying with that Standard requires major changes to the C header files to accommodate the namespace issue, which demands changes to C headers to support C++ requirements. Some heavy hitters in the compiler vendor world have flatly refused to make these changes, and the issue is hotly contested and still unresolved.

Visual C++ 5.0: A Partial Implementation

Microsoft Visual C++ 5.0 implements the Standard C++ Library in the std namespace, but, although it uses all the new header file formats, it does not implement the Standard C Libraries in the std namespace. Consequently, Listing Four does not compile because the compiler complains that rand and strcpy are not in the std namespace. Guess which of the two namespace camps Microsoft belongs to.

Be wary of Visual C++ 5.0. If you include <iostream>, you get the new code wherein istream and ostream are implemented as specialized templates basic_ istream<char> and basic_ostream <char>. If you include <iostream.h>, you get the old code wherein istream and ostream are implemented as conventional classes. A system that uses new code conventions in programs that call legacy libraries will run into difficulty. Consider Listing Five, two source code files that should compile independently and link into an executable program. They do not link, however, because the two modules have completely different versions of the ofstream class, name-mangled differently, and, therefore, different classes, different objects. This is not a mistake. Microsoft did this on purpose to permit an orderly transition from the old to the new.

For now, you should use the old stuff, in my opinion. P.J. Plauger, who authored Microsoft's library, suggests that you not rush into using the new iostream libraries if you already have programs that work with the old libraries. There are significant conversion implications as Listing Five illustrates. The new implementations are close but not fully operational. The program in Listing Six does not compile with VC++ 5.0, and it should. The compiler rejects the overloaded << operator as being ambiguous. Change <fstream> to <fstream.h>, remove the using declaration, and the code compiles okay.

Compromise

Listing Seven is Herb's and my compromise for the current editions of our books with the same name. We arrived at this compromise independently and later were happy to validate each other's conclusions. We evince current technology by using the standard header #include notation. We are, up to this point, politically correct. We then subvert the good intentions of the committee by using the using namespace std; declaration, which, in a daring and cavalier move, effectively puts back into the global namespace everything that the headers conservatively and conscientiously put into the std namespace. But, all is not for naught; as a side benefit, we have code that endures irrespective of the outcome of the great C header namespace debate.

What, then, if the reader wants to use a legacy compiler? Herb has to deal with that problem because Herb's book offers only the source code, and then only for downloaders. I solved the problem by including Quincy 97 and the gnu-win32 port of the GNU compiler on the CD-ROM. My readers get not only source code, but a 32-bit Windows 95 C++ compiler as well. Eat your heart out, Herb. The GNU compiler does not support the std namespace, but it supports the namespace feature syntax, which the compiler parses and passes but which has no effect on the program. My code looks compliant even if the compiler is not. But if I had to deal with the problem of readers with legacy compilers, I would supply simulated Standard C++ header files like the one in Listing Eight.

Such compromises in code examples are good, particularly when the compromises avoid conflict, teach properly, keep me working, and keep those royalty checks rolling in so that Judy's life continues in the manner to which she is accustomed.


Listing One

#include <iostream.h>#include <string.h>
#include <stdlib.h>


int main() { char msg[25]; strcpy(msg, "The random number is: "); cout << msg << rand() << endl; return 0; }

Back to Article

Listing Two

#ifndef _IOSTREAM#define _IOSTREAM
namespace std  {
    #include <iostream.h>
}
#endif

Back to Article

Listing Three

#ifndef _CSTDLIB#define _CSTDLIB
namespace std  {
    #include <stdlib.h>
}
#endif

Back to Article

Listing Four

#include <iostream>#include <cstring>
#include <cstdlib>


int main() { char msg[25]; std::strcpy(msg, "The random number is: "); std::cout << msg << std::rand() << std::endl; return 0; }

Back to Article

Listing Five

// ------- main.cpp#include <fstream>
using namespace std;


void foo(ofstream& ofile);

int main() { ofstream ofile("test.txt"); foo(ofile); return 0; } // ------- foo.cpp #include <fstream.h>

void foo(ofstream& ofile) { ofile << "Hello Dolly"; }

Back to Article

Listing Six

#include <fstream>using namespace std;


void foo(ofstream& ofile) { ofile << "Hello Dolly"; }

Back to Article

Listing Seven

#include <iostream>#include <cstring>
#include <cstdlib>
using namespace std;


int main() { char msg[25]; strcpy(msg, "The random number is: "); cout << msg << rand() << endl; return 0; }

Back to Article

Listing Eight

#ifndef _IOSTREAM#define _IOSTREAM
    #include <iostream.h>
    #ifndef using
        #define using     /* */
        #define namespace /* */
        #define std       /* */
    #endif
#endif

Back to Article

DDJ


Copyright © 1997, Dr. Dobb's Journal

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.