C++0x, the next Standard C++, will support "concepts", whose chief benefit is to allow library
writers to make the compiler produce comprehensible error messages for library usage errors.
Therefore, this problem is temporary.
Posted Jun 18, 2008 22:03 UTC (Wed) by ajross (subscriber, #4563)
[Link]
This is a joke, right? The solution to "this language's error messages suck" is "make it the
library author's job to fix it". I await such a feature with baited breath. Truly, this will
revolutionize programming. Just think about how we've all been suffering in modern languages
with their readable and non-configurable errors! Woe!
Pathetic. I'm sorry, but C++ has jumped the shark at this point. The language is now
self-parody. It appeals not to productive hackers, but to gadget freaks and language theory
nerds.
And yeah, the snark is flowing freely in this post. But I stand by every word of it.
C++0x to save the day
Posted Jun 18, 2008 22:28 UTC (Wed) by pphaneuf (subscriber, #23480)
[Link]
This is because template parameters are untyped (they are types themselves!), and concepts are basically typing for types. C preprocessor macros have exactly the same problem. Consider this:
#include <stdio.h>
// Ignore that this is unsafe, it's just an example.
#define mymacro(X) printf(X)
void main() {
mymacro(42);
}
You can see that there is no typing for X there, and the same applies to template parameters (except they actually do have a little bit of typing, but not much).
Also, you might note that in C, this compiles with a warning, then crashes at runtime. In C++, compile-time error, because, well, it is. That's an example of what I was saying earlier: program in C, but call your file foo.cc instead of foo.c, and it will be better. You won't get any of those horrible template diagnostic messages (you don't use templates!), you'll in fact have better warnings and errors.
C++0x to save the day
Posted Jun 19, 2008 0:37 UTC (Thu) by flewellyn (subscriber, #5047)
[Link]
I see the problem: C++ creates a metalanguage to describe types in the language. But the
metalanguage itself lacks types, so you create a meta-metalanguage to describe types in the
metalanguage. What happens when you want to have types in concepts? A
meta-meta-metalanguage?
This is an argument in favor of reflection.
C++0x to save the day
Posted Jun 19, 2008 3:02 UTC (Thu) by pynm0001 (guest, #18379)
[Link]
Concepts are not types, and are not a panacea, as what they test for will have to be kept in
sync with what the template class actually requires. But acting like it's some kind of
infinite recursive type is foolhardy and leads me to believe you haven't looked at concepts
yet. ;)
Or to put it another way, why are people inundated in metametametainfo nowadays, what with the
explosion of features that take advantage of metainfo about our information?
But why are we complaining about this anyways? unwieldy compiler error messages *are* a
problem, and if were as simple as simply changing the compiler a bit that would have already
been done. Even scripts that try to condense the error messages down a bit after the fact
don't help. Concepts allow you to fail-fast when compiling.
error: foo.cpp:15 -- Cannot instantiate template<class T> Foo with T = Widget because Widget
is not Iterable (concept defined in foo.h:17).
is much more useful than an error message talking about missing copy constructors or something
in Widget. Concepts are optional but you only have to put in a bit of work to add them to
your library and they work on everything which uses that template, it doesn't need changes in
your code to derive from IEnumerable or something crazy, which is good if you can't change
your class hierarchy, or simply don't want to derive from a class just to prove you've
implemented some specific functions.
Careful use of concepts will allow a program to be able to avoid having to use adaptor classes
to interface with a template as well, as instead of having to rename functions you can use a
concept_map to tell the template what function to call in class Foo to get the effect of
push_back, for instance. So when the template calls T::push_back, the correct Foo::append()
would get called instead.
So yes, you may have to do extra work, but it's optional. If you don't use concepts then you
get what you have now, if you do use concepts your programs can get better, easier to read and
easier to build. I think of this like the visibility support added to g++ in 4.0. It was a
pain to figure out but it has lead to great speedups so I'm not upset that they developed it.
I'm actually quite pleased.
I have to disagree:
Posted Jun 19, 2008 15:09 UTC (Thu) by hummassa (subscriber, #307)
[Link]
> But why are we complaining about this anyways? unwieldy compiler error
> messages *are* a problem, and if were as simple as simply changing the
> compiler a bit that would have already been done. Even scripts that
> try to condense the error messages down a bit after the fact don't
> help. Concepts allow you to fail-fast when compiling.
This is wrong in many levels; I don't know where to start... so, I'll
reply to your example:
> error: foo.cpp:15 -- Cannot instantiate template<class T> Foo with T =
> Widget because Widget is not Iterable (concept defined in foo.h:17).
The correct error message would be IMHO:
error: foo.cpp:15 -- cannot instantiate template<class T> Foo with T =
Widget because Widget::operator++(int) nor ::operator++(Widget&,int)
exists. Foo<T> is defined at foo.h:20 and uses said operator at foo.h:25.
This is feasible because when Foo<T> was defined, it already had the
information that T needed T::operator*() or ::operator*(T&) and
T::operator++(int) or ::operator++(T&, int), just because foo.h:25 is:
while( *t++ ) { do_something_with(t); }
I understand that "Widget is not Iterable" is even easier than "Widget::
operator*() not defined", so I still think that concepts are a good idea
as documentation facilities, but I can't agree that good error
messages "were impossible to attain before concepts".
Just for the kicks, I tried to see what would be the error message in
such a case:
> um.cc: In static member function 'static int Foo<T>::foo(T) [with T =
> std::basic_string<char, std::char_traits<char>, std::allocator<char>
> >]':
> um.cc:16: instantiated from here
> um.cc:8: error: no 'operator++(int)' declared for postfix '++', trying
> prefix operator instead
> um.cc:8: error: no match for 'operator++' in '++x'
um.cc:8 is the usage of *t++ in Foo<T>::foo(T); actually, the message
contains almost every single useful bit of information, but in a garbled
way: it satys that the problem is the usage of a postfix ++ in line 8,
when instantiated on line 16. But it forgets to say what type it's
instantiated to... this can't be hard to correct IMHO.
I have to disagree:
Posted Jun 19, 2008 18:08 UTC (Thu) by nix (subscriber, #2304)
[Link]
The [with T=...] bit says what the type the template is being instantiated
with is. (Ow. Nasty center-embedding. Sorry.)
Many days later...
Posted Aug 24, 2008 11:08 UTC (Sun) by hummassa (subscriber, #307)
[Link]
I forgot to explain that it doesn't say the "most short, meaningful to the
lines where the error ocurred name", /in/ /casu/ "std::string".
C++0x to save the day
Posted Jun 19, 2008 3:58 UTC (Thu) by elanthis (subscriber, #6227)
[Link]
Reflection happens at run time, or requires an even more complex meta-language (.e.g.
meta-c++) in order to handle them at compile time.
Concepts are, for all intents and purposes, just a simple way of specifying type constraints.
Standard C++ allows you to have very specific type matches (unsigned long, Foo*, etc.) or very
generic types (typename anything), while Concepts add the ability to describe a type that
follows some particular contract (anything that can be added together, anything with a
set(string,int) method, anything with a default constructor, etc.).
However, the unwieldly error messages produced by C++ really aren't directly related to the
lack of Concepts in the current language. It's mostly just the compilers explicitly choosing
to be too verbose.
Say your code looks like this:
typedef vector<int> vint;
vint numbers;
numbers.add("foo");
You're going to get a huge error including things like std::basic_vector<int>::blah::blargh
etc. etc. What is happening is that the compiler is substituting in the actual type in the
AST/IR instead of the type specified by the user.
A compiler like Clang (eventually) will not have this issue. Instead of spitting out the base
template type and every child in the chain of derived templates, it can just say "vint
(typedef std::vector<int>) has no method matching ::add(char*)" and then maybe spit out the
other overloaded versions of ::add() a la GCC.
GCC and the other C++ compilers spit out huge error messages for templates because the
compiler authors just didn't care enough (or didn't think enough) to support cleaner error
messages. Nothing in C++ itself makes those cleaner messages impossible, or even all that
difficult.
C++0x to save the day
Posted Jun 18, 2008 22:47 UTC (Wed) by ncm (subscriber, #165)
[Link]
C++ appeals to serious writers of useful libraries, and users of those libraries.
There's nothing freaky here. The compiler can't know, by itself, that a template argument must
model a numeric type. Concepts allow the library writer to say so. Then, when a user tries to
use the template on something that isn't numeric, the compiler can say so right there, instead
of complaining that some expression down in the function body is ill-formed.
As noted above, macros in C have the same problem, but hardly anybody tries to do anything
ambitious with C macros; far fewer do it successfully, in part because of precisely this sort
of problem. In essence, a C++ library can extend the compiler, and compiler extensions need
their own error messages. Concepts gives library writers a practical way to provide them, to
describe the error in terms of the library interface, not in terms of details of the library
implementation, which is all a compiler could conceivably do by itself.
C++0x to save the day
Posted Aug 7, 2009 19:50 UTC (Fri) by hummassa (subscriber, #307)
[Link]
> The compiler can't know, by itself, that a template argument must model a numeric type.
Sure it can. The compiler has access to the source of the template; it will have to generate code based on that source eventually, so it knows what it needs.
Even if the compiler does not "plan ahead", during the instantiation phase it can deduce WHY the instantiation went wrong, instead of spilling WHAT went wrong with it... and point to the right lines of code, and giving meaningful class names instead of "complete" class names (IOW:
std::string
instead of
std::basic_string<char, std::char_traits<char>, std::allocator<char>>