I like C++. There, I said it. And I swear I won’t qualify that declaration for at least three paragraphs.
After eight years of work, the C++ Standards Committee recently voted the C++0x standard forward to formal adoption voting. The “0x” appellation was ironically adopted as a nod to the glacial pace of standards committees in general and legacy programming language committees in particular.
Unlike many standards, the C and C++ languages are widely produced; there are literally hundreds of C and C++ compilers (although many at this point use the same components and libraries), and it is claimed that the amount of C and C++ “in the wild” approaches a billion lines of code. One can be certain that somewhere in that vast body of code, there are critical routines that rely on every subtlety of the previous standards, that every “MAY” is routinely ignored, that the most arcane combinations of “MUST” are relied upon, and, just to be fun, vast swaths of the code rely on “undefined behavior” continuing in the way it did before (the committee MAY make a breaking change to a widely implemented “undefined behavior,” but it is hesitant to do so).
The task of a language standards committee is like the task of writing the season finale for a multiyear supernatural drama, like “Lost” or “The X-Files.” The legacy of past years has to be incorporated (even if, in retrospect, it was just a plain-and-simple mistake) while moving the plot forward in a major way.
For C and C++, the task of dealing with the legacy is made vastly harder by such things as the preprocessor, strings, the memory model and, above all, security. The preprocessor is now used for sophisticated code generation; strings must be treated both as just null-terminated strips of 8-bit integers and Unicode-based typesafe objects; the standard memory model must make sense on virtually any conceivable chip; and the language standard has to do what it can to mitigate the multibillion-dollar problem of buffer-overflow attacks.
That’s just the legacy: moving the plot forward requires that C++ be kept at the top of the list as a language that can be used to program systems in the most high-performing way. No one has been more vocal about the ending of the performance-improving “free lunch” of Moore’s Law than Microsoft’s Herb Sutter, who is the Secretary of the C++ committee. I’ll admit that I hoped that C++0x had gone further with its support for concurrency, but no honest analyst can claim that the path forward is clear.
C++0x specifies both a memory model with explicit thread-access guarantees (an important base for STM development), and a thread library with “lazy futures and promises” that, while less ambitious than Sutter’s Concur project or C++ AMP (another Microsoft project, presented by Sutter in June 2011), seems to provide an adequate foundation for exploring large “shared-nothing” message-passing schemes.
The most visible syntax change in C++0x is likely the addition of lambda functions and closures, the anonymous inline functions that have become familiar to C# programmers. Those who wish to point out that there’s nothing new under the sun can say that function objects and pointers are longstanding capabilities that are equally capable. But in moderation, lambdas do clean up syntax.
Given that C++ is so wildly successful, why is it so unpopular? For one thing, the development community is decidedly fickle in its enthusiasms: the cool language is Teh Greatest Evah and last year’s model is Totally Lame. (One day the bloom will be off the Ruby rose, just you wait.)
For another, the sheer weight of a high-level application is apparent in C++; you explicitly bring in the headers and link in the libraries rather than hide all the megabytes in an easy-to-ignore infrastructure.
But most importantly, there’s no such thing as a “typical” C++ codebase. The differences between individual programmers are more easily spotted in a C++ application than in any other language in which I’ve worked; at an extreme, I’ve seen systems where one fellow routinely wrote mind-twisting template meta-programs, while another fellow stubbornly was writing code from the 8-bit era (loop counters marked as “register,” which I think most modern compilers outright ignore). This actually provides a nice opportunity for what John Cook, writing on his blog, calls “Top” and “Bottom” C++: local conventions that certain language facilities are “high level” and can be used at any time, and that other, lower-level facilities require more vetting and stricter code review and so forth.
Unfortunately, this is a good idea that I’ve never seen carried out. Instead, you have confusing codebases where language features come and go seemingly at random, with all the complexities and minor ramifications piling up. So critics can point at those codebases and say, “Look, another messy and complicated C++ codebase.” Also, of course, it’s in the nature of C++ that it often targets low-level performance, and people conflate the sausage guts of the domain solution with an “ugliness” of the language.
As I discussed in my previous column, Microsoft’s initial discussion of Windows 8 programming offered JavaScript and HTML on the one hand and C++ on the other, but it seems to me that there is still a gap between the two programming models. One still needs, I think, the CLR and languages like C#, VB, and F#. But when it comes to performance and native fit-and-finish, C++ is still the king.
Larry O’Brien is a technology consultant, analyst and writer. Read his blog at www.knowing.net.