The Rise and Fall of C++0x Concepts

hat were you doing during the morning hours (EST) of July 13th 2009? On that auspicious day, in a dramatic vote, the C++ standards committee decided to remove concepts from C++0x. Undoubtedly, this resolution will have a huge impact on C++. In this column I will outline the causes of concepts’ failure, discuss the lessons from this unprecedented event, and try to predict how it will affect the future of C++.

Immaculate Concepts

The main impetus for adding concepts to C++ was to allow template designers to precisely specify requirements and constraints on and among types. The problem was how to design a constraints mini-language that would be simple and intuitive on the one hand, and complete and efficient on the other hand. To demonstrate the problem that concepts were supposed to solve, consider the function template min(). It imposes certain implicit requirements on the type T:

templateconst T& min(const T& x, const T& y) {  return x < y? x : y;}

T must be a type that has a less-than operator (<) to compare two values of type T, and the result of which must be convertible to a Boolean value. In C++03 it's difficult to express these requirements in a clear and bullet-proof manner. Bjarne Stroustrup and Gabriel Do Reis presented the first concepts paper in 2003 (other committee members contributed to this endeavor later). At first, it seemed as if concepts ticked the right boxes. Here's a modified min() function that uses concepts to express the constraints on T:

concept LessThanComparable {  bool operator<(const T& x, const T& y);}templaterequires LessThanComparableconst T& min(const T& x, const T& y) {  return x < y? x : y;}
Author's Note: The examples are quoted from Douglas Gregor's excellent introduction to concepts.

If C++ templates had to deal only with simple cases like min(), the design of concepts would be a cinch. However, the C++ Standard Library consists of far more complex templates?containers that impose certain requirements on their elements, smart pointers with peculiar ownership semantics, algorithms that must meet certain performance limits, various categories of iterators?you name it. That is why the authors have been refining the concepts specification for more than seven years.

After several iterations, the concepts proposal forked off in two different directions (the technical differences between the two proposals will not be discussed here). A compromise was reached at the October 2005 meeting in Mont-Tremblant, Canada; the two competing proposals would be merged into an integrated concepts proposal known as the "Mont-Tremblant compromise."

Off the record, some committee members viewed the Mont-Tremblant compromise as the watershed?the integrated concepts proposal had simply turned into an incoherent monster. Debates about whether the imminent C++ standard should include a conceptualized Standard Library heated up. While some of the problems with concepts were resolved promptly, each new day led to the discovery of additional problems and disagreements. With serious efforts, the committee managed to approve the C++0x Committee Draft (which included concepts) in September 2008. However, in recent months, the criticism and doubts concerning concepts reached a boiling point. The last straw was probably Stroustrup's latest concepts paper, which added more fears and doubts. The concepts-related threads on the committee's reflectors (list servers) pointed out that concepts were "untried, risky, incomplete and controversial." Concerns about compile-time and runtime overhead were also voiced. As the Frankfurt meeting got closer, these voices became harsher and louder.

Two Tough Choices

The distrust and antipathy toward concepts paved the way to voting this feature out of C++0x. There was one huge problem with this decision though: concepts were already pervasive in the Committee Draft (CD). Almost every paragraph and code listing involving templates uses concepts directly or indirectly. Worse yet, many new features that have been accepted into C++0x in recent years presuppose concepts. Removing concepts from the standard will require a massive excision operation that might kill the patient. But what other choices did the committee have?

Leaving concepts in situ wasn't a better choice. Even the authors agree that the current concepts specification isn't complete, and that perfecting it would take "several more years." However, they consider the current proposal "good enough for now." Furthermore, they insist that the outward complexity of concepts is misleading?the underlying model is "good enough;" it's only the surface complexity (what the user has to write) that needs fixing. Considering that concepts have already taken seven years of precious committee time, no one was willing to spend five more years or so on refining the surface complexity, or indeed any other concepts complexity. The cruel choice was thus between a painful excision, and asymptotic refinement of concepts. On the afternoon of July 13th the die was cast: Concepts were voted out of C++0x by a decisive margin.

An Unprecedented Event

Unlike other self-contained features that usually have no huge impact on C++ as a whole (nullptr for example), the removal of concepts amounts to a landslide, and will probably lead to a witch hunt. Committee members and the C++ community will want answers. It appears that the committee's limited resources were wasted on a feature that failed, while at the same time, other critical C++0x features such as multithreading and garbage collection didn't get enough attention.

As far as I can remember, this fiasco is unprecedented. I've been following the C++ standardization process closely since the early 1990s and witnessed all sorts of things, such as features that were radically revised just a couple of days before finalization of the standard, and ghost features that made into the standard even though few people understood what they were good for?only to be deprecated years later (examples are exception specifications, and vector). We even had exported templates in C++98, a feature that (except for Comeau, some eight years later) no compiler vendor has ever bothered to implement. And yet, nothing prepared us for the removal of a feature that was already in the Committee Draft, and that was considered as the most important addition to C++ in years. Why did concepts go wrong?

Standardizing Existing Practice

Generally, the standards committee is best at standardizing existing practice, that is, wordsmithing features that some compiler vendor has already implemented independently. For example, consider thread-local storage. The committee based this proposal on a similar non-standard extension that several vendors had been offering voluntarily for years. Hashed containers (called unordered containers in C++03) were also based on previous non-standard extensions of various vendors. By contrast, concepts were designed ex-nihilo, and were never tested in real-world projects outside the committee's sandbox.

Concepts Didn't Eliminate Template Complexity

Concepts didn't live up to their promise. They were supposed to make template programming and usage easier. Instead, they transferred the complexities from templates into concept maps and axioms. Pedagogically, concepts were a disaster. There's no way that Joe Coder would ever master such a huge, confusing and unintuitive set of rules and constructs.

No Deadline

Concepts took seven years to design, without reaching satisfactory results. It might have been a good idea to reconsider the whole idea after a certain time limit. How many software projects go on forever without a clear deadline? How many years should a new feature take to design?

What Next?

At this stage, no one really knows how difficult (and dangerous) the removal of concepts will be. Rewriting every piece of code and sentence that refer to concepts will be a painstaking process. Yet the main problem here isn't just editorial. In the past five years C++0x has pretended that concepts are a done deal. Therefore, every phrase in "conceptese" will have to be rephrased in plain English. To illustrate the extent of this problem, consider article 30.3.1/3 of the CD:

"A Mutex type shall be DefaultConstructible and Destructible. [?] A Mutex type shall not be copyable nor movable."

These two sentences alone reference four different concepts! And the CD contains 1,340 pages of text, charts and code.

The removal of concepts leads C++ developers back to square one. The same problems that have been troubling C++ users and library designers for years are back with a vengeance. Presently, there's no real alternative to concepts. We'll simply have to make do with C++03-style hacks and improvisations such as SFINAE and type traits. Although the authors are free to refine concepts or redesign it from scratch, don't hold your breath. That could take years?and I doubt that committee members will risk a second fiasco.

The removal of concepts was probably the right choice, no matter how painful it will prove to be. However, I suspect that it will haunt the C++ community for many years to come.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Related Posts