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.
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 (guest, #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.