tags:

views:

795

answers:

9

Background

Using boost and other similar libraries is the easiest way to find compiler shortcomings, but is there a stage at which things go too far?

This mangled symbol:

_ZTSN5boost6spirit2qi6detail13parser_binderINS1_11alternativeINS_6fusion4consINS1_8sequenceINS6_INS1_16lexeme_directiveINS7_INS6_INS1_6actionINS1_9referenceIKNS1_4ruleIN9__gnu_cxx17__normal_iteratorIPKcSsEEFN7xxxxxxx2ir8carry_op2OpEvENS5_11unused_typeESM_EEEENS_7phoenix5actorINSQ_9compositeINSQ_11assign_evalENS5_6vectorINS0_14local_variableILi0EEENS0_8argumentILi0EEENS5_5void_ESZ_SZ_SZ_SZ_SZ_SZ_SZ_EEEEEEEENS6_INS1_10char_classINS0_3tag9char_codeINS15_5spaceENS0_13char_encoding5asciiEEEEENS5_3nilEEEEEEEEENS6_INS9_INS7_INS6_INSA_IKNSB_ISG_FSbIwSt11char_traitsIwESaIwEEvENSH_6parser11white_spaceISG_EESM_EEEENS6_INS1_12literal_charINS18_8standardELb1ELb0EEENS6_IS1R_NS6_IS1U_NS6_IS1R_NS6_IS1U_NS6_IS1R_NS6_IS1U_NS6_IS1R_S1C_EEEEEEEEEEEEEEEEEEEENSR_INSS_IST_NSU_INS0_9attributeILi0EEENSS_INSQ_6detail14construct_evalISJ_EENSU_ISW_SY_NSX_ILi1EEENSX_ILi2EEENSX_ILi3EEENSX_ILi4EEESZ_SZ_SZ_SZ_EEEESZ_SZ_SZ_SZ_SZ_SZ_SZ_SZ_EEEEEEEES1C_EEEEEENS6_INS7_INS6_IS1G_NS6_INS9_INS7_INS6_IS1R_NS6_IS1U_NS6_IS1R_NS6_IS1U_NS6_IS1R_NS6_IS1U_NS6_IS1U_S1W_EEEEEEEEEEEEEEEENSR_INSS_IST_NSU_IS26_NSS_IS29_NSU_ISW_SY_S2A_S2B_NSQ_5valueINS_8optionalIS1K_EEEES2C_SZ_SZ_SZ_SZ_EEEESZ_SZ_SZ_SZ_SZ_SZ_SZ_SZ_EEEEEEEES1C_EEEEEENS6_INS7_INS6_IS1G_NS6_INS9_INS7_IS21_EENSR_INSS_IST_NSU_IS26_NSS_IS29_NSU_ISW_SY_S2A_S2B_S2C_S2Y_SZ_SZ_SZ_SZ_EEEESZ_SZ_SZ_SZ_SZ_SZ_SZ_SZ_EEEEEEEES1C_EEEEEES1C_EEEEEEEEN4mpl_5bool_ILb0EEEEE

(1,388 characters)

Translates into (thanks c++filt!):

boost::spirit::qi::detail::parser_binder<boost::spirit::qi::alternative<boost::fusion::cons<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::lexeme_directive<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::action<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, xxxxxxx::ir::carry_op::Op ()(), boost::fusion::unused_type, boost::fusion::unused_type> const>, boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::assign_eval, boost::fusion::vector<boost::spirit::local_variable<0>, boost::spirit::argument<0>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > > >, boost::fusion::cons<boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, boost::fusion::nil> > > >, boost::fusion::cons<boost::spirit::qi::action<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > ()(), xxxxxxx::parser::white_space<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::fusion::unused_type> const>, boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::standard, true, false>, boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > ()(), xxxxxxx::parser::white_space<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::fusion::unused_type> const>, boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::standard, true, false>, boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > ()(), xxxxxxx::parser::white_space<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::fusion::unused_type> const>, boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::standard, true, false>, boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > ()(), xxxxxxx::parser::white_space<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::fusion::unused_type> const>, boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::standard, true, false>, boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > ()(), xxxxxxx::parser::white_space<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::fusion::unused_type> const>, boost::fusion::nil> > > > > > > > > >, boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::assign_eval, boost::fusion::vector<boost::spirit::attribute<0>, boost::phoenix::composite<boost::phoenix::detail::construct_eval<xxxxxxx::ir::carry_op>, boost::fusion::vector<boost::spirit::local_variable<0>, boost::spirit::argument<0>, boost::spirit::argument<1>, boost::spirit::argument<2>, boost::spirit::argument<3>, boost::spirit::argument<4>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> >, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > > >, boost::fusion::nil> > >, boost::fusion::cons<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::lexeme_directive<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::action<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, xxxxxxx::ir::carry_op::Op ()(), boost::fusion::unused_type, boost::fusion::unused_type> const>, boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::assign_eval, boost::fusion::vector<boost::spirit::local_variable<0>, boost::spirit::argument<0>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > > >, boost::fusion::cons<boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, boost::fusion::nil> > > >, boost::fusion::cons<boost::spirit::qi::action<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > ()(), xxxxxxx::parser::white_space<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::fusion::unused_type> const>, boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::standard, true, false>, boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > ()(), xxxxxxx::parser::white_space<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::fusion::unused_type> const>, boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::standard, true, false>, boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > ()(), xxxxxxx::parser::white_space<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::fusion::unused_type> const>, boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::standard, true, false>, boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::standard, true, false>, boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::standard, true, false>, boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > ()(), xxxxxxx::parser::white_space<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::fusion::unused_type> const>, boost::fusion::nil> > > > > > > > > >, boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::assign_eval, boost::fusion::vector<boost::spirit::attribute<0>, boost::phoenix::composite<boost::phoenix::detail::construct_eval<xxxxxxx::ir::carry_op>, boost::fusion::vector<boost::spirit::local_variable<0>, boost::spirit::argument<0>, boost::spirit::argument<1>, boost::spirit::argument<2>, boost::phoenix::value<boost::optional<std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > > >, boost::spirit::argument<3>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> >, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > > >, boost::fusion::nil> > >, boost::fusion::cons<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::lexeme_directive<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::action<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, xxxxxxx::ir::carry_op::Op ()(), boost::fusion::unused_type, boost::fusion::unused_type> const>, boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::assign_eval, boost::fusion::vector<boost::spirit::local_variable<0>, boost::spirit::argument<0>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > > >, boost::fusion::cons<boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, boost::fusion::nil> > > >, boost::fusion::cons<boost::spirit::qi::action<boost::spirit::qi::sequence<boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > ()(), xxxxxxx::parser::white_space<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::fusion::unused_type> const>, boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::standard, true, false>, boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > ()(), xxxxxxx::parser::white_space<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::fusion::unused_type> const>, boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::standard, true, false>, boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > ()(), xxxxxxx::parser::white_space<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::fusion::unused_type> const>, boost::fusion::cons<boost::spirit::qi::literal_char<boost::spirit::char_encoding::standard, true, false>, boost::fusion::cons<boost::spirit::qi::reference<boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > ()(), xxxxxxx::parser::white_space<__gnu_cxx::__normal_iterator<char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::fusion::unused_type> const>, boost::fusion::nil> > > > > > > >, boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::assign_eval, boost::fusion::vector<boost::spirit::attribute<0>, boost::phoenix::composite<boost::phoenix::detail::construct_eval<xxxxxxx::ir::carry_op>, boost::fusion::vector<boost::spirit::local_variable<0>, boost::spirit::argument<0>, boost::spirit::argument<1>, boost::spirit::argument<2>, boost::spirit::argument<3>, boost::phoenix::value<boost::optional<std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > > >, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> >, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > > >, boost::fusion::nil> > >, boost::fusion::nil> > > >, mpl_::bool_<false> >

(12,980 characters)


Question

So my question is, in light of these (which technically don't pass the standard as I understand it, as the mangled name is over 1,024 characters), is this a sign that C++ is showing its age by not keeping up-to-date with the newest concepts? Or is it simply a sign that programmers are expecting too much from the language, and template libraries like boost are doing the best they can to facilitate this?

+5  A: 

I think it's a sign of aging for the standard limiting mangled name to 1,024 characters ;-)

Michael Krelin - hacker
+7  A: 

As much as a wrench shows its age when it's being used to hammer in a nail.

databyss
Nah, I agree with jalf. It's more like a wrench "showing its age" when it's being used to tighten a nut on the Millennium Falcon. Nothing wrong with the wrench, and nothing wrong with using it for that purpose, just because its inventor didn't explicitly intend it to be used for interstellar travel.
Steve Jessop
As The Tao Of Programming so elegantly puts it:"The Tao gave birth to machine language. Machine language gave birth to the assembler.The assembler gave birth to the compiler. Now there are ten thousand languages.Each language has its purpose, however humble. Each language expresses the Yin and Yang of software. Each language has its place within the Tao.But do not program in COBOL if you can avoid it."
Grant Peters
I wrench will tighten a bolt no matter what, and it's still a good tool for it. You can also use it to hammer in a nail, but it's not the right tool for the job.
databyss
+13  A: 

In C++, the mangled symbol name is the equivalent of the call stack in other languages.

Show a 1970s asm programmer a call stack 23 deep, and they would say 'surely that is taking that new-fangled function stuff a bit far? How could you possibly debug and analyse something that complicated? You would need a special tool just to work out where everything was in memory'.

In fact, in the absence of a debugger, it would actually be really impractical to work with functions nested that deep - fine when things work, but when they break, it becomes impossibly complex to relate the memory image back to your code.

Eclipse CDT actually has a really nice feature where it can take pre-processor macros and expand them one step at a time, with backwards and forwards buttons. Display of templates, especially in error messages, needs something like that. So you can navigate between

list<T>
list<ptr<t>>
list<ptr<string<T>>>>

and so on.

soru
Agreed. Mangled names and names of complex template instantiations have nothing to do with using C++; they are internal implementation details. It's unfortunate that there is a 1,024-character limit, but it doesn't reflect anything about C++'s usefulness.
Kristopher Johnson
@Kristopher Johnson: Surely level of complexity is beyond what the language was originally designed to cater for, though? The fact it works notwithstanding, of course.
Matthew Iselin
It's certainly going beyond what the implementation and tooling of the language was designed for. The asm programmer above wouldn't be wrong if, given a core dump from a crash, they had to manually work out how the compiler had 'location mangled' all his variables onto the stack.
soru
Dunno about call stack, but certainly a hierarchy of templated types to give a single type signature...
Dan
@Matthew: First you have to define what "the language as originally designed" actually is. "C with classes"? Pre-standard C++? C++98?
sbi
True. I take it to mean pre-standard "C with classes", but that's just my interpretation. The design of C++ wasn't a single discrete event. It's something that has been ongoing from the 80's, when Stroustrup first started playing around with what was basically C with Classes, and up till today. Answering the question of "what the language was originally designed for" is nontrivial.
jalf
A: 

Please remember that the original C++ (C with classes) was a hack on C. Its goal was good - enable better organization of C programs by bringing in ideas from the OOP world. The objective was good but the way it was done - bad. C++, over the time, has grown in by piling feature upon feature on its tiny C base, which was designed for simplicity. What will happen if you construct a 100 storey building on a foundation meant for a 2 storey house? That is the disaster happened to C++. It culminated with the confusion around "concepts", which is now out of the new standard. Many of these new features were added to workaround the core C++'s inherent weaknesses. I think a statically typed language cannot be a good vehicle for OOP, at least if you go by Alan Kay's definition of that paradigm. When I use C++ I try to stick to the basic features like namespaces, standard template libraries and exceptions. I will create a C++ class only if an hierarchy of types makes absolute sense in the current context. I just ignore the rest of the 'advanced', complicated stuff.

Vijay Mathew
If C++ started out as C with classes, then namespaces, templates, and exceptions are the advanced features. Anything more "advanced" would be RAII, metaprogramming, and other creative ways of using these features.
Dima
templates and exceptions has got nothing to do with classes or OOP. Generic programming and exceptions are nice features any decent language should have, I don't consider them advanced. RAII is not a language feature, but an idiom. So it need not be discussed here. Any complex C++ application can be written using the basic features and I have done it many times. For just one example, please see http://spark-scheme.wikispot.org/.
Vijay Mathew
+1 for the link and for mentioning that concepts are out of C++0x (news to me). It's a shame that parts of C++ are so complex (e.g. template overload resolution) but I still think that in the "big picture" sense it was a smart move to grow C into an OOP language, however technically awful the result, because the dominance of C ensured widespread uptake and thus ongoing development. (For much the same reason, Intel were wise to stick with 8086 compatibility even though it placed drastic technical limits on them.)
j_random_hacker
@Vijay: _"Any complex C++ application can be written using the basic features"_ Of course. It can also be written using assembler. And just as with writing the code in assembly, it will be more complicated, more verbose, more error-prone.
sbi
There is a big difference between C++ and assembler. Now please tell me how not using template metaprogramming will make my C++ program more verbose, complicated and error-prone? Links to some of your simple, concise and clean C++ code demosntrating all the advanced language features will suffice. Note that I have already provided a link to one of my real-world projects to back-up my argument.
Vijay Mathew
@Vijay: Ever use iterators? Tell me how to implement those without these "advanced and complex" features.
jalf
@Vijay: jalf's excellent example of iterators helps to distinguish where template metaprogramming is and isn't useful. It is almost never helpful to use metaprogramming for "application" code (where it can needlessly obfuscate and the extra "generality" isn't needed) but frequently helpful to use it for building libraries (where the obfuscation is "paid for" by the increased generality). Of course, 99% of C++ code is apps; only ~1% is general-purpose libraries like Boost/Blitz etc. But that's an important 1%.
j_random_hacker
Yes I use iterators, but never had to implement them. Could you please explain the 'advanced features' needed to implement iterators? As far as I understand they involve little more than plain pointer arithmetic. BTW, I am not of the opinion that Boost is a well designed library. For instance, look at the boost threads API. C++ programmers seems to be held up in a strange world where even the simplest tasks are expected to be performed 'ceremoniously'.
Vijay Mathew
To implement iterators in such a way that a pointer can *be* an iterator, you first of all need templates and operator overloading. To make them efficient (e.g. so that faster algorithms can be selected when random-access iterators are available), you need type tagging and traits classes, and a complicated overload resolution mechanism. That doesn't quite amount to template metaprogramming, but it's getting "up there" in terms of complexity, yes?
j_random_hacker
You need templates, operator overloading, type tagging etc, etc because C++ is a statically typed language. That's what I said in my answer - "a statically typed language is *not* a good vehicle for OOP". If you have to introduce all this complications to work around the weakness of the language, then why not use a dynamically typed, well designed OOP language (Smalltalk or Lisp) in the first place? BTW, I think it is unethical to down vote someone just because he has a different viewpoint. Otherwise it should be proved that, what he said is completely irrelevant.
Vijay Mathew
Because dynamic typing = *slow*. Which, admittedly, is becoming less important as CPU speeds continue to increase, but it's still important for many tasks. C++ is designed for speed, and it explicitly has the philosophy of "you don't pay for what you don't use", so dynamic typing is out. Of course if you want the ultimate in flexibility, you're free to throw away type safety -- just bung some function pointers in a `struct` and bingo! Per-object "dynamic" OOP message dispatch.
j_random_hacker
@Vijay: `A)` Iterators are not about OOP, they are about generic programming. C++ is a multi-paradigm language and that's where it's strongest. If you're using iterators, you're already using more than its OO subset. `B)` I just bounce the question back at you: If you want to use a pure OOP language, why do you use C++? `C)` Usually answers are downvoted because they argue a POV that's considered _wrong_, not different. Did anyone here indicate this isn't the case with the downvotes for your answer?
sbi
@sbi: I am not whining that my answer should not be down-voted! But the reason for a down-vote should be supported by a comment. POV that's considered wrong? Which POV considered wrong by whom? By any authority on OOP or language design? Well, my answer already contains a link to what an authority said on OOP. Please try to see the reason behind what I said before posting shallow comments.
Vijay Mathew
@Vijay: I certainly agree that it's courteous to explain why when giving a -1. I guess the difficulty here is that both the original question and your response are a bit amorphous -- there's nothing really concrete that can objectively settle things one way or the other, just a bunch of different people's opinions about what qualities are most important. I'm still interested in hearing your response to my last comment BTW.
j_random_hacker
@j_random_hacker: My preferred way to write software is to use a dynamic language, most preferably my own version of Lisp. In fact this has the advantage that I design and code at the same time and get my job done really fast. I use C/C++ when ever I have to directly talk to the underlying platform, which I do very rarely, because the prototyping language already have a host of libraries. Re-writing a part of the program just for speed has not happened so far (for me), probably because of the virtue of better hardware. In short, using C/C++ just for *speed* does not pay much any more.
Vijay Mathew
@Vijay: As for my downvote: I _did_ add a comment to say why I downvoted your answer.
sbi
@sbi: Fair enough. Your comment only supports what I said - an answer should not be down-voted just because it has a different POV. BTW, you haven't answered the questions I asked in the previous comment.
Vijay Mathew
@Vijay: This gets tiring. One last time: I disagreed with your POV. I commented why I do. I down-voted your answer. Nothing wrong with that AFICS.
sbi
@Vijay: As to your questions: `A)` I already gave the reason in a comment. If you don't think it's valid -- fine. But stop asking for another one. `B)` _Your_ POV was considered wrong by _me_. (_Wasn't this clear?_) `C)` First, (also repeatedly said) C++ isn't an OO language, but a multi-paradigm one. Further, I don't need a guru to support my own POV, I have _arguments_. You're free to agree or disagree with or even ignore them, but if you want your POV taken seriously (or even convert me to it), you need to bring better arguments. `D)` Please stop insulting me. That's bad for your karma.
sbi
+12  A: 

I think the fact that people keep coming up with new ways of using the features of C++ is the sign of its flexibility and power, not its aging.

Dima
+36  A: 

Wouldn't the language be showing its age if people did not apply it to new, bigger problems than originally intended?

I think this is exactly the opposite -- it shows that C++ is able to do something far more complex than was intended in the earliest versions of the language. How is that "showing its age"? C++ would be showing its age if it was still being used in the half-baked Java-like OOP style popular 15 years ago.

I think the fact that the usage of the language continues to evolve so much, even when the actual standard is unchanged, is a sign of strength.

Of course, C++ is showing its age in countless other ways, but I don't think this is one of them. On the contrary, this is one of C++'s redeeming features.

jalf
Seconded.
j_random_hacker
I honestly didn't consider that perspective, and I agree. +1.
Matthew Iselin
Can I please have a dozen votes to pile it on this answer?
sbi
Very true.
Michael Krelin - hacker
@jalf: So wait, you're saying that ridiculously long symbols is a "redeeming feature"? :P
Dan Moulding
Several years ago, Bjarne Stroustrup gave a lecture at my university and someone asked him a similar question. Your response is almost exactly the answer he gave.
bta
+4  A: 

Most of the resulting name is "noise", in that it's either specified by a typedef, or the arguments were defaults.

This IMHO, is more of an issue with where compiler implementors have decided to focus their efforts. Most compiler vendors spend more of their time ensuring that they implement the (complex) C++ standard correctly in a way that produces code that is as fast as they can possibly make it.

Providing pretty names for most is an after thought to the above.

Just to highlight this, with the exception of the last two items, the following mappings could be implemented in the demangler so that they always took place:

  • We can search and replace basic_string<const char *, ...> and replace it with string
  • We can search and replace basic_string<const wchar_t *, ...> and replace it with wstring
  • We can search and replace __gnu_cxx::__normal_iterator<char const *... and replace it with string::const_iterator
  • For display purposes we can remove boost::<namespace>:: and std:: as in context these don't add much.
  • Finally, C++ 0x will introduce template parameter packs and so we can remove things like boost:fusion::void_, boost:fusion::void_, boost:fusion::void_, since there will no longer be any need for preprocessor hacks to handle them.

After all of the above we have:

qi::detail::parser_binder<qi::alternative<cons<qi::sequence<cons<qi::lexeme_directive<qi::sequence<cons<qi::action<qi::reference<qi::rule<string::const_iterator, xxxxxxx::ir::carry_op::Op ()(), unused_type, unused_type> const>, boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::assign_eval, vector<local_variable<0>, argument<0> > > > >, cons<qi::char_class<tag::char_code<tag::space, char_encoding::ascii> > > > > >, cons<qi::action<qi::sequence<cons<qi::reference<qi::rule<string::const_iterator, wstring()(), xxxxxxx::parser::white_space<string::const_iterator >, unused_type> const>, cons<qi::literal_char<char_encoding::standard, true, false>, cons<qi::reference<qi::rule<string::const_iterator, wstring()(), xxxxxxx::parser::white_space<string::const_iterator >, unused_type> const>, cons<qi::literal_char<char_encoding::standard, true, false>, cons<qi::reference<qi::rule<string::const_iterator, wstring()(), xxxxxxx::parser::white_space<string::const_iterator >, unused_type> const>, cons<qi::literal_char<char_encoding::standard, true, false>, cons<qi::reference<qi::rule<string::const_iterator, wstring()(), xxxxxxx::parser::white_space<string::const_iterator >, unused_type> const>, cons<qi::literal_char<char_encoding::standard, true, false>, cons<qi::reference<qi::rule<string::const_iterator, wstring()(), xxxxxxx::parser::white_space<string::const_iterator >, unused_type> const> > > > > > > > > > >, boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::assign_eval, vector<attribute<0>, boost::phoenix::composite<boost::phoenix::detail::construct_eval<xxxxxxx::ir::carry_op>, vector<local_variable<0>, argument<0>, argument<1>, argument<2>, argument<3>, argument<4> > > > > > > > > >, cons<qi::sequence<cons<qi::lexeme_directive<qi::sequence<cons<qi::action<qi::reference<qi::rule<string::const_iterator, xxxxxxx::ir::carry_op::Op ()(), unused_type, unused_type> const>, boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::assign_eval, vector<local_variable<0>, argument<0> > > > >, cons<qi::char_class<tag::char_code<tag::space, char_encoding::ascii> > > > > >, cons<qi::action<qi::sequence<cons<qi::reference<qi::rule<string::const_iterator, wstring()(), xxxxxxx::parser::white_space<string::const_iterator >, unused_type> const>, cons<qi::literal_char<char_encoding::standard, true, false>, cons<qi::reference<qi::rule<string::const_iterator, wstring()(), xxxxxxx::parser::white_space<string::const_iterator >, unused_type> const>, cons<qi::literal_char<char_encoding::standard, true, false>, cons<qi::reference<qi::rule<string::const_iterator, wstring()(), xxxxxxx::parser::white_space<string::const_iterator >, unused_type> const>, cons<qi::literal_char<char_encoding::standard, true, false>, cons<qi::literal_char<char_encoding::standard, true, false>, cons<qi::literal_char<char_encoding::standard, true, false>, cons<qi::reference<qi::rule<string::const_iterator, wstring()(), xxxxxxx::parser::white_space<string::const_iterator >, unused_type> const> > > > > > > > > > >, boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::assign_eval, vector<attribute<0>, boost::phoenix::composite<boost::phoenix::detail::construct_eval<xxxxxxx::ir::carry_op>, vector<local_variable<0>, argument<0>, argument<1>, argument<2>, boost::phoenix::value<boost::optional<wstring> >, argument<3> > > > > > > > > >, cons<qi::sequence<cons<qi::lexeme_directive<qi::sequence<cons<qi::action<qi::reference<qi::rule<string::const_iterator, xxxxxxx::ir::carry_op::Op ()(), unused_type, unused_type> const>, boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::assign_eval, vector<local_variable<0>, argument<0> > > > >, cons<qi::char_class<tag::char_code<tag::space, char_encoding::ascii> > > > > >, cons<qi::action<qi::sequence<cons<qi::reference<qi::rule<string::const_iterator, wstring()(), xxxxxxx::parser::white_space<string::const_iterator >, unused_type> const>, cons<qi::literal_char<char_encoding::standard, true, false>, cons<qi::reference<qi::rule<string::const_iterator, wstring()(), xxxxxxx::parser::white_space<string::const_iterator >, unused_type> const>, cons<qi::literal_char<char_encoding::standard, true, false>, cons<qi::reference<qi::rule<string::const_iterator, wstring()(), xxxxxxx::parser::white_space<string::const_iterator >, unused_type> const>, cons<qi::literal_char<char_encoding::standard, true, false>, cons<qi::reference<qi::rule<string::const_iterator, wstring()(), xxxxxxx::parser::white_space<string::const_iterator >, unused_type> const> > > > > > > > >, boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::assign_eval, vector<attribute<0>, boost::phoenix::composite<boost::phoenix::detail::construct_eval<xxxxxxx::ir::carry_op>, vector<local_variable<0>, argument<0>, argument<1>, argument<2>, argument<3>, boost::phoenix::value<boost::optional<wstring> > > > > > > > > > > > > > >, mpl_::bool_<false> >

This string now has 5k characters (still a lot I agree) but its now less than half of the lenght of the original. Looking deeper at a sub section other patterns are visible:

cons<qi::reference<qi::rule<string::const_iterator, wstring()()
      , xxxxxxx::parser::white_space<string::const_iterator >
      , unused_type> const>
      , cons<qi::literal_char<char_encoding::standard, true, false>,
cons<qi::reference<qi::rule<string::const_iterator, wstring()()
      , xxxxxxx::parser::white_space<string::const_iterator >
      , unused_type> const>
      , cons<qi::literal_char<char_encoding::standard, true, false>,
cons<qi::reference<qi::rule<string::const_iterator, wstring()()
      , xxxxxxx::parser::white_space<string::const_iterator >
      , unused_type> const>
      , cons<qi::literal_char<char_encoding::standard, true, false>,
cons<qi::reference<qi::rule<string::const_iterator, wstring()()
      , xxxxxxx::parser::white_space<string::const_iterator >
      , unused_type> const>
      , cons<qi::literal_char<char_encoding::standard, true, false>,
cons<qi::reference<qi::rule<string::const_iterator, wstring()()
      , xxxxxxx::parser::white_space<string::const_iterator >
      , unused_type> const>

Again, 'boost' is using preprocessor tricks to allow a type to be built as if it is a vector. Similar to the case of void_ and nil, C++-0x parameter packs will avoid the need for the preprocessor to expand everything out 10 deep and the templates will be built to hold exactly what the user required. The above string takes up nearly a 1000 characters, and it is just one of 3 or 4 such strings in the original.

So if the question is: Is C++'03 showing its age, then the answer is "maybe" but only because it doesn't yet have template parameter packs.

Richard Corden
+1  A: 

C was designed in the spirit of "mechanism, not policy"; this means it can cope in strange places, like embedded devices or kernels, where a decent standard library may not be present. It opens up the door to writing portable code (though doesn't by any means guarantee it). Importantly, the language is powerful enough that important things are not treated as special cases (e.g. "printf" is just another function; you don't need special operators to do string formatting or any such). This means that the language can (to some extent) be built by its users, not its creators.

C++ has inherited some of this spirit. And in this spirit, people have made libraries that offer both functionality and fairly succinct syntax.

C++ is still used in cheap embedded systems because it cuts the costs of software development compared to C, but remains reasonably fast (and has actually been ported to the systems). For such reasons I don't think C++ is broken or showing its age.

But trying to turn it into a language suitable for "modern" pursuits is a simple case of using the wrong tool for the job. C++ has a place, but it is taking up a much wider area than it should be due to its historical popularity and momentum.

Artelius
+2  A: 

I don't think the example you have given is a good example of the language being used "in ways it was never designed to be used". C++'s design explicitly allows for uses such as this. I think what it really shows is some of the language's weaknesses. The way templates and static typing work together in the language result in monstrosities such as your nice example. Even simpler uses of templates can easily result in absurdly long and complicated names. Programmers more familiar with other languages and less familiar with C++ would see things like this and immediately recognize that there's something not quite "right" with C++.

Now it's not to say that C++ is a crap language just because it has some shortcomings. All languages that I've ever used have some disadvantages. In the end, I think your example illustrates one of C++'s weaknesses better than it illustrates C++'s age.

Dan Moulding