
On 11/25/2011 3:10 AM, Daniel James wrote:
On 24 November 2011 13:35, Dean Michael Berris <mikhailberis@gmail.com> wrote:
Why are people blaming the libraries for horrible error messages when it's compilers that spew these error messages?
They just don't want to use a library which has horrible error messages. It doesn't matter if it's the library's fault or the compiler's fault. Blame has nothing to do with it.
Those are very good points, Daniel. So is this, from Nathan:
The problem is that errors point to code that is deep within the library's implementation, or worse, the implementations of helper libraries used by the library. To understand the error, the user has to look at the library's implementation. The user shouldn't have to do that - understanding the implementation of a library should not be a prerequisite for using it.
If you have any specific suggestions about what compilers could do to turn these errors from deep within the library implementation, into errors that do not require knowing anything about the library implementation, I would like to hear it, and I'm sure so would compiler writers.
Otherwise, you have to accept that library writers face a trade-off between the user-friendliness of error messages, and the expressiveness, terseness, and power obtained by extensive use of advanced techniques such as template metaprogramming. There is no one right answer to this tradeoff, and it is good for users to have different alternatives available to them.
It's not that we TMP/ET advocates are ignorant about it. There have been efforts to fix or at least alleviate this problem. Yet, it's still not enough to satisfy everyone. Eric Niebler noted that it is a bug if a library spews error messages and that the one encountering such problems should report it as a bug for the author to fix. We've done that in Spirit by detecting invalid expressions as early as possible with a static-assert: template <typename Auto, typename Expr> static void define(rule& lhs, Expr const& expr, mpl::false_) { // Report invalid expression error as early as possible. // If you got an error_invalid_expression error message here, // then the expression (expr) is not a valid spirit qi expression. BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr); } The goal is to provide better diagnostics for the user. The code is isolated (notice that this branch of code calls nothing else in order to minimize the error trace). Brent Spillner triggered this static-assert:
But that's nothing; if you omit the '>>' from the expression or term definition you get the 33 kilochar beauty copied at the bottom of this email.
With MSVC, you see the error up front: C:\dev\boost\boost/spirit/home/qi/nonterminal/rule.hpp(176) : error C2664: 'boost::mpl::assertion_failed' : cannot convert parameter 1 from 'boost::mpl::failed ************(__thiscall boost::spirit::qi::rule<Iterator,T1,T2,T3,T4>::define::error_invalid_ expression::* ***********)(Expr)' to 'boost::mpl::assert<false>::type' Plus some more extra error trace after which leads you to the erroneous Spirit expression. G++ is worse. It spews 4 long lines of trace before the actual static-assert. You'll have to do a textual search for "error" to get to the actual error. You might think that 4 lines is not that long, but these 4 lines contain complex ET types that the casual user need not know about. Right now, we are using BOOST_MPL_ASSERT_MSG. I switched to c++11 static_assert and now I get a better error message in MSVC: C:\dev\boost\boost/spirit/home/qi/nonterminal/rule.hpp(179) : error C2338: Invalid Expression C:\dev\boost\boost/spirit/home/qi/nonterminal/rule.hpp(223) : see reference to ... plus some more extra error trace after. With g++, I get: C:\dev\boost/boost/spirit/home/qi/nonterminal/rule.hpp:179:13: error: static assertion failed: "Invalid Expression" Which looks good, but without any trailing error trace, there's no way to follow the trail to where the actual error is. (I think that's a g++ bug! If you care about g++, they should be informed about this problem.) Sooo... despite our valiant efforts, the current state of affairs is still not good enough. People scared with error messages are still turned off. Now. What else can we do about it? Here's an idea. I'd like to hear yours. Presentation: The error trace is very noisy! It contains lots of types with full qualifications. E.g. Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_right, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript It might be good to present that in a GUI where the types are collapsed by default. Qualifications in a trace can also be optionally collapsed. With this, the user will see only this, for example: [+] rule.hpp(179) : error C2338: Invalid Expression [+] rule.hpp(223) : see reference to function template instantiation [+] with[+] [+] calc3.cpp(54) : see reference to function template instantiation [+] with[+] [+] calc3.cpp(43) : while compiling class template member function [+] with[+] [+] calc3.cpp(90) : see reference to class template instantiation [+] with[+] Clicking one of the [+] will reveal further information, hierarchically. It is possible to write a parser for the common compilers (MSVC and g++) and have it generate the data in HTML with some javascript for collapsing the data, or maybe just XML since text editors can collapse XML nodes already. I care about TMP in general and especially ET. I'd like to make the situation better, lest we will have more anti-TMP sentiment. I'm sure many people here care too. It's so utterly frustrating to see people avoid TMP libraries because of this prevalent problem. If there are any more nice ideas (hey this is Boost and we are full of wonderful ideas!), please share them. Regards, -- Joel de Guzman http://www.boostpro.com http://boost-spirit.com