[parameter] Lazy binding and operator|| patch

Hello, Section 3.2.3 of the Boost Parameter Library documentation prescribes a remedy for lazy binding ArgumentPacks directly using the Boost Lambda Library. I encountered some compilation errors when attempting this. The following illustrates the problem. $ g++ -dumpversion 4.1.2 $ cat lazy_binding_errors.cpp #include <iostream> #include <string> #include <boost/lambda/lambda.hpp> #include <boost/parameter.hpp> using namespace boost; using namespace boost::parameter; BOOST_PARAMETER_NAME(s1) BOOST_PARAMETER_NAME(s2) BOOST_PARAMETER_NAME(s3) template <class ArgumentPack> std::string f(ArgumentPack const& args) { std::string const& s1 = args[_s1]; std::string const& s2 = args[_s2]; typename binding< ArgumentPack, tag::s3, std::string >::type s3 = args[_s3 || lambda::ret<std::string>( lambda::var(s1) + lambda::var(s2) ) ]; return s3; } int main() { std::string x = f((_s1="hello,", _s2=" world")); std::cout << x << std::endl; } $ g++ -I./boost lazy_binding_errors.cpp 2>&1 | perl gSTLFilt.pl ... lazy_binding_errors.cpp:24: error: no match for 'operator[]' in 'args[boost ::lambda::operator||( const boost::parameter::keyword<tag::s3> & , const boost::lambda::lambda_functor< ... > & ) ... $ The problem is that both parameter::keyword and the lambda expression have overloads of operator||. Since using lambda expressions in conjunction with parameter::keywords is an intended use case for Boost.Parameter, why not resolve the problem by providing an operator|| specifically for this case? template <class Tag, class Default> aux::lazy_default<Tag, lambda::lambda_functor<Default> > operator||(keyword<Tag> const& key, lambda::lambda_functor<Default> const& default_) { return key.operator||(default_); } The attached patch implements this. Apply with 'patch -p0 < djw_lazy_binding.patch' from the boost root directory. However, after the patch is applied the following errors occur. $ g++ -I./boost lazy_binding_errors.cpp 2>&1 | perl gSTLFilt.pl ... lazy_binding_errors.cpp:24: error: conversion from 'void' to non-scalar type 'string' requested ./boost/boost/parameter/aux_/arg_list.hpp:136: error: return-statement with a value, in function returning 'void' ... $ These errors happen because lazy binding ultimately depends on boost::result_of to deduce the type of the lambda expression, but boost::result_of doesn't handle lambda expressions. This issue can be resolved by applying the two patches I submitted previously. mpl patch: http://tinyurl.com/35x5z5 utility patch: http://tinyurl.com/2h3g7n These patches do not need to be applied in any particular order. Applying all three has the effect of making lazy binding behave more like the description in the documentation. I ran the Boost Parameter Library test suite and everything passed. Let me know if I've misunderstood something or if there's a better way to solve this problem or if you'd like additional documentation/tests. Thanks! Daniel Walker

on Tue Mar 20 2007, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:
Hello,
Section 3.2.3 of the Boost Parameter Library documentation prescribes a remedy for lazy binding ArgumentPacks directly using the Boost Lambda Library. I encountered some compilation errors when attempting this.
Interesting; that example passed our automated tests.
The problem is that both parameter::keyword and the lambda expression have overloads of operator||. Since using lambda expressions in conjunction with parameter::keywords is an intended use case for Boost.Parameter, why not resolve the problem by providing an operator|| specifically for this case?
template <class Tag, class Default> aux::lazy_default<Tag, lambda::lambda_functor<Default> > operator||(keyword<Tag> const& key, lambda::lambda_functor<Default> const& default_) { return key.operator||(default_); }
The attached patch implements this. Apply with 'patch -p0 < djw_lazy_binding.patch' from the boost root directory.
Seems like a good idea. Please submit this to the SF patch tracker.
However, after the patch is applied the following errors occur.
$ g++ -I./boost lazy_binding_errors.cpp 2>&1 | perl gSTLFilt.pl ... lazy_binding_errors.cpp:24: error: conversion from 'void' to non-scalar type 'string' requested
./boost/boost/parameter/aux_/arg_list.hpp:136: error: return-statement with a value, in function returning 'void' ... $
These errors happen because lazy binding ultimately depends on boost::result_of to deduce the type of the lambda expression, but boost::result_of doesn't handle lambda expressions. This issue can be resolved by applying the two patches I submitted previously.
mpl patch: http://tinyurl.com/35x5z5 utility patch: http://tinyurl.com/2h3g7n
Please submit those to the tracker, too.
These patches do not need to be applied in any particular order. Applying all three has the effect of making lazy binding behave more like the description in the documentation. I ran the Boost Parameter Library test suite and everything passed. Let me know if I've misunderstood something or if there's a better way to solve this problem or if you'd like additional documentation/tests.
I don't have any suggestions, though maybe Daniel W. does. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On 3/20/07, David Abrahams <dave@boost-consulting.com> wrote:
on Tue Mar 20 2007, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:
template <class Tag, class Default> aux::lazy_default<Tag, lambda::lambda_functor<Default> > operator||(keyword<Tag> const& key, lambda::lambda_functor<Default> const& default_) { return key.operator||(default_); }
The attached patch implements this. Apply with 'patch -p0 < djw_lazy_binding.patch' from the boost root directory.
Seems like a good idea. Please submit this to the SF patch tracker.
Thanks! I just submitted it to SF.
These errors happen because lazy binding ultimately depends on boost::result_of to deduce the type of the lambda expression, but boost::result_of doesn't handle lambda expressions. This issue can be resolved by applying the two patches I submitted previously.
mpl patch: http://tinyurl.com/35x5z5 utility patch: http://tinyurl.com/2h3g7n
Please submit those to the tracker, too.
Done. I also submitted a patch for Boost.Lambda per the discussions here http://tinyurl.com/yr3gc9 and here http://tinyurl.com/2jgtld. Daniel

David Abrahams wrote:
on Tue Mar 20 2007, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:
These patches do not need to be applied in any particular order. Applying all three has the effect of making lazy binding behave more like the description in the documentation. I ran the Boost Parameter Library test suite and everything passed. Let me know if I've misunderstood something or if there's a better way to solve this problem or if you'd like additional documentation/tests.
I don't have any suggestions, though maybe Daniel W. does.
I think in general a better solution would be to add a member function to the keyword class template. Maybe: template <class F> ... lazy(F const& f) {} And possibly change the docs to not use Boost.Lambda. We're going to hit the same problem with the every lambda library. Changing the implementation is to late for 1.34, but we should probably change the docs so they don't mention Lambda. The example would become: bind(std::plus<std::string>(), ref(s1), ref(s2)) it's unfortunate, but not that bad IMO. -- Daniel Wallin Boost Consulting www.boost-consulting.com

on Thu Mar 22 2007, Daniel Wallin <daniel-AT-boost-consulting.com> wrote:
David Abrahams wrote:
on Tue Mar 20 2007, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:
These patches do not need to be applied in any particular order. Applying all three has the effect of making lazy binding behave more like the description in the documentation. I ran the Boost Parameter Library test suite and everything passed. Let me know if I've misunderstood something or if there's a better way to solve this problem or if you'd like additional documentation/tests.
I don't have any suggestions, though maybe Daniel W. does.
I think in general a better solution would be to add a member function to the keyword class template. Maybe:
template <class F> ... lazy(F const& f) {}
As a substitute for op|| ? I would rather call it lazy_default. However, I think the solution is in the lambda library already: http://boost.org/doc/html/lambda/le_in_details.html#lambda.unlambda
And possibly change the docs to not use Boost.Lambda. We're going to hit the same problem with the every lambda library. Changing the implementation is to late for 1.34, but we should probably change the docs so they don't mention Lambda. The example would become:
bind(std::plus<std::string>(), ref(s1), ref(s2))
it's unfortunate, but not that bad IMO.
Is it better not to discuss lambda, or to mention unlambda as a way around this problem? -- Dave Abrahams Boost Consulting www.boost-consulting.com

On 3/22/07, David Abrahams <dave@boost-consulting.com> wrote:
on Thu Mar 22 2007, Daniel Wallin <daniel-AT-boost-consulting.com> wrote:
David Abrahams wrote:
on Tue Mar 20 2007, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:
These patches do not need to be applied in any particular order. Applying all three has the effect of making lazy binding behave more like the description in the documentation. I ran the Boost Parameter Library test suite and everything passed. Let me know if I've misunderstood something or if there's a better way to solve this problem or if you'd like additional documentation/tests.
I don't have any suggestions, though maybe Daniel W. does.
I think in general a better solution would be to add a member function to the keyword class template. Maybe:
template <class F> ... lazy(F const& f) {}
As a substitute for op|| ?
I would rather call it lazy_default.
However, I think the solution is in the lambda library already: http://boost.org/doc/html/lambda/le_in_details.html#lambda.unlambda
Really, users just need to provide a result_of compatible function object. So if the documentation says that more clearly and replaces the lambda example with a bind example, it would alleviate confusion. Unlambda gets rid of the operator|| overload resolution problem, but doesn't generate a lambda compatible functor as far as I know... at least not yet. For 1.34, since users can't use lambda anyway (due to lack of result_of compatibility) there's no need for this patch or renaming op||. In the future, if/when lambda is result_of compatible, keyword::operator|| will need to be renamed or somthing like this patch should be applied. My preference is to keep the current syntax. I kind of like using args[ _arg || default() ] better than args[ _arg.lazy(default()) ], especially if there's still args[ _arg | default() ].
And possibly change the docs to not use Boost.Lambda. We're going to hit the same problem with the every lambda library. Changing the implementation is to late for 1.34, but we should probably change the docs so they don't mention Lambda. The example would become:
bind(std::plus<std::string>(), ref(s1), ref(s2))
it's unfortunate, but not that bad IMO.
Is it better not to discuss lambda, or to mention unlambda as a way around this problem?
For 1.34, yes, I think it's better not to mention it. Daniel

On 3/22/07, Daniel Walker <daniel.j.walker@gmail.com> wrote:
On 3/22/07, David Abrahams <dave@boost-consulting.com> wrote:
However, I think the solution is in the lambda library already: http://boost.org/doc/html/lambda/le_in_details.html#lambda.unlambda
[...]
Unlambda gets rid of the operator|| overload resolution problem, but doesn't generate a lambda compatible functor as far as I know... at least not yet.
I meant unlambda doesn't generate a result_of compatible functor, as far as I know. Sorry. Daniel

on Thu Mar 22 2007, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:
However, I think the solution is in the lambda library already: http://boost.org/doc/html/lambda/le_in_details.html#lambda.unlambda
Really, users just need to provide a result_of compatible function object. So if the documentation says that more clearly and replaces the lambda example with a bind example, it would alleviate confusion.
Unlambda gets rid of the operator|| overload resolution problem, but doesn't generate a lambda compatible functor as far as I know... at least not yet.
For 1.34, since users can't use lambda anyway (due to lack of result_of compatibility)
I don't get it. As mentioned earlier, we automatedly test our examples and that one passed. Any idea why?
there's no need for this patch or renaming op||. In the future, if/when lambda is result_of compatible, keyword::operator|| will need to be renamed or somthing like this patch should be applied. My preference is to keep the current syntax. I kind of like using args[ _arg || default() ] better than args[ _arg.lazy(default()) ], especially if there's still args[ _arg | default() ].
And possibly change the docs to not use Boost.Lambda. We're going to hit the same problem with the every lambda library. Changing the implementation is to late for 1.34, but we should probably change the docs so they don't mention Lambda. The example would become:
bind(std::plus<std::string>(), ref(s1), ref(s2))
it's unfortunate, but not that bad IMO.
Is it better not to discuss lambda, or to mention unlambda as a way around this problem?
For 1.34, yes, I think it's better not to mention it.
I'm open to whatever you and Daniel agree on. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On 3/23/07, David Abrahams <dave@boost-consulting.com> wrote:
on Thu Mar 22 2007, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:
However, I think the solution is in the lambda library already: http://boost.org/doc/html/lambda/le_in_details.html#lambda.unlambda
Really, users just need to provide a result_of compatible function object. So if the documentation says that more clearly and replaces the lambda example with a bind example, it would alleviate confusion.
Unlambda gets rid of the operator|| overload resolution problem, but doesn't generate a lambda compatible functor as far as I know... at least not yet.
For 1.34, since users can't use lambda anyway (due to lack of result_of compatibility)
I don't get it. As mentioned earlier, we automatedly test our examples and that one passed. Any idea why?
I looked in boost/libs/parameter/test and grep lambda returned nothing. I found three tests for lazy binding with operator|| and none used lambda. It looks like lambda was never test. Is there some other way it would have been tested that I'm missing?
there's no need for this patch or renaming op||. In the future, if/when lambda is result_of compatible, keyword::operator|| will need to be renamed or somthing like this patch should be applied. My preference is to keep the current syntax. I kind of like using args[ _arg || default() ] better than args[ _arg.lazy(default()) ], especially if there's still args[ _arg | default() ].
And possibly change the docs to not use Boost.Lambda. We're going to hit the same problem with the every lambda library. Changing the implementation is to late for 1.34, but we should probably change the docs so they don't mention Lambda. The example would become:
bind(std::plus<std::string>(), ref(s1), ref(s2))
it's unfortunate, but not that bad IMO.
Is it better not to discuss lambda, or to mention unlambda as a way around this problem?
For 1.34, yes, I think it's better not to mention it.
I'm open to whatever you and Daniel agree on.
I like the idea of replacing the lambda example with a boost::bind example as Daniel suggested above. Daniel Walker

on Tue Mar 27 2007, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:
On 3/23/07, David Abrahams <dave@boost-consulting.com> wrote:
I don't get it. As mentioned earlier, we automatedly test our examples and that one passed. Any idea why?
I looked in boost/libs/parameter/test and grep lambda returned nothing.
It's not there.
I found three tests for lazy binding with operator|| and none used lambda. It looks like lambda was never test. Is there some other way it would have been tested that I'm missing?
Yes, we have a system (see tools/litre) that allows us to embed testing instructions in the source for our documentation. Actually the process assembles source files and a Jamfile. We then run all the tests in that Jamfile. If you look at the .rst files that document the use of lambda, you can see that those examples are tested.
I'm open to whatever you and Daniel agree on.
I like the idea of replacing the lambda example with a boost::bind example as Daniel suggested above.
Daniel, can you do that? -- Dave Abrahams Boost Consulting www.boost-consulting.com

On 3/27/07, David Abrahams <dave@boost-consulting.com> wrote:
on Tue Mar 27 2007, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:
On 3/23/07, David Abrahams <dave@boost-consulting.com> wrote:
I don't get it. As mentioned earlier, we automatedly test our examples and that one passed. Any idea why?
I looked in boost/libs/parameter/test and grep lambda returned nothing.
It's not there.
I found three tests for lazy binding with operator|| and none used lambda. It looks like lambda was never test. Is there some other way it would have been tested that I'm missing?
Yes, we have a system (see tools/litre) that allows us to embed testing instructions in the source for our documentation. Actually the process assembles source files and a Jamfile. We then run all the tests in that Jamfile. If you look at the .rst files that document the use of lambda, you can see that those examples are tested.
Aha! Litre sounds like a good idea. How are you supposed to run it? I'd like to try to see what happens with the .rst files that document using lambda. Is the litre test a build target in a Jamfile?
I'm open to whatever you and Daniel agree on.
I like the idea of replacing the lambda example with a boost::bind example as Daniel suggested above.
Daniel, can you do that?
You mean Daniel Wallin, not me, right? Daniel

on Thu Apr 05 2007, "Daniel Walker" <daniel.j.walker-AT-gmail.com> wrote:
On 3/27/07, David Abrahams <dave@boost-consulting.com> wrote:
Yes, we have a system (see tools/litre) that allows us to embed testing instructions in the source for our documentation. Actually the process assembles source files and a Jamfile. We then run all the tests in that Jamfile. If you look at the .rst files that document the use of lambda, you can see that those examples are tested.
Aha! Litre sounds like a good idea. How are you supposed to run it?
I have to beg ignorance; I wrote the original thing for testing the examples in "C++ Template Metaprogramming" and Daniel W. made lots of modifications and did the testing for the parameter lib; I don't remember how to use it anymore :-/. Daniel?
I'd like to try to see what happens with the .rst files that document using lambda. Is the litre test a build target in a Jamfile?
Wow; I thought we were checking that stuff in. Ignorance again. Daniel?
I'm open to whatever you and Daniel agree on.
I like the idea of replacing the lambda example with a boost::bind example as Daniel suggested above.
Daniel, can you do that?
You mean Daniel Wallin, not me, right?
Yep. -- Dave Abrahams Boost Consulting www.boost-consulting.com Don't Miss BoostCon 2007! ==> http://www.boostcon.com
participants (3)
-
Daniel Walker
-
Daniel Wallin
-
David Abrahams