When Gabriel Dos Reis and Bjarne Stroustrup first introduced C++ concepts, they did so in the hope of making the C++ template facility more expressive (Specifying C++ Concepts [PDF file]):
We consider the problem of how to express concepts in a precise way that is simple enough to be usable by ordinary programmers. In doing so, we expose a few weakness of the current specification of the C++ standard library and suggest a far more precise and complete specification. We also present a systematic way of translating our proposed concept definitions,
based on use-patterns rather than function signatures, into constraint sets that can serve as convenient basis for concept checking in a compiler.
Concepts received a fair amount of attention in the intervening years, with the expectation that they would eventually be included in the C++0x standard. This week, however, the C++ standards committee voted against including Concepts in the core language. In a recent article, The Removal of Concepts From C++0x, Danny Kalev speculates about the reasons for this rejection and what the future may hold for Concepts, or a similar idea, in C++:
Concepts were supposed to be the most important addition to core C++ since 1998. Tremendous efforts and discussions were dedicated to Concepts in every committee meeting during the past five years. After dozens of official papers, tutorials and articles -- all of which were dedicated to presenting and evangelizing Concepts -- it seemed very unlikely that just before the finishing line, Concepts would be dropped in a dramatic voting.
Kalev summarizes the significance of Concepts as follows:
Concepts introduce a type system for templates, enabling you to specify template constraints clearly and intuitively, while improving the compiler’s capability to detect and diagnose violations of these constraints...
Concepts rely on the notion of separate type checking for templates. Template declarations are augmented with a set of constraints. When a template is instantiated, the compiler checks that the instantiation meets all of the constraints, or requirements, of the said template. If all is well, the template is instantiated successfully. Otherwise, a compilation error stating which constraints(s) were violated is issued.
In his article, Kalev speculates that both the Concepts proposal, as well as relative lack of practical experience with Concepts, led to its rejection:
Committee members claimed that it was too early to adopt such a radical change to the Standard Library without real world experience. Apart from that, there were still too many unresolved issues. As a compromise, the committee decided to pursue the refinement of Concepts while leaving the Standard Library unconceptualized for the time being. This was an ominous sign -- if the committee is wary of conceptualizing the Standard Library, why should Joe Code trust Concepts? (...)
A total overhaul of Concepts is one possibility, however unlikely. This could take up to five years and no one is certain that the redesigned Concepts will not have introduced other problems. A second approach is to leave the door open for a drastically reduced and diluted Concepts proposal. The third approach is to refine the current Concepts proposal further, knowing that it will not be integrated into C++0x. I'm willing to bet on the following -- Concepts are dead for good.
What do you think about C++ Concepts, and what is your take on the committee's rejection of Concepts from the upcoming standard?
One of the reasons concepts was introduced was because they couldn't figure out how to make template error reporting better.
Concepts are not required for error reporting. The code inside a template implicitly contains the concepts required by the template types. Currently, compilers report the template errors from inside out, i.e. they report the innermost error first, and the outermost last, while it should have been the other way around.
Take the following piece of code, for example:
#include <vector>
class Foo { };
template <class T> const T &max(const T &a, const T &b) { return a > b ? a : b; }
template <class T> class SortedVector { public: void insert(const T &a) { for(std::vector<T>::iterator it = m_data.begin(); it != m_data.end(); ++it) { const T &b = *it; if (&max(a, b) == &b) { m_data.insert(it, a); break; } } }
1>e:\temp\test_mod\main.cpp(9) : error C2676: binary '>' : 'const Foo' does not define this operator or a conversion to a type acceptable to the predefined operator 1> e:\temp\test_mod\main.cpp(18) : see reference to function template instantiation 'const T &max<T>(const T &,const T &)' being compiled 1> with 1> [ 1> T=Foo 1> ] 1> e:\temp\test_mod\main.cpp(15) : while compiling class template member function 'void SortedVector<T>::insert(const T &)' 1> with 1> [ 1> T=Foo 1> ] 1> e:\temp\test_mod\main.cpp(31) : see reference to class template instantiation 'SortedVector<T>' being compiled 1> with 1> [ 1> T=Foo 1> ]
If the templates are deeply nested, this type of error message becomes incomprehensible.
The error message could have been:
1> e:\temp\test_mod\main.cpp(31) : SortedVector<Foo> can not be compiled because Foo does not implement the operator >. Details: 1> e:\temp\test_mod\main.cpp(15) : while compiling class template member function 'void SortedVector<T>::insert(const T &)' 1> e:\temp\test_mod\main.cpp(9) : while compiling template function 'const T &max(const T &a, const T &b)'
@Danny Kalev @How will C++0x programming and design look like without Concepts? Brace yourself for many more years of indecipherable template compilation errors. Additionally, type traits will become a hot commodity once again. Presently, type traits are one of the very few proven techniques for enforcing compile-time constraints on templates. Pedagogically, C++ will be a tad easier to teach.
But type traits should also significantly improve error message quality.
Concepts were never one of my favorite C++0x features. Sure, they would make possible to have better compiler errors, but it is not such a big deal. In fact I am pleasantly surprised to see the comitee make such a hard and brave decision this late in the process - they probably learned from the past (export and auto_ptr).
The important thing is that rvalue references are remaining. This is the most significant feature of the new standard, and some compilers are already implementing it.
No. Concepts would be great, but for most users, the presence or absence of concepts will make no difference to their experience with C++0x except for quality of error messages (see below).
More evidence towards concepts' primary reason for existence being template error messages.
I wonder why they don't simply fix the error messages.
> I wonder why they don't simply fix the error messages.
Without a way to specify a template's requirements, how can the compiler tell you if you failed to meet those requirements when instantiating the template?
Templates in C++ today have implied requirements, and there is no way to state the requirements in the source (only in documentation). Concepts provide a way to state them in the language, so you can say "this algorithm requires BidirectionalIterators" and if you use it with a weaker category of iterator, the compiler can give a clear message like "InputIterator used where BidirectionalIterator required". Today you get errors like "no matching function for call to operator--" and there's no good way to improve on that.
> > I wonder why they don't simply fix the error messages. > > Without a way to specify a template's requirements, how > can the compiler tell you if you failed to meet those > requirements when instantiating the template? > > Templates in C++ today have implied requirements, and > there is no way to state the requirements in the source > (only in documentation). Concepts provide a way to state > them in the language, so you can say "this algorithm > requires BidirectionalIterators" and if you use it with a > weaker category of iterator, the compiler can give a clear > message like "InputIterator used where > BidirectionalIterator required". Today you get errors > like "no matching function for call to operator--" and > there's no good way to improve on that.
I posted an example above on how it could be done.
If you look carefully at the template error messages, you will see that the compiler knows everything required to output an error message like as if concepts were available. More specifically, the compiler knows:
1) the place in the code that instantiated the template. 2) the types involved in all templates.
Therefore, whenever a deeply nested template error is encountered, the compiler could simply report that type X does not implement feature Y required by template Z.
Concepts should allow a diagnostic such as "SortedVector<Foo> requires Foo to model the LesThanComparable concept" to be given in main(), rather than a few levels down in a specific member function. That would be one line of error output, not three or more.
Flat View: This topic has 19 replies
on 2 pages
[
12
|
»
]