Important Shock

A Deeply Skeptical Look at C++0x

Today I saw a link to an article entitled C++ Gets an Overhaul on Hacker News detailing C++0x, the proposed set of standards for the new generation of C++. Working on Half-Life 2 mods and a DirectX game in C++ left me with the impression that C++ was complicated, ugly, bloated and inexpressive. and I was eager to see if these latest changes – other than garbage collection, about which I had already heard – would bring a much-needed dose of simplicity and ease-of-use to C++. Alas, it was not to be. As I read the article, I became so incensed with the sheer stupidity of some of the changes being introduced that I began mocking them out loud. In an attempt to preserve these witticisms for posterity, I will juxtapose extracts from this article and my thoughts.

Introduction

Ten years after the ratification of the first ISO C++ standard, C++ is heading for no less than a revolution.

Seriously, though, a revolution? The sort of revolution in which average people are freed from unjust laws, or the sort in which average people are crushed under infighting among the elite? Or is it the sort in which everyone’s head gets chopped off?

C++0x, the new C++ standard due in 2009, brings a new spirit and new flesh into the software development world.

How the hell do you pronounce ‘C++0x’ anyway? I’ve got a few ideas:

I think I’ll go with the last one.

Brace yourself for state-of-the-art design idioms, even better performance, and a plethora of new features such as multithreading, concepts, hash table, rvalue references, smarter smart pointers, and new algorithms.

Sweet crouching Jesus! Brace yourselves! Hash tables? Multithreading? Truly, the future has arrived, and it’s going to kick your ass.

No doubt you’ll find a lot to like in C++0x!

Replace “like” with “mock” and you have yourself a true statement, sir.

New Core Features

The two most important features of C++0x are concepts and concurrency support. Concepts enable programmers to specify constraints on template parameters, thus making generic programming and design immensely simpler and more reliable.

Go on, try to think of a worse or more ambiguous name for a proposed language addition than ‘concepts’. No luck? Me neither.

Variadic templates, template aliases (also called template typedefs), and static_assert—though not directly related to concepts—will also make the use of templates in generic libraries more intuitive, flexible, and less error prone.

Please, please don’t add language features just to make the lives of library designers easier. Add features to make the average programmer’s life easier.

The importance of a standardized concurrency API in C++ can’t be overstated

Technically, it could; I could say “a standardized concurrency API in C++ will end world hunger”. But to step away from relentlessly mocking hoary clichés, I’d like to point out that compiled imperative languages like C++ are the absolute worst languages in which to do multithreading. The whole model of imperative programming is based around the introduction of changes in state – and when the state is being modified by hundreds of concurrent processes, your previously-bug-free program becomes nondeterministic. Multithreading is really, really hard for a vast array of reasons. Some of the smartest people in the world are trying to figure out how to make programming languages play nice with multiple cores now that Moore’s Law is on its way out, and there’s a reason that they’re using Haskell or inventing new languages rather than pretending that yet another layer on the tower of hacks that is C++ will fix the problem.

As multicore processors are becoming widespread, you simply can’t afford to remain stuck in the single-threaded era, or compromise on platform-dependent APIs. At last, there’s a portable, standardized and efficient multithreading library for C++.

There is very little that about C++ that can be described as “portable” – just ask the Firefox team. Even changing compilers from g++ to Visual C++ involves working through a host of cross-compiler flaws and incompatibilities, and actually porting across operating systems – or, God forbid, architectures – involves more #ifdef’s than you can shake a proprocessor at. (Whether a compiled language can be considered to be portable at all is another matter entirely.) Deep in your heart, you know that you’re going to have to make a lot of changes to make sure that your program compiles across architectures and OS’s – why not recognize this fact and use each target OS’s most powerful threading API?

Rvalue references are yet another silent revolution. While most users will probably not even know they exist (read my interview with Bjarne Stroustrup), rvalue references enable library designers to optimize containers and algorithms by implementing move semantics and perfect forwarding easily, thus reducing unneeded copy operations.

I have to force myself not to write this in as sarcastic a manner as possible, and this is the sort of statement that doesn’t help. C++ doesn’t need any more optimization, because it’s plenty fast already. The reason that Java beat C++ in the 90’s wasn’t because Java had features that C++ didn’t, it was because Java and Sun were willing to take a small performance hit in exchange for happier programmers, more readable code and cleaner algorithms. Silent revolutions won’t help C++; the only thing that can really save its life now is to remove features from the language. Yes, users will bitch and moan, but they do that anyway. Don’t let your language linger and die while it tries to bear the burden of backwards comaptibility.

Automatic type deduction is made possible by the new keywords auto and decltype which deduce the type of an object from its initializer and capture the type of an expression without having to spell it out, respectively.

Wow, uh, that’s actually exactly what C++ needed. Someone is listening to me!

Adding auto and decltype also paves the way for a new function declaration syntax. The function’s return type appears after the -> sign:
auto func(int x)->double {return pow(x);}

There are so many things wrong with this that I barely know where to start. The arrow? The fact that in contravention of who-knows-how-many-years of tradition, return type is going after the function and parameter names? The fact that though auto supposedly deduces that this is a function, it can’t figure out that this function would return a double, forcing the programmer to give two seemingly contradictory types?

Lambda expressions and closures are another prominent feature of C++0x. A lambda expression is a nameless function defined at > the place where it’s called. It is similar to a function object except that the programmer is rid of the burden of declaring a class with a constructor, defining an overloaded () operator and an instantiating a temporary object of that class—this tedium now becomes the compiler’s job. Here’s an example of a lambda expression:
//a lambda expression is used as an argument
myfunc([]\(int x, int y) -> int {return x+y;}

The lambda expression is indicated by the lambda introducer [] followed by a parameter list in parentheses. The optional return type comes next, following the -> sign. Finally, the lambda block itself is enclosed in braces.

Oh, man. Instead of the square brackets to introduce an anonymous function, why not use syntax that is a) meaningful and b) not used everywhere else? Off the top of my head, square brackets perform array declaration, array initialization, and are overloadable operators – why use them to declare anonymous functions as well? Why not take a cue from Python and use an actual keyword?

myfunc(lambda: (int x, int y) -> int {return x+y;} )

Clearer, no? What about function? Anything except this. How do we even tell where the anonymous function ends and the other arguments begin?

Other Additions

Some C++0x features are meant to simplify recurring programming tasks and minimize boilerplate code. Most of these “convenience features” were borrowed from other programming languages.

Maybe they’re recognizing that boilerplate code is a Bad Thing. Perhaps we’re getting typesafe macros? Better syntax for function pointers?

These convenience features include a null pointer literal called nullptr

We have a null pointer literal. It’s called NULL. It’s in C. Honestly.

C++0x enhances compatibility with other independent International Standards. The first set of additions is designed to bring the C++ in closer agreement with the ISO/IEC 9899:1999 Standard C (C99 for short).

Well, better a decade late than never, I guess.

The influence of the recent Unicode 4.0 standard is also reflected in C++0x. C++98 defines a wide char type called wchar_t, that has an implementation-defined size. In the mid-1990s, it was assumed that wchar_t would be sufficient for supporting Unicode but this turned out to be a false hope. The unspecified size of wchar_t prohibits portable UTF encoding in C++98. C++0x solves this problem by introducing two new character types with standardized sizes: char16_t and char32_t that are specifically designed to support portably all the Unicode 4.0 codesets and encoding schemes (UTF8, UTF16 and UTF32).

No, God Damnit. In introducing yet another character type, C++0x just made the problem worse. Now a newbie has to Google his way through forests of documentation and reports just to find out which character type to use. Considering that very few people have the know-how to use wchar_t anyway, why not simply redefine wchar_t to use UTF8? If your “solution” involves introducing two new character types into a language already fraught with unnecessary typedef’s, it’s not a solution. Period.

Some support for Unicode strings in its Standard Library will be available too.

Excuse me? If you’re going to introduce an entirely new character type, then you’d better provide C++ programmers with a coherent reason to switch beyond “because we said so.” The lure of a Unicode-embracing standard library would do much to spur adoption of these char_16t and char_32t types, harebrained though they may be; considering that strings are possibly the most fragile thing in C++, thanks to a million competing implementations, I sure as hell wouldn’t switch my already-working code to use a new character type if I wasn’t provided with a comprehensive set of reliable and fast string manipulation libraries.

A new library for manipulating regular expressions is defined in the C++0x header. Regular expression support has been noticeably lacking in C++—especially among web programmers, designers of XML parsers, and other text-processing applications.

There’s a reason for that, and it’s because scripting languages do regular expressions better than compiled languages. Continually tweaking a regular expression to capture just the right amount of information gets very tiresome when you have to wait ten seconds for your latest code to build, rather than having Perl or Ruby interpret your code for you.

C++ is my forefathers’ language, the language of the 80’s, the language of enormous videogames, segmentation faults, bluescreens, and linker errors. The programmers of my generation want to work in languages that teach us how to love our own potential before we have to hate others’ restrictions. C++0x makes no effort to step in this direction, and it truly saddens me that future generations of programmers will be taught in this language.