Rave for proposed Boost.Local (functions)

Hey everyone, The purpose of this e-mail is to rave about Lorenzo's proposed Boost.Local library in the hopes of inspiring people to start the review process for it. :-) I have been experimenting with using this library in my own code, and it has been a godsend for me. In one of the projects I have been working on I ran into many situations where I needed to call a higher-order function with a closure, and the closure was just complicated enough that I couldn't use Boost.Lambda. Before using this library I frequently found myself either writing a lot of extra code to work-around the need for a higher-order function, or writing a lot of boilerplate to create classes that would only be used by a single function in order to create a function object. This library has let me write the closures that I need in a fairly painless fashion and so has made my life a lot easier! At first I thought that the interface needed to use it was ugly, but as I have gotten used to it I have changed my mind. Part of why I thought it was ugly was because of the way that whitespace was used in the example included in the original e-mail: BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) (bind)((&sum)) ) ) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0); To my mind this example looks a lot clearer if you reformat it as follows: BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) (bind)((&sum)) ) ) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0); I would be happy to volunteer to be the review manager if one is needed to move the process along, but since I am new to the community and personally biased in favor of the library (though I would endeavor to be unbiased as a reviewer) I recognize you all will presumably want someone that you all know better and who is more neutral. Regardless, I hope that we can start down the road of incorporating this library into boost because I believe it would be of great benefit to the C++ community at large. Cheers, Greg

Hi Greg (& Lorenzo), Gregory Crosswhite wrote:
The purpose of this e-mail is to rave about Lorenzo's proposed Boost.Local library in the hopes of inspiring people to start the review process for it. :-)
I have been experimenting with using this library in my own code, and it has been a godsend for me. In one of the projects I have been working on I ran into many situations where I needed to call a higher-order function with a closure, and the closure was just complicated enough that I couldn't use Boost.Lambda. Before using this library I frequently found myself either writing a lot of extra code to work-around the need for a higher-order function, or writing a lot of boilerplate to create classes that would only be used by a single function in order to create a function object. This library has let me write the closures that I need in a fairly painless fashion and so has made my life a lot easier!
Do you have any thoughts about how lambdas in C++0x compare for your problems? I guess I'm thinking, how useful is this going to be in a couple of years when hopefully we all have C++0x compilers? Could this be seen as a sort of "C++0x lambda emulation" library? I don't think it's really quite the same, though... Regards, Phil.

Hi Phil, On 2/1/11 3:52 PM, Phil Endecott wrote:
Do you have any thoughts about how lambdas in C++0x compare for your problems?
Lambdas in C++0x look like they would work just as well for my problems and furthermore would be less verbose, though I haven't experimented with them since I don't have easy access to a compiler that supports them on my Mac laptop.
I guess I'm thinking, how useful is this going to be in a couple of years when hopefully we all have C++0x compilers?
That though had occurred to me as well. However, even in a couple of years there will likely still be lots of places where we will not have access to C++0x lambdas. For example, I have not seen any timeline for when the default OSX build environment will have them, given that they are not going to use any gcc above version 4.2 (due to the license change) and instead are planning to switch to LLVM/Clang, which is still ironing out the bugs in its C++03 support and has barely started on C++0x.
Could this be seen as a sort of "C++0x lambda emulation" library? I don't think it's really quite the same, though...
It offers a few additional features above merely emulating C++0x lambdas. Most significantly, the local functions that it provides are named, which means one can use them at multiple points in a function. It also provides a means to add an extra const annotation to the variables that it captures (which I do as much as possible) to make sure that the local function cannot mutate them even when they are mutable in the parent function, which is a feature not provided by C++0x lambdas. I have not used the other features myself, but it also provides local exits (similar to Boost.ScopeExit, but with the ability to bind the object "this" and to add const annotations to the bound variables) and "local blocks" that allow you to essentially put some of your code in a scope where they can only see a subset of the variables in a function. Cheers, Greg

Gregory Crosswhite wrote:
Hey everyone,
The purpose of this e-mail is to rave about Lorenzo's proposed Boost.Local library in the hopes of inspiring people to start the review process for it. :-)
I have been experimenting with using this library in my own code, and it has been a godsend for me. In one of the projects I have been working on I ran into many situations where I needed to call a higher-order function with a closure, and the closure was just complicated enough that I couldn't use Boost.Lambda. Before using this library I frequently found myself either writing a lot of extra code to work-around the need for a higher-order function, or writing a lot of boilerplate to create classes that would only be used by a single function in order to create a function object. This library has let me write the closures that I need in a fairly painless fashion and so has made my life a lot easier!
I would be interested in what limitations you ran into using Boost.Lambda and if you are aware of the recent efforts that were put into Boost.Phoenix?
To my mind this example looks a lot clearer if you reformat it as follows:
BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) (bind)((&sum)) ) ) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0);
As far is a am concerned, I still find this syntax overly verbose. I do realize though that this is just a toy example. For better comparison, Here is how the same thing would like in Boost.Phoenix: boost::function<void(double)> add =( ref(sum) += factor * _1, std::clog << var("Summed: ") << sum << std::endl ) ; add(100.0); Despite the Local Blocks and Local Exits feature, I can't see much difference to the already existing lambda libraries. I just looked through the Boost.Local documentation and immediately navigated to the "Alternatives" section and its not really correct regarding the features of Boost.Lambda and Boost.Phoenix. I am specifically talking about the "Bind variables in scope" and "Program body using usual C++ syntax" part. The last is debatable, but how are the above examples (both of Boost.Local and Boost.Phoenix) not C++ syntax? Can you highlight the advantages/disadvantages again?
Cheers, Greg _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 2/1/2011 11:00 PM, Thomas Heller wrote:
Gregory Crosswhite wrote:
Hey everyone,
The purpose of this e-mail is to rave about Lorenzo's proposed Boost.Local library in the hopes of inspiring people to start the review process for it. :-) [...] Despite the Local Blocks and Local Exits feature, I can't see much difference to the already existing lambda libraries. I just looked through the Boost.Local documentation and immediately navigated to the "Alternatives" section and its not really correct regarding the features of Boost.Lambda and Boost.Phoenix. I am specifically talking about the "Bind variables in scope" and "Program body using usual C++ syntax" part. The last is debatable, but how are the above examples (both of Boost.Local and Boost.Phoenix) not C++ syntax? Can you highlight the advantages/disadvantages again?
Purely speculating, but I'd guess the difference in compile times could be quite a bit different, especially for more elaborate uses (both in terms of the number of template instantiations and function inlinings as well as the amount of header code to parse through and preprocessor code to expand). If so, do you consider that a "plus" for (proposed) Boost.Local over, e.g., Boost.Phoenix? It *might* also be *possible* that the higher transparency (from the perspective of the compiler) of functions written with (proposed) Boost.Local may give superior (faster, smaller, whatever) compiled code on some compilers than the equivalent in Boost.Phoenix. Obviously, though, I'm sure you (Thomas) along with Eric, Joel, Dan Marsden, and any number of other boosters with vastly more experience in expression template libraries would be better able to assess that possibility. It might help Lorenzo's cause to give specific examples where he (or anyone else) feels the (proposed) Boost.Local construct is superior in some way to the Boost.Phoenix construct. - Jeff

On 02/01/2011 11:24 PM, Jeffrey Lee Hellrung, Jr. wrote:
It might help Lorenzo's cause to give specific examples where he (or anyone else) feels the (proposed) Boost.Local construct is superior in some way to the Boost.Phoenix construct.
Agreed. As a heavy user of Phoenix 2.0 I am unable to see the improvements over existing Phoenix or the anticipate release of 3.0. A list of benefits over existing solutions as well as known limitations would be extremely helpful in determining the relevance of this proposed library. michael -- Michael Caisse Object Modeling Designs www.objectmodelingdesigns.com

On 02/02/2011 08:46, Michael Caisse wrote:
On 02/01/2011 11:24 PM, Jeffrey Lee Hellrung, Jr. wrote:
It might help Lorenzo's cause to give specific examples where he (or anyone else) feels the (proposed) Boost.Local construct is superior in some way to the Boost.Phoenix construct.
Agreed. As a heavy user of Phoenix 2.0 I am unable to see the improvements over existing Phoenix or the anticipate release of 3.0. A list of benefits over existing solutions as well as known limitations would be extremely helpful in determining the relevance of this proposed library.
I can see one clear advantage: error messages are readable.

Mathias Gaunard wrote:
On 02/02/2011 08:46, Michael Caisse wrote:
On 02/01/2011 11:24 PM, Jeffrey Lee Hellrung, Jr. wrote:
It might help Lorenzo's cause to give specific examples where he (or anyone else) feels the (proposed) Boost.Local construct is superior in some way to the Boost.Phoenix construct.
Agreed. As a heavy user of Phoenix 2.0 I am unable to see the improvements over existing Phoenix or the anticipate release of 3.0. A list of benefits over existing solutions as well as known limitations would be extremely helpful in determining the relevance of this proposed library.
I can see one clear advantage: error messages are readable.
To quote the Boost.Local docs: "Warning Unfortunately, there are intrinsic limitations to the amount of syntactic error checking that can be done by the parsing macros implemented using the preprocessor. As a consequence, an error in using the parenthesized syntax might result in cryptic preprocessor errors. The best way to identify and correct these errors is usually to visually inspect the signature comparing it with the parenthesized syntax grammar (see the Grammar section). When syntactic errors can be detected by the parsing macros, they are raised at compile-time using error messages of the form ERROR_description_text."

On 02/02/2011 13:23, Thomas Heller wrote:
To quote the Boost.Local docs: "Warning Unfortunately, there are intrinsic limitations to the amount of syntactic error checking that can be done by the parsing macros implemented using the preprocessor. As a consequence, an error in using the parenthesized syntax might result in cryptic preprocessor errors. The best way to identify and correct these errors is usually to visually inspect the signature comparing it with the parenthesized syntax grammar (see the Grammar section). When syntactic errors can be detected by the parsing macros, they are raised at compile-time using error messages of the form ERROR_description_text."
Enumeration of parameters and bindings is not where code complexity is.

On Wed, Feb 2, 2011 at 6:31 AM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote:
On 02/02/2011 08:46, Michael Caisse wrote:
On 02/01/2011 11:24 PM, Jeffrey Lee Hellrung, Jr. wrote:
It might help Lorenzo's cause to give specific examples where he (or anyone else) feels the (proposed) Boost.Local construct is superior in some way to the Boost.Phoenix construct.
Agreed. As a heavy user of Phoenix 2.0 I am unable to see the improvements over existing Phoenix or the anticipate release of 3.0. A list of benefits over existing solutions as well as known limitations would be extremely helpful in determining the relevance of this proposed library.
I can see one clear advantage: error messages are readable.
That is true for the error within the function body. The function body is normal C++ syntax and it is programmer *outside* the macro programmers get the usual C++ error messages (which might already be cryptic enough ;) ), error line numbers, etc (this is also spelled out as the main Rationale for keeping the body code outside the macro parameters in the library doc). However, errors within the macro when specifying the parenthesized syntax can lead to cryptic preprocessor errors. The macro parser attempt to to so basic syntax checking for the parenthesized syntax but while this error checking could be (and probably should be) improved there are fundamental limitation about what can be done (e.g., there is no way I can gracefully detect and report missing closing parenthesis `)` ). The parenthesized syntax errors which are detected are gracefully reported as compiler-errors using static assertions (BOOST_MPL_ASSERT...). That said, in my experience when you get cryptic preprocessor errors, you take a good look at the parenthesized syntax and you just find the problem, plus after a while you get used to the parenthesized syntax and you just get it right in the first place. This library limitation is well discussed in the library doc. On Wed, Feb 2, 2011 at 5:12 PM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote:
On 02/02/2011 13:23, Thomas Heller wrote:
To quote the Boost.Local docs: "Warning Unfortunately, there are intrinsic limitations to the amount of syntactic error checking that can be done by the parsing macros implemented using the preprocessor. As a consequence, an error in using the parenthesized syntax might result in cryptic preprocessor errors. The best way to identify and correct these errors is usually to visually inspect the signature comparing it with the parenthesized syntax grammar (see the Grammar section). When syntactic errors can be detected by the parsing macros, they are raised at compile-time using error messages of the form ERROR_description_text."
Enumeration of parameters and bindings is not where code complexity is.
Yes, I agree. Most of the complexity of the code is (usually) in the local function definition (normal compiler errors) and not in its declaration (sometimes cryptic preprocessor errors) so in my experience this is an important plus for Boost.Local overall. To people that have experimented with Boost.Local: 1) Did you find it hard to write the parenthesized syntax declarations? 2) Did you find it hard to find and correct eventual parenthesized syntax errors you made? (If so, this I might be able to improve it a bit...) -- Lorenzo

Jeffrey Lee Hellrung, Jr. wrote:
On 2/1/2011 11:00 PM, Thomas Heller wrote:
Gregory Crosswhite wrote:
Hey everyone,
The purpose of this e-mail is to rave about Lorenzo's proposed Boost.Local library in the hopes of inspiring people to start the review process for it. :-) [...] Despite the Local Blocks and Local Exits feature, I can't see much difference to the already existing lambda libraries. I just looked through the Boost.Local documentation and immediately navigated to the "Alternatives" section and its not really correct regarding the features of Boost.Lambda and Boost.Phoenix. I am specifically talking about the "Bind variables in scope" and "Program body using usual C++ syntax" part. The last is debatable, but how are the above examples (both of Boost.Local and Boost.Phoenix) not C++ syntax? Can you highlight the advantages/disadvantages again?
Purely speculating, but I'd guess the difference in compile times could be quite a bit different, especially for more elaborate uses (both in terms of the number of template instantiations and function inlinings as well as the amount of header code to parse through and preprocessor code to expand).
Yes, compile times are kind of a problem right now. (We need bigger machines :P)
If so, do you consider that a "plus" for (proposed) Boost.Local over, e.g., Boost.Phoenix?
(This is a biased statement.) I personally don't like the macros to define Boost.Local functions, they are too verbose. I'd rather pay for higher compile times than having to use these macros. However, for people liking this syntax, lower compile times are an absolute plus over the other ET based lambda libraries.
It *might* also be *possible* that the higher transparency (from the perspective of the compiler) of functions written with (proposed) Boost.Local may give superior (faster, smaller, whatever) compiled code on some compilers than the equivalent in Boost.Phoenix. Obviously, though, I'm sure you (Thomas) along with Eric, Joel, Dan Marsden, and any number of other boosters with vastly more experience in expression template libraries would be better able to assess that possibility.
Expression templates have the same order of visibility than any other header only library. There us no use in discussing a theoretical possibility, we need benchmarks here :)
It might help Lorenzo's cause to give specific examples where he (or anyone else) feels the (proposed) Boost.Local construct is superior in some way to the Boost.Phoenix construct.
That will be highly appreciated.
- Jeff _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On Wed, Feb 2, 2011 at 2:24 AM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
Purely speculating, but I'd guess the difference in compile times could be quite a bit different, especially for more elaborate uses (both in terms of the number of template instantiations and function inlinings as well as the amount of header code to parse through and preprocessor code to expand). If so, do you consider that a "plus" for (proposed) Boost.Local over, e.g., Boost.Phoenix?
It *might* also be *possible* that the higher transparency (from the perspective of the compiler) of functions written with (proposed) Boost.Local may give superior (faster, smaller, whatever) compiled code on some compilers than the equivalent in Boost.Phoenix. Obviously, though, I'm sure you (Thomas) along with Eric, Joel, Dan Marsden, and any number of other boosters with vastly more experience in expression template libraries would be better able to assess that possibility.
Setting a side all of the Local and Phoenix comparisons which have already been discussed enough concluding complementarity of the two libraries as far as local functions are concerned. Unfortunately, I cannot comment on Boost.Local performances. I can only say that *I think* Boost.Local does more or less what Boost.ScopeExit does but I have not studied Boost.Local performances yet. I am posting here the code generated by the macros which might help curious readers in spotting costly operations performed by Boost.Local (if there are any). This of course does not include the preprocessing time. (I hope it's not too much code... just try to get passed the typeof noise at the beginning...) int main() { double sum = 0.0; int factor = 10; // BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) ) expands to: // Determining bound variable types (taken from Boost.ScopeExit). typedef void (*boost_se_tag_0_add36)(int factor ); typedef void (*boost_se_tag_1_add36)(int &sum ); typedef __typeof__(boost::type_of::ensure_obj(boost::scope_exit::aux::wrap( boost::scope_exit::aux::deref(factor, (boost_se_tag_0_add36)0)))) boost_se_wrapped_t_0_add36; typedef boost_se_wrapped_t_0_add36::type boost_se_capture_t_0_add36; typedef __typeof__(boost::type_of::ensure_obj(boost::scope_exit::aux::wrap( boost::scope_exit::aux::deref(&sum, (boost_se_tag_1_add36)0)))) boost_se_wrapped_t_1_add36; typedef boost_se_wrapped_t_1_add36::type boost_se_capture_t_1_add36; struct boost_se_params_t_add36 { typedef boost_se_capture_t_0_add36 boost_se_param_t_0_add36; typedef boost_se_capture_t_1_add36 boost_se_param_t_1_add36; boost::scope_exit::aux::member< boost_se_param_t_0_add36, boost_se_tag_0_add36 > boost_se_param_0_add36; boost::scope_exit::aux::member< boost_se_param_t_1_add36, boost_se_tag_1_add36 > boost_se_param_1_add36; } boost_local_auxXparams_add36 = { { boost::scope_exit::aux::deref(factor, (boost_se_tag_0_add36)0) } , { boost::scope_exit::aux::deref(&sum, (boost_se_tag_1_add36)0) } }; boost::scope_exit::aux::declared< boost::scope_exit::aux::resolve< sizeof(boost_local_auxXargs) >::cmp1<0>::cmp2 > boost_local_auxXargs; boost_local_auxXargs.value = &boost_local_auxXparams_add36; // Functor for the local function. typedef ::boost::local::function_ref< void ( double ) , 0 > boost_local_auxXaddXref; struct boost_local_auxXfunctorXadd : ::boost::local::aux::function_base< void ( double ), 0> { explicit boost_local_auxXfunctorXadd(void* bind_params) : boost_local_auxXparams( (boost_se_params_t_add36*) bind_params) {} void operator()( double num ) { return boost_local_auxXbody( *this , boost_local_auxXparams-> boost_se_param_0_add36.value , boost_local_auxXparams-> boost_se_param_1_add36.value , num ); } private: boost_se_params_t_add36* boost_local_auxXparams; static void boost_local_auxXbody( boost_local_auxXfunctorXadd& add , ::boost::add_const< boost_se_params_t_add36:: boost_se_param_t_0_add36 >::type factor , boost_se_params_t_add36:: boost_se_param_t_1_add36 &sum , double num ) // Programmers' write the local function body. { sum += factor * num; std::clog << "Summed: " << sum << std::endl; } // BOOST_LOCAL_FUNCTION_END(add) expands to: }; boost_local_auxXfunctorXadd boost_local_auxXobjectXadd( boost_local_auxXargs.value); boost_local_auxXaddXref add( boost_local_auxXobjectXadd); // Finally the actual functor... add(100.0); return 0; } -- Lorenzo

On 2/6/2011 9:17 AM, Lorenzo Caminiti wrote: [...]
I am posting here the code generated by the macros which might help curious readers in spotting costly operations performed by Boost.Local (if there are any). This of course does not include the preprocessing time. (I hope it's not too much code... just try to get passed the typeof noise at the beginning...)
Is the use of Boost.Typeof optional? I.e., can I just provide the types of the arguments and bound variables myself?
int main() { double sum = 0.0; int factor = 10;
// BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) ) expands to: // Determining bound variable types (taken from Boost.ScopeExit). typedef void (*boost_se_tag_0_add36)(int factor ); typedef void (*boost_se_tag_1_add36)(int&sum );
Where did sum come from??? I don't see it in the BOOST_LOCAL_FUNCTION( ... ) line...I guess you're *really* showing the expansion of a similar macro invocation, but with sum also bound...?
typedef __typeof__(boost::type_of::ensure_obj(boost::scope_exit::aux::wrap( boost::scope_exit::aux::deref(factor, (boost_se_tag_0_add36)0)))) boost_se_wrapped_t_0_add36; typedef boost_se_wrapped_t_0_add36::type boost_se_capture_t_0_add36; typedef __typeof__(boost::type_of::ensure_obj(boost::scope_exit::aux::wrap( boost::scope_exit::aux::deref(&sum, (boost_se_tag_1_add36)0)))) boost_se_wrapped_t_1_add36; typedef boost_se_wrapped_t_1_add36::type boost_se_capture_t_1_add36;
I have a feeling there should be a typename here when boost_se_wrapped_t_1_add36 is a dependent type...
struct boost_se_params_t_add36 { typedef boost_se_capture_t_0_add36 boost_se_param_t_0_add36; typedef boost_se_capture_t_1_add36 boost_se_param_t_1_add36; boost::scope_exit::aux::member< boost_se_param_t_0_add36, boost_se_tag_0_add36> boost_se_param_0_add36; boost::scope_exit::aux::member< boost_se_param_t_1_add36, boost_se_tag_1_add36> boost_se_param_1_add36; } boost_local_auxXparams_add36 = { { boost::scope_exit::aux::deref(factor, (boost_se_tag_0_add36)0) } , { boost::scope_exit::aux::deref(&sum, (boost_se_tag_1_add36)0) } }; boost::scope_exit::aux::declared< boost::scope_exit::aux::resolve< sizeof(boost_local_auxXargs)>::cmp1<0>::cmp2> boost_local_auxXargs;
Shouldn't the name boost_local_auxXargs have some kind of line number or counter or function name pasted into it to prevent name collision of multiple BOOST_LOCAL_FUNCTION declarations in the same scope?
boost_local_auxXargs.value =&boost_local_auxXparams_add36; // Functor for the local function. typedef ::boost::local::function_ref< void ( double ) , 0> boost_local_auxXaddXref; struct boost_local_auxXfunctorXadd : ::boost::local::aux::function_base< void ( double ), 0> { explicit boost_local_auxXfunctorXadd(void* bind_params) : boost_local_auxXparams( (boost_se_params_t_add36*) bind_params) {}
static_cast ? Just being picky here... ;)
void operator()( double num ) { return boost_local_auxXbody( *this , boost_local_auxXparams-> boost_se_param_0_add36.value , boost_local_auxXparams-> boost_se_param_1_add36.value , num ); } private: boost_se_params_t_add36* boost_local_auxXparams; static void boost_local_auxXbody( boost_local_auxXfunctorXadd& add , ::boost::add_const< boost_se_params_t_add36:: boost_se_param_t_0_add36>::type factor , boost_se_params_t_add36:: boost_se_param_t_1_add36&sum , double num )
// Programmers' write the local function body. { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; }
// BOOST_LOCAL_FUNCTION_END(add) expands to: }; boost_local_auxXfunctorXadd boost_local_auxXobjectXadd( boost_local_auxXargs.value); boost_local_auxXaddXref add( boost_local_auxXobjectXadd); // Finally the actual functor...
add(100.0);
return 0; }
For maintenance purposes, do you plan on providing a brief sketch of the above mechanism (e.g., the main players in the above macro expansion, and the inheritance from function_base and type-erasure to simulate the binding of local functions to template parameters)? I remember you doing an earlier study on the performance impact of using this type erasure (compared to moving the local function to namespace scope and avoid the overhead of the virtual dispatch)...is that included in the documentation? I don't see it from a quick glance... - Jeff

On Sun, Feb 6, 2011 at 3:23 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
On 2/6/2011 9:17 AM, Lorenzo Caminiti wrote: [...]
I am posting here the code generated by the macros which might help curious readers in spotting costly operations performed by Boost.Local (if there are any). This of course does not include the preprocessing time. (I hope it's not too much code... just try to get passed the typeof noise at the beginning...)
Is the use of Boost.Typeof optional? I.e., can I just provide the types of the arguments and bound variables myself?
No but I think you can simply use a normal (not bound) local function parameters to do this: int main() { double sum = 0.0; int factor = 10; BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const int)(factor) (double&)(sum) ) // No binds so no typeof. ) { sum += factor * num; std::clog << "Summed: " << sum << std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0, factor, sum); }
int main() { double sum = 0.0; int factor = 10;
// BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) ) expands to: // Determining bound variable types (taken from Boost.ScopeExit). typedef void (*boost_se_tag_0_add36)(int factor ); typedef void (*boost_se_tag_1_add36)(int&sum );
Where did sum come from??? I don't see it in the BOOST_LOCAL_FUNCTION( ... ) line...I guess you're *really* showing the expansion of a similar macro invocation, but with sum also bound...?
Ooops, I missed it. The code I posted is the expansion of this: int main() { double sum = 0.0; int factor = 10; BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) (bind)((&sum)) ) ) { sum += factor * num; std::clog << "Summed: " << sum << std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0); }
typedef __typeof__(boost::type_of::ensure_obj(boost::scope_exit::aux::wrap( boost::scope_exit::aux::deref(factor, (boost_se_tag_0_add36)0)))) boost_se_wrapped_t_0_add36; typedef boost_se_wrapped_t_0_add36::type boost_se_capture_t_0_add36; typedef __typeof__(boost::type_of::ensure_obj(boost::scope_exit::aux::wrap( boost::scope_exit::aux::deref(&sum, (boost_se_tag_1_add36)0)))) boost_se_wrapped_t_1_add36; typedef boost_se_wrapped_t_1_add36::type boost_se_capture_t_1_add36;
I have a feeling there should be a typename here when boost_se_wrapped_t_1_add36 is a dependent type...
Yes, you use `BOOST_LOCAL_FUNCTION_TPL` in dependent type contexts (from within templates, etc) which adds the typenames. (It's in the docs.)
struct boost_se_params_t_add36 { typedef boost_se_capture_t_0_add36 boost_se_param_t_0_add36; typedef boost_se_capture_t_1_add36 boost_se_param_t_1_add36; boost::scope_exit::aux::member< boost_se_param_t_0_add36, boost_se_tag_0_add36> boost_se_param_0_add36; boost::scope_exit::aux::member< boost_se_param_t_1_add36, boost_se_tag_1_add36> boost_se_param_1_add36; } boost_local_auxXparams_add36 = { { boost::scope_exit::aux::deref(factor, (boost_se_tag_0_add36)0) } , { boost::scope_exit::aux::deref(&sum, (boost_se_tag_1_add36)0) } }; boost::scope_exit::aux::declared< boost::scope_exit::aux::resolve< sizeof(boost_local_auxXargs)>::cmp1<0>::cmp2> boost_local_auxXargs;
Shouldn't the name boost_local_auxXargs have some kind of line number or counter or function name pasted into it to prevent name collision of multiple BOOST_LOCAL_FUNCTION declarations in the same scope?
No, this has to be a global extern variable declared as: extern boost::scope_exit::aux::undeclared boost_local_auxXargs; in one of Boost.Local headers. It's a trick carried over 100% from Boost.ScopeExit (as I understand it, this is because only global or static variables can be used from within a nested block http://lists.boost.org/Archives/boost/2006/11/113658.php).
boost_local_auxXargs.value =&boost_local_auxXparams_add36; // Functor for the local function. typedef ::boost::local::function_ref< void ( double ) , 0> boost_local_auxXaddXref; struct boost_local_auxXfunctorXadd : ::boost::local::aux::function_base< void ( double ), 0> { explicit boost_local_auxXfunctorXadd(void* bind_params) : boost_local_auxXparams( (boost_se_params_t_add36*) bind_params) {}
static_cast ? Just being picky here... ;)
Ooops, again. I'll fix this C-style cast (it probably was a quick piece of code that I then forgot to go back and fix). Thanks.
void operator()( double num ) { return boost_local_auxXbody( *this , boost_local_auxXparams-> boost_se_param_0_add36.value , boost_local_auxXparams-> boost_se_param_1_add36.value , num ); } private: boost_se_params_t_add36* boost_local_auxXparams; static void boost_local_auxXbody( boost_local_auxXfunctorXadd& add , ::boost::add_const< boost_se_params_t_add36:: boost_se_param_t_0_add36>::type factor , boost_se_params_t_add36:: boost_se_param_t_1_add36&sum , double num )
// Programmers' write the local function body. { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; }
// BOOST_LOCAL_FUNCTION_END(add) expands to: }; boost_local_auxXfunctorXadd boost_local_auxXobjectXadd( boost_local_auxXargs.value); boost_local_auxXaddXref add( boost_local_auxXobjectXadd); // Finally the actual functor...
add(100.0);
return 0; }
For maintenance purposes, do you plan on providing a brief sketch of the above mechanism (e.g., the main players in the above macro expansion, and the inheritance from function_base and type-erasure to simulate the binding of local functions to template parameters)?
Yes, I can add an Appendix with the pseudo code in the library docs.
I remember you doing an earlier study on the performance impact of using this type erasure (compared to moving the local function to namespace scope and avoid the overhead of the virtual dispatch)...is that included in the documentation? I don't see it from a quick glance...
A preliminary study was hinted by John Bytheway (http://lists.boost.org/Archives/boost/2010/09/170891.php). I have not done any performance study of Boost.Local yet (yes, I will include performance considerations in the docs once I do them). -- Lorenzo

On 2/6/2011 5:46 PM, Lorenzo Caminiti wrote:
On Sun, Feb 6, 2011 at 3:23 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
On 2/6/2011 9:17 AM, Lorenzo Caminiti wrote: [...]
I am posting here the code generated by the macros which might help curious readers in spotting costly operations performed by Boost.Local (if there are any). This of course does not include the preprocessing time. (I hope it's not too much code... just try to get passed the typeof noise at the beginning...)
Is the use of Boost.Typeof optional? I.e., can I just provide the types of the arguments and bound variables myself?
No but I think you can simply use a normal (not bound) local function parameters to do this: [...]
So Boost.Typeof is necessary to bind variables...? [...]
boost::scope_exit::aux::declared< boost::scope_exit::aux::resolve< sizeof(boost_local_auxXargs)>::cmp1<0>::cmp2> boost_local_auxXargs;
Shouldn't the name boost_local_auxXargs have some kind of line number or counter or function name pasted into it to prevent name collision of multiple BOOST_LOCAL_FUNCTION declarations in the same scope?
No, this has to be a global extern variable declared as:
extern boost::scope_exit::aux::undeclared boost_local_auxXargs;
in one of Boost.Local headers. It's a trick carried over 100% from Boost.ScopeExit (as I understand it, this is because only global or static variables can be used from within a nested block http://lists.boost.org/Archives/boost/2006/11/113658.php).
Ugh, okay ;) Will read the link. [...]
For maintenance purposes, do you plan on providing a brief sketch of the above mechanism (e.g., the main players in the above macro expansion, and the inheritance from function_base and type-erasure to simulate the binding of local functions to template parameters)?
Yes, I can add an Appendix with the pseudo code in the library docs.
Excellent.
I remember you doing an earlier study on the performance impact of using this type erasure (compared to moving the local function to namespace scope and avoid the overhead of the virtual dispatch)...is that included in the documentation? I don't see it from a quick glance...
A preliminary study was hinted by John Bytheway (http://lists.boost.org/Archives/boost/2010/09/170891.php). I have not done any performance study of Boost.Local yet (yes, I will include performance considerations in the docs once I do them).
This must be what I remembered. - Jeff

On Sun, Feb 6, 2011 at 11:09 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
On 2/6/2011 5:46 PM, Lorenzo Caminiti wrote:
On Sun, Feb 6, 2011 at 3:23 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
On 2/6/2011 9:17 AM, Lorenzo Caminiti wrote: [...]
I am posting here the code generated by the macros which might help curious readers in spotting costly operations performed by Boost.Local (if there are any). This of course does not include the preprocessing time. (I hope it's not too much code... just try to get passed the typeof noise at the beginning...)
Is the use of Boost.Typeof optional? I.e., can I just provide the types of the arguments and bound variables myself?
No but I think you can simply use a normal (not bound) local function parameters to do this:
[...]
So Boost.Typeof is necessary to bind variables...?
Yes. Boost.Typeof is only used to automatically deduce the type of the bound variables. I will double check that if you bind no variable then no typeof code is generated by the macros. -- Lorenzo

AMDG On 2/6/2011 8:09 PM, Jeffrey Lee Hellrung, Jr. wrote:
On 2/6/2011 5:46 PM, Lorenzo Caminiti wrote:
On Sun, Feb 6, 2011 at 3:23 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
On 2/6/2011 9:17 AM, Lorenzo Caminiti wrote: [...]
boost::scope_exit::aux::declared< boost::scope_exit::aux::resolve< sizeof(boost_local_auxXargs)>::cmp1<0>::cmp2> boost_local_auxXargs;
Shouldn't the name boost_local_auxXargs have some kind of line number or counter or function name pasted into it to prevent name collision of multiple BOOST_LOCAL_FUNCTION declarations in the same scope?
No, this has to be a global extern variable declared as:
extern boost::scope_exit::aux::undeclared boost_local_auxXargs;
in one of Boost.Local headers. It's a trick carried over 100% from Boost.ScopeExit (as I understand it, this is because only global or static variables can be used from within a nested block http://lists.boost.org/Archives/boost/2006/11/113658.php).
Ugh, okay ;) Will read the link.
That link isn't very relevant. This code is one of the most awful hacks around. Basically, it takes advantage of the template argument list/ comparison operator ambiguity to declare a variable iff it hasn't already been declared in that scope. The second occurrence is parsed as (boost::scope_exit::aux::declared< (boost::scope_exit::aux::resolve< sizeof(boost_local_auxXargs)>::cmp1 < 0)>::cmp2 > boost_local_auxXargs); which is a no-op. In Christ, Steven Watanabe

On 2/6/2011 8:45 PM, Steven Watanabe wrote:
AMDG
On 2/6/2011 8:09 PM, Jeffrey Lee Hellrung, Jr. wrote:
On 2/6/2011 5:46 PM, Lorenzo Caminiti wrote:
On Sun, Feb 6, 2011 at 3:23 PM, Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> wrote:
On 2/6/2011 9:17 AM, Lorenzo Caminiti wrote: [...]
boost::scope_exit::aux::declared< boost::scope_exit::aux::resolve< sizeof(boost_local_auxXargs)>::cmp1<0>::cmp2> boost_local_auxXargs;
Shouldn't the name boost_local_auxXargs have some kind of line number or counter or function name pasted into it to prevent name collision of multiple BOOST_LOCAL_FUNCTION declarations in the same scope?
No, this has to be a global extern variable declared as:
extern boost::scope_exit::aux::undeclared boost_local_auxXargs;
in one of Boost.Local headers. It's a trick carried over 100% from Boost.ScopeExit (as I understand it, this is because only global or static variables can be used from within a nested block http://lists.boost.org/Archives/boost/2006/11/113658.php).
Ugh, okay ;) Will read the link.
That link isn't very relevant. This code is one of the most awful hacks around. Basically, it takes advantage of the template argument list/ comparison operator ambiguity to declare a variable iff it hasn't already been declared in that scope.
The second occurrence is parsed as
(boost::scope_exit::aux::declared< (boost::scope_exit::aux::resolve< sizeof(boost_local_auxXargs)>::cmp1 < 0)>::cmp2 > boost_local_auxXargs);
which is a no-op.
In Christ, Steven Watanabe
Ummm...wow. Thanks Steven. At the risk of being off-topic, I strongly feel compelled to ask some follow-up questions... As I understand it, the first occurrence within a given scope is parsed as boost::scope_exit::aux::declared< boost::scope_exit::aux::resolve< sizeof( boost_local_auxXargs ) >::cmp1< 0 >::cmp2
boost_local_auxXargs;
which is a declaration of a variable called boost_local_auxXargs in local scope which *hides* the variable of the same name from the global scope. Thus all subsequent references to boost_local_auxXargs in this scope refer to this variable. But I don't really understand how the extern global declaration ties into this, except...it gives sizeof( boost_local_auxXargs ) meaning...? Why is the extern keyword necessary in the global declaration? Wouldn't something like const boost::scope_exit::aux::undeclared boost_local_auxXargs = { }; (at global scope) suffice? As Steven explained, the second occurence within a scope is parsed as (rearranging the formatting a little) (boost::scope_exit::aux::declared< (boost::scope_exit::aux::resolve< sizeof( boost_local_auxXargs ) >::cmp1 < 0)
::cmp2) > boost_local_auxXargs;
which amounts some greater-than comparison between boost::scope_exit::aux::declared< ... >::cmp2 and boost_local_auxXargs (presumably overloaded to be a no-op). So what precisely is it about the second occurrence that causes it to be parsed differently? Is the rule (roughly) that if there is an ambiguity, try parsing as if it's a variable declaration, and if that fails (for any of a number of reasons, one of which is the variable has already been declared in *this* scope), then try an alternative parse? What is the logic one goes through to parse this expression? Looking back at the macro expansion Lorenzo supplied, it seems the only use for this boost_local_auxXargs variable is to hold a definite reference to the bound variables struct to be used within BOOST_LOCAL_FUNCTION_END( xxx ). I can see the necessity of this for BOOST_SCOPE_EXIT_END, but BOOST_LOCAL_FUNCTION_END has the name of the local function passed to it, which should be unique to the scope, hence could be used to construct a unique name for the reference to the bound variables struct. So it seems this "awful hack" wouldn't be necessary for (proposed) Boost.Local. Am I missing something? Again, apologies if this is too off-topic, but Steven's explanation really put a "WTF" look on my face (directed toward this "awful hack", not Steven). - Jeff

AMDG On 2/7/2011 12:42 AM, Jeffrey Lee Hellrung, Jr. wrote:
At the risk of being off-topic, I strongly feel compelled to ask some follow-up questions...
As I understand it, the first occurrence within a given scope is parsed as
boost::scope_exit::aux::declared< boost::scope_exit::aux::resolve< sizeof( boost_local_auxXargs )
::cmp1< 0 >::cmp2 boost_local_auxXargs;
which is a declaration of a variable called boost_local_auxXargs in local scope which *hides* the variable of the same name from the global scope. Thus all subsequent references to boost_local_auxXargs in this scope refer to this variable. But I don't really understand how the extern global declaration ties into this, except...it gives sizeof( boost_local_auxXargs ) meaning...?
The first time through, sizeof(boost_local_auxXargs) refers to the global. Afterward, it refers to a local variable. The two types are designed to have different sizes. resolve is specialized to trigger the correct parse. resolve<>::cmp1 is a template the first time and an int subsequently.
Why is the extern keyword necessary in the global declaration? Wouldn't something like
const boost::scope_exit::aux::undeclared boost_local_auxXargs = { };
(at global scope) suffice?
It would, but extern avoids actually creating the variable. It's only used in sizeof, so it doesn't actually have to exist.
<snip>
Looking back at the macro expansion Lorenzo supplied, it seems the only use for this boost_local_auxXargs variable is to hold a definite reference to the bound variables struct to be used within BOOST_LOCAL_FUNCTION_END( xxx ). I can see the necessity of this for BOOST_SCOPE_EXIT_END, but BOOST_LOCAL_FUNCTION_END has the name of the local function passed to it, which should be unique to the scope, hence could be used to construct a unique name for the reference to the bound variables struct. So it seems this "awful hack" wouldn't be necessary for (proposed) Boost.Local. Am I missing something?
You're not missing anything. The hack was only introduced to avoid having to use a name in scope_exit, like in Boost.Local.
Again, apologies if this is too off-topic, but Steven's explanation really put a "WTF" look on my face (directed toward this "awful hack", not Steven).
In Christ, Steven Watanabe

On Mon, Feb 7, 2011 at 11:42 AM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
On 2/7/2011 12:42 AM, Jeffrey Lee Hellrung, Jr. wrote:
Looking back at the macro expansion Lorenzo supplied, it seems the only use for this boost_local_auxXargs variable is to hold a definite reference to the bound variables struct to be used within BOOST_LOCAL_FUNCTION_END( xxx ). I can see the necessity of this for BOOST_SCOPE_EXIT_END, but BOOST_LOCAL_FUNCTION_END has the name of the local function passed to it, which should be unique to the scope, hence could be used to construct a unique name for the reference to the bound variables struct. So it seems this "awful hack" wouldn't be necessary for (proposed) Boost.Local. Am I missing something?
You're not missing anything. The hack was only introduced to avoid having to use a name in scope_exit, like in Boost.Local.
OK, I will study if this hack is needed for Boost.Local or not (I think, it might in order to support BOOST_LOCAL_FUNCTION_END_RENAME which is actually the one used by BOOST_LOCAL_BLOCK_END and BOOST_LOCAL_EXIT_END but I need to go back and check the code). -- Lorenzo

Thomas Heller wrote:
I would be interested in what limitations you ran into using Boost.Lambda and if you are aware of the recent efforts that were put into Boost.Phoenix?
To my mind this example looks a lot clearer if you reformat it as follows:
BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) (bind)((&sum)) ) ) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0);
As far is a am concerned, I still find this syntax overly verbose. I do realize though that this is just a toy example. For better comparison, Here is how the same thing would like in Boost.Phoenix:
boost::function<void(double)> add =( ref(sum) += factor * _1, std::clog << var("Summed: ") << sum << std::endl ) ; add(100.0);
but how are the above examples (both of Boost.Local and Boost.Phoenix) not C++ syntax?
Well, to spell out the obvious, the way that the Boost.Local code terminates statements with ';' while the Pheonix code uses ',' is a reasonably good example of "normal" vs. "obfuscated" syntax. Then there is all the replacement of keywords, changing of brackets, numbered vs. named parameters, and extra bits of fluff like ref() and bind(). No doubt it seems like second-nature once you are used to it, but I'd much prefer to use "normal" C++ syntax to write lambdas if I can. Again, since the future is no doubt C++0x lambdas, should we be trying to converge towards that? I.e. choosing whatever approach has the closest syntax to that? Regards, Phil.

Phil Endecott wrote:
Thomas Heller wrote:
I would be interested in what limitations you ran into using Boost.Lambda and if you are aware of the recent efforts that were put into Boost.Phoenix?
To my mind this example looks a lot clearer if you reformat it as follows:
BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) (bind)((&sum)) ) ) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0);
As far is a am concerned, I still find this syntax overly verbose. I do realize though that this is just a toy example. For better comparison, Here is how the same thing would like in Boost.Phoenix:
boost::function<void(double)> add =( ref(sum) += factor * _1, std::clog << var("Summed: ") << sum << std::endl ) ; add(100.0);
but how are the above examples (both of Boost.Local and Boost.Phoenix) not C++ syntax?
Well, to spell out the obvious, the way that the Boost.Local code terminates statements with ';' while the Pheonix code uses ',' is a reasonably good example of "normal" vs. "obfuscated" syntax. Then there is all the replacement of keywords, changing of brackets, numbered vs. named parameters, and extra bits of fluff like ref() and bind(). No doubt it seems like second-nature once you are used to it, but I'd much prefer to use "normal" C++ syntax to write lambdas if I can.
Point taken. OTOH the macros used to define the local functions are not even close to those of either C++0x lambdas or regular C++ functions. The "fluff" and "obfuscated" syntax you find in Phoenix et al in the body of the expressions, was shifted in Boost.Local to the function decelerator.
Again, since the future is no doubt C++0x lambdas, should we be trying to converge towards that? I.e. choosing whatever approach has the closest syntax to that?
1) It is, IMHO, not only a matter of the syntax used in the body of the statements (regular C++ with Boost.Local vs. stylized, emulated C++ in Boost.Phoenix). It is how the general usecase is, which is probably a inplace definition of some unnamed function, to be used in some std algorithm, as callback in for example boost.asio etc. Boost.Local unfortunately can not deliver that inplace definition: Boost.Local: BOOST_LOCAL_FUNCTION(...) {}BOOST_LOCAL_FUNCTION_END(...) std::for_each(v.begin(), v.end(), ...); C++0x lambdas, Boost.Bind, Boost.Lambda and Boost.Phoenix: std::for_each(v.begin(), v.end(), some_lambda_expression); 2) Even though C++0x will support unnamed functions as a language feature, Boost.Phoenix will not become obsolete. Quite the opposite, Boost.Phoenix offers a lot of advantages over C++0x lambdas. (Forgive me if I won't go into detail here about that, this thread is about Boost.Local) Whereas Boost.Local are just a complicated way to express what can be done with C++0x lambdas, I see no real advantage of Boost.Local over C++0x lambdas. Regards, Thomas

On 02/02/2011 13:21, Thomas Heller wrote:
Point taken. OTOH the macros used to define the local functions are not even close to those of either C++0x lambdas or regular C++ functions.
I find them pretty close to both, except you need to explicitly enumerate variables you wish to bind. (C++0x lambdas do it do, but also have a mode where it captures everything)
The "fluff" and "obfuscated" syntax you find in Phoenix et al in the body of the expressions, was shifted in Boost.Local to the function decelerator.
Right, and that's a good thing. The body of a function is its important part; that's what you want to be lightweight, clear, expressive and debuggable. The syntax to declare a local (I think nested would be a better name) function is not much more different than the one to define a regular monomorphic function, except you have to take care of capturing scope manually. I can tell from experience that I often end up writing by hand the very function objects that Boost.Local can automatically generate.
2) Even though C++0x will support unnamed functions as a language feature, Boost.Phoenix will not become obsolete. Quite the opposite, Boost.Phoenix offers a lot of advantages over C++0x lambdas. (Forgive me if I won't go into detail here about that, this thread is about Boost.Local) Whereas Boost.Local are just a complicated way to express what can be done with C++0x lambdas, I see no real advantage of Boost.Local over C++0x lambdas.
As far as I can see, there are few restriction compared to the equivalent C++0x lambdas: - creating a local can only be done at statement scope. - locals may not automatically capture all context - size of a local function cannot be optimized to be two words. Let's compare Phoenix and that library and C++0x lambdas for a minute. Both C++0x lambdas and Boost.Local are better than Boost.Phoenix on several points. Doing anything non-trivial with Phoenix requires creating lazy functions beforehand (typically done at namespace scope). The fact that Phoenix itself bundles many lazy functions for any other container member and standard algorithm (for a total of 4,000 lines of code for that task alone) is testament to that; you can't really work with it otherwise. Bind and ->* can help to an extent (at the price of high verbosity), but if you want polymorphic behaviour (or don't want to specify manually all types involved) with template functions or members, you can't use those. This severely restricts Boost.Phoenix to being either used as a toy, or in a limited sub-world of C++ where naked classes, structures and functions don't exist, unless they've been adapted or wrapped to be used with it. On the other hand, C++0x lambdas can use arbitrary C++ syntax, and Boost.Local likewise, which means they can readily integrate in any source code. They cannot be polymorphic, but if that restriction were to be removed (through support for template member functions of local structures or otherwise), then the use for Phoenix would be even more limited. I see Boost.Local as merely an emulation for C++0x-like lambdas; it can be used to make code compatible with C++03. In truth, I believe Boost.Local is useful to a much broader audience than Phoenix, and is therefore as worthy of being a Boost library. There is also a lot of precedent in libraries that allow C++0x features in C++03.

On 2/3/11 7:13 AM, Mathias Gaunard wrote:
Doing anything non-trivial with Phoenix requires creating lazy functions beforehand (typically done at namespace scope). The fact that Phoenix itself bundles many lazy functions for any other container member and standard algorithm (for a total of 4,000 lines of code for that task alone) is testament to that; you can't really work with it otherwise.
If you unwrap the macros from Boost.Local, something like a Phoenix.function will emerge. So, why not just provide a phoenix macro to give you the same level of verbosity and the same level of debuggability and c++ syntax error handling? It is trivial to write such a macro in phoenix. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On 03/02/2011 01:19, Joel de Guzman wrote:
On 2/3/11 7:13 AM, Mathias Gaunard wrote:
Doing anything non-trivial with Phoenix requires creating lazy functions beforehand (typically done at namespace scope). The fact that Phoenix itself bundles many lazy functions for any other container member and standard algorithm (for a total of 4,000 lines of code for that task alone) is testament to that; you can't really work with it otherwise.
If you unwrap the macros from Boost.Local, something like a Phoenix.function will emerge. So, why not just provide a phoenix macro to give you the same level of verbosity and the same level of debuggability and c++ syntax error handling?
It is trivial to write such a macro in phoenix.
Consider I want to write a function that does _1.foo(_2.bar()) + _3.baz. If I did as you suggested, I would end up writing three macro invocations before finally being able to write a readable phoenix expression. shortest syntax possible in C++03 -- return type could be avoided in C++0x -- (with Tn to be replaced by actual types): SHORT_FUNCTION(T2, foo, (T0 a, T1 b), a.foo(b)) SHORT_FUNCTION(T1, bar, (T3 a), a.bar()) SHORT_FUNCTION(T2, baz, (T4 a), a.baz) auto f = foo(_1, bar(_2)) + baz(3); I might as well write: SHORT_FUNCTION(T2, f, (T0 a, T3 b, T4 c), a.foo(b.bar()) + c.baz) Note I don't even have to specify T1 here. I could have written the expression as this though (not sure if I remember the right syntax): SHORT_FUNCTION(T2, foo, (T0 a, T1 b), a.foo(b)) auto f = foo(_1, (_2->*&T2::bar)()) + (_3->*&T3::baz)(); but not only is that verbose, I still need to define a foo lazy function because T0::foo could be overloaded (casting to select the right overload is even more horrible than the ->* syntax). Now, let's consider another case, I want to do a.foo(b.bar()) + c.baz, but with a, b, and c taken from the scope, and I don't want to have to specify the types of a, b, and c. I can't do that in Phoenix without defining the foo, bar and baz functions at namespace scope, since they must have a template operator(), which is only allowed at that level. I can, however, do that with no problem with Boost.Local.

On 2/3/2011 5:44 PM, Mathias Gaunard wrote:
On 03/02/2011 01:19, Joel de Guzman wrote:
On 2/3/11 7:13 AM, Mathias Gaunard wrote:
Doing anything non-trivial with Phoenix requires creating lazy functions beforehand (typically done at namespace scope). The fact that Phoenix itself bundles many lazy functions for any other container member and standard algorithm (for a total of 4,000 lines of code for that task alone) is testament to that; you can't really work with it otherwise.
If you unwrap the macros from Boost.Local, something like a Phoenix.function will emerge. So, why not just provide a phoenix macro to give you the same level of verbosity and the same level of debuggability and c++ syntax error handling?
It is trivial to write such a macro in phoenix.
Consider I want to write a function that does _1.foo(_2.bar()) + _3.baz.
If I did as you suggested, I would end up writing three macro invocations before finally being able to write a readable phoenix expression.
shortest syntax possible in C++03 -- return type could be avoided in C++0x -- (with Tn to be replaced by actual types):
SHORT_FUNCTION(T2, foo, (T0 a, T1 b), a.foo(b)) SHORT_FUNCTION(T1, bar, (T3 a), a.bar()) SHORT_FUNCTION(T2, baz, (T4 a), a.baz)
auto f = foo(_1, bar(_2)) + baz(3);
I might as well write:
SHORT_FUNCTION(T2, f, (T0 a, T3 b, T4 c), a.foo(b.bar()) + c.baz)
Note I don't even have to specify T1 here.
I could have written the expression as this though (not sure if I remember the right syntax):
SHORT_FUNCTION(T2, foo, (T0 a, T1 b), a.foo(b)) auto f = foo(_1, (_2->*&T2::bar)()) + (_3->*&T3::baz)();
but not only is that verbose, I still need to define a foo lazy function because T0::foo could be overloaded (casting to select the right overload is even more horrible than the ->* syntax).
Now, let's consider another case, I want to do a.foo(b.bar()) + c.baz, but with a, b, and c taken from the scope, and I don't want to have to specify the types of a, b, and c. I can't do that in Phoenix without defining the foo, bar and baz functions at namespace scope, since they must have a template operator(), which is only allowed at that level. I can, however, do that with no problem with Boost.Local.
Well, you have seen nothing yet ;-) Regards, -- Joel de Guzman http://www.boostpro.com http://boost-spirit.com

Joel de Guzman wrote:
On 2/3/2011 5:44 PM, Mathias Gaunard wrote:
On 03/02/2011 01:19, Joel de Guzman wrote:
On 2/3/11 7:13 AM, Mathias Gaunard wrote:
Doing anything non-trivial with Phoenix requires creating lazy functions beforehand (typically done at namespace scope). The fact that Phoenix itself bundles many lazy functions for any other container member and standard algorithm (for a total of 4,000 lines of code for that task alone) is testament to that; you can't really work with it otherwise.
If you unwrap the macros from Boost.Local, something like a Phoenix.function will emerge. So, why not just provide a phoenix macro to give you the same level of verbosity and the same level of debuggability and c++ syntax error handling?
It is trivial to write such a macro in phoenix.
Consider I want to write a function that does _1.foo(_2.bar()) + _3.baz.
If I did as you suggested, I would end up writing three macro invocations before finally being able to write a readable phoenix expression.
shortest syntax possible in C++03 -- return type could be avoided in C++0x -- (with Tn to be replaced by actual types):
SHORT_FUNCTION(T2, foo, (T0 a, T1 b), a.foo(b)) SHORT_FUNCTION(T1, bar, (T3 a), a.bar()) SHORT_FUNCTION(T2, baz, (T4 a), a.baz)
auto f = foo(_1, bar(_2)) + baz(3);
I might as well write:
SHORT_FUNCTION(T2, f, (T0 a, T3 b, T4 c), a.foo(b.bar()) + c.baz)
Note I don't even have to specify T1 here.
I could have written the expression as this though (not sure if I remember the right syntax):
SHORT_FUNCTION(T2, foo, (T0 a, T1 b), a.foo(b)) auto f = foo(_1, (_2->*&T2::bar)()) + (_3->*&T3::baz)();
but not only is that verbose, I still need to define a foo lazy function because T0::foo could be overloaded (casting to select the right overload is even more horrible than the ->* syntax).
Now, let's consider another case, I want to do a.foo(b.bar()) + c.baz, but with a, b, and c taken from the scope, and I don't want to have to specify the types of a, b, and c. I can't do that in Phoenix without defining the foo, bar and baz functions at namespace scope, since they must have a template operator(), which is only allowed at that level. I can, however, do that with no problem with Boost.Local.
Well, you have seen nothing yet ;-)
http://svn.boost.org/svn/boost/sandbox/SOC/2010/phoenix3/libs/phoenix/doc/ht... A boilerplate macro for that would be a very welcome contribution... Let's start to concentrate on more important things right now, OK? We all know that Boost.Phoenix has certain limitations and drawbacks, the problem you, Mathias, described above is one of them.
Regards,

On 03/02/2011 16:45, Thomas Heller wrote:
Now, let's consider another case, I want to do a.foo(b.bar()) + c.baz, but with a, b, and c taken from the scope, and I don't want to have to specify the types of a, b, and c. I can't do that in Phoenix without defining the foo, bar and baz functions at namespace scope, since they must have a template operator(), which is only allowed at that level. I can, however, do that with no problem with Boost.Local.
Well, you have seen nothing yet ;-)
http://svn.boost.org/svn/boost/sandbox/SOC/2010/phoenix3/libs/phoenix/doc/ht... A boilerplate macro for that would be a very welcome contribution...
All of this still needs to happen at namespace scope. The problem with declaring those things at namespace scope is that they necessarily become far away from the lambda function you want to write.

Le 04/02/2011 16:12, Mathias Gaunard a écrit :
All of this still needs to happen at namespace scope. The problem with declaring those things at namespace scope is that they necessarily become far away from the lambda function you want to write.
AFAIK, this will no longer be true with C++1x, and already false with some compilers. -- Loïc

On 04/02/2011 23:04, Loïc Joly wrote:
Le 04/02/2011 16:12, Mathias Gaunard a écrit :
All of this still needs to happen at namespace scope. The problem with declaring those things at namespace scope is that they necessarily become far away from the lambda function you want to write.
AFAIK, this will no longer be true with C++1x, and already false with some compilers.
I believe you are wrongly informed. What C++0x allows is for local and unnamed types to be used as template arguments, which is unrelated. A local class still can't have a template member function.

Le 05/02/2011 00:43, Mathias Gaunard a écrit :
On 04/02/2011 23:04, Loïc Joly wrote:
Le 04/02/2011 16:12, Mathias Gaunard a écrit :
All of this still needs to happen at namespace scope. The problem with declaring those things at namespace scope is that they necessarily become far away from the lambda function you want to write.
AFAIK, this will no longer be true with C++1x, and already false with some compilers.
I believe you are wrongly informed. What C++0x allows is for local and unnamed types to be used as template arguments, which is unrelated. A local class still can't have a template member function.
Ah, this is what I had in mind... Thank you for correcting me, I knew I was missing something, but did not know what... -- Loïc

On 03/02/2011 16:45, Thomas Heller wrote:
Now, let's consider another case, I want to do a.foo(b.bar()) + c.baz, but with a, b, and c taken from the scope, and I don't want to have to specify the types of a, b, and c. I can't do that in Phoenix without defining the foo, bar and baz functions at namespace scope, since they must have a template operator(), which is only allowed at that level. I can, however, do that with no problem with Boost.Local.
Well, you have seen nothing yet
http://svn.boost.org/svn/boost/sandbox/SOC/2010/phoenix3/libs/phoenix/doc/ht...
Mathias Gaunard <mathias.gaunard <at> ens-lyon.org> writes: phoenix/inside/extending_actors.html
A boilerplate macro for that would be a very welcome contribution...
All of this still needs to happen at namespace scope.
Sure it would. The point of this exercise was to adapt some "old style" C++ class to be used in a phoenix expression. Much in the fashion of BOOST_FUSION_ADAPT_STRUCT. Since you complained about using member functions in a phoenix expression is a pain ...
The problem with declaring those things at namespace scope is that they necessarily become far away from the lambda function you want to write.
Arguing like that disqualifies every library, since the defintion of the functions you want to use is _very_ far away... I don't see a point in that argument.

On 2/5/11 7:40 PM, Thomas Heller wrote:
On 03/02/2011 16:45, Thomas Heller wrote:
Now, let's consider another case, I want to do a.foo(b.bar()) + c.baz, but with a, b, and c taken from the scope, and I don't want to have to specify the types of a, b, and c. I can't do that in Phoenix without defining the foo, bar and baz functions at namespace scope, since they must have a template operator(), which is only allowed at that level. I can, however, do that with no problem with Boost.Local.
Well, you have seen nothing yet
http://svn.boost.org/svn/boost/sandbox/SOC/2010/phoenix3/libs/phoenix/doc/ht...
Mathias Gaunard<mathias.gaunard<at> ens-lyon.org> writes: phoenix/inside/extending_actors.html
A boilerplate macro for that would be a very welcome contribution...
All of this still needs to happen at namespace scope.
Sure it would. The point of this exercise was to adapt some "old style" C++ class to be used in a phoenix expression. Much in the fashion of BOOST_FUSION_ADAPT_STRUCT. Since you complained about using member functions in a phoenix expression is a pain ...
The problem with declaring those things at namespace scope is that they necessarily become far away from the lambda function you want to write.
Arguing like that disqualifies every library, since the defintion of the functions you want to use is _very_ far away... I don't see a point in that argument.
I think his argument is that with lambda expressions, the code is at the call site. However, I'd also argue that for more complex code spanning several statements, it is good practice to refactor them into their own functions. Overly complex lambda functions are a poor form. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On 05/02/2011 13:42, Joel de Guzman wrote:
I think his argument is that with lambda expressions, the code is at the call site. However, I'd also argue that for more complex code spanning several statements, it is good practice to refactor them into their own functions. Overly complex lambda functions are a poor form.
So Boost.Phoenix self-acknowledges that it can only be used to write trivial things? In functional programming, there is no difference between defining lambdas and functions (except the former cannot be recursive), and it is not viewed as bad practice to have functions spanning a couple hundred lines.

On 2/5/11 9:05 PM, Mathias Gaunard wrote:
On 05/02/2011 13:42, Joel de Guzman wrote:
I think his argument is that with lambda expressions, the code is at the call site. However, I'd also argue that for more complex code spanning several statements, it is good practice to refactor them into their own functions. Overly complex lambda functions are a poor form.
So Boost.Phoenix self-acknowledges that it can only be used to write trivial things?
What are you saying? Did I say that? You must be confused because phoenix is not just about inline lambda functions, you know. There's also phoenix function, remember?
In functional programming, there is no difference between defining lambdas and functions (except the former cannot be recursive), and it is not viewed as bad practice to have functions spanning a couple hundred lines.
Sure! But so what's your point? Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On 2/5/11 9:48 PM, Joel de Guzman wrote:
On 2/5/11 9:05 PM, Mathias Gaunard wrote:
On 05/02/2011 13:42, Joel de Guzman wrote:
I think his argument is that with lambda expressions, the code is at the call site. However, I'd also argue that for more complex code spanning several statements, it is good practice to refactor them into their own functions. Overly complex lambda functions are a poor form.
So Boost.Phoenix self-acknowledges that it can only be used to write trivial things?
What are you saying? Did I say that? You must be confused because phoenix is not just about inline lambda functions, you know. There's also phoenix function, remember?
In functional programming, there is no difference between defining lambdas and functions (except the former cannot be recursive), and it is not viewed as bad practice to have functions spanning a couple hundred lines.
Sure! But so what's your point?
Limiting the discussion to C++, show me a function spanning a couple hundred lines and I'll show you ways to refactor the code into smaller functions and make the code more readable and maintainable. Overly complex functions are a poor form! More so for lambda functions because they add clutter to the enclosing function. Imagine: std::for_each(f, l, ...some 100 lines of code here ); Eeeeww! Yuck! I'll give the one who wrote that a rotten egg as an award! Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On 05/02/2011 12:40, Thomas Heller wrote:
On 03/02/2011 16:45, Thomas Heller wrote:
Now, let's consider another case, I want to do a.foo(b.bar()) + c.baz, but with a, b, and c taken from the scope, and I don't want to have to specify the types of a, b, and c. I can't do that in Phoenix without defining the foo, bar and baz functions at namespace scope, since they must have a template operator(), which is only allowed at that level. I can, however, do that with no problem with Boost.Local.
Well, you have seen nothing yet
http://svn.boost.org/svn/boost/sandbox/SOC/2010/phoenix3/libs/phoenix/doc/ht...
Mathias Gaunard<mathias.gaunard<at> ens-lyon.org> writes: phoenix/inside/extending_actors.html
A boilerplate macro for that would be a very welcome contribution...
All of this still needs to happen at namespace scope.
Sure it would. The point of this exercise was to adapt some "old style" C++ class to be used in a phoenix expression. Much in the fashion of BOOST_FUSION_ADAPT_STRUCT. Since you complained about using member functions in a phoenix expression is a pain ...
The problem with declaring those things at namespace scope is that they necessarily become far away from the lambda function you want to write.
Arguing like that disqualifies every library, since the defintion of the functions you want to use is _very_ far away... I don't see a point in that argument.
The argument I made in my initial message was the following: the problem with Phoenix is that it requires you to write boilerplate forwarding code for every function and class you want to be able to use. Then someone said something like "but that macro boilerplate is the same thing that you do with Boost.Local": no it's not, since it can only happen at namespace scope, which changes everything; and if I do that, I might as well use Boost.Local directly to define the lambda.

Mathias Gaunard <mathias.gaunard <at> ens-lyon.org> writes: <snip>
The problem with declaring those things at namespace scope is that they necessarily become far away from the lambda function you want to write.
Arguing like that disqualifies every library, since the defintion of the functions you want to use is _very_ far away... I don't see a point in that argument.
The argument I made in my initial message was the following: the problem with Phoenix is that it requires you to write boilerplate forwarding code for every function and class you want to be able to use.
Then someone said something like "but that macro boilerplate is the same thing that you do with Boost.Local": no it's not, since it can only happen at namespace scope, which changes everything; and if I do that, I might as well use Boost.Local directly to define the lambda.
The BOOST_LOCAL_FUNCTION generates a struct in the current scope that can be used as a functor. That functor can be used with a phoenix::function object, since it is a model of the Callable concept. So it really is the same thing. Of course, you use a lot of features that you might have with defining the implementation of a phoenix::function at namespace scope. However, Boost.Local doesn't give you these possibilities in the first place.

On 05/02/2011 14:47, Thomas Heller wrote:
Mathias Gaunard<mathias.gaunard<at> ens-lyon.org> writes: <snip>
The problem with declaring those things at namespace scope is that they necessarily become far away from the lambda function you want to write.
Arguing like that disqualifies every library, since the defintion of the functions you want to use is _very_ far away... I don't see a point in that argument.
The argument I made in my initial message was the following: the problem with Phoenix is that it requires you to write boilerplate forwarding code for every function and class you want to be able to use.
Then someone said something like "but that macro boilerplate is the same thing that you do with Boost.Local": no it's not, since it can only happen at namespace scope, which changes everything; and if I do that, I might as well use Boost.Local directly to define the lambda.
The BOOST_LOCAL_FUNCTION generates a struct in the current scope that can be used as a functor. That functor can be used with a phoenix::function object, since it is a model of the Callable concept. So it really is the same thing. Of course, you use a lot of features that you might have with defining the implementation of a phoenix::function at namespace scope. However, Boost.Local doesn't give you these possibilities in the first place.
As I said, it does. With Boost.Local, you can still call polymorphic functions on the variables captured from scope without specifying the types of the arguments.

On Wed, Feb 2, 2011 at 6:13 PM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote:
The syntax to declare a local (I think nested would be a better name)
Yes, gcc calls local function "nested function" but WiKi computer programming articles, Pascal, and Ada use "local functions" (I have references in the library doc). In one of the Rationale notes I indicate these as possible names: 1) Stay with Boost.Local. 2) Merge Boost.Local and Boost.ScopeExit into Boost.Scope (so to retain the current BOOST_SCOPE_EXIT name and API but BOOST_SCOPE_FUNCTION might not mean much...). 3) Boost.Nested for BOOST_NESTED_FUNCTION (good!) BOOST_NESTED_BLOCK (I like it!) BOOST_NESTED_EXIT (maybe but BOOST_SCOPE_EXIT is better). Anyways, this naming discussion can be resumed later if Boost.Local moves forward :)
function is not much more different than the one to define a regular monomorphic function, except you have to take care of capturing scope manually. I can tell from experience that I often end up writing by hand the very function objects that Boost.Local can automatically generate.
2) Even though C++0x will support unnamed functions as a language feature, Boost.Phoenix will not become obsolete. Quite the opposite, Boost.Phoenix offers a lot of advantages over C++0x lambdas. (Forgive me if I won't go into detail here about that, this thread is about Boost.Local) Whereas Boost.Local are just a complicated way to express what can be done with C++0x lambdas, I see no real advantage of Boost.Local over C++0x lambdas.
As far as I can see, there are few restriction compared to the equivalent C++0x lambdas: - creating a local can only be done at statement scope. - locals may not automatically capture all context - size of a local function cannot be optimized to be two words.
Let's compare Phoenix and that library and C++0x lambdas for a minute. Both C++0x lambdas and Boost.Local are better than Boost.Phoenix on several points.
Doing anything non-trivial with Phoenix requires creating lazy functions beforehand (typically done at namespace scope). The fact that Phoenix itself bundles many lazy functions for any other container member and standard algorithm (for a total of 4,000 lines of code for that task alone) is testament to that; you can't really work with it otherwise.
Bind and ->* can help to an extent (at the price of high verbosity), but if you want polymorphic behaviour (or don't want to specify manually all types involved) with template functions or members, you can't use those.
This severely restricts Boost.Phoenix to being either used as a toy, or in a limited sub-world of C++ where naked classes, structures and functions don't exist, unless they've been adapted or wrapped to be used with it.
On the other hand, C++0x lambdas can use arbitrary C++ syntax, and Boost.Local likewise, which means they can readily integrate in any source code. They cannot be polymorphic, but if that restriction were to be removed (through support for template member functions of local structures or otherwise), then the use for Phoenix would be even more limited.
What does "polymorphic" mean in this context? (I think it means that the local functions cannot be template functions... right?) -- Lorenzo

On 05/02/2011 18:20, Lorenzo Caminiti wrote:
What does "polymorphic" mean in this context? (I think it means that the local functions cannot be template functions... right?)
It refers to parametric polymorphism, which is indeed obtained through the use of templates in C++.

On Sun, Feb 6, 2011 at 10:18 AM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote:
On 05/02/2011 18:20, Lorenzo Caminiti wrote:
What does "polymorphic" mean in this context? (I think it means that the local functions cannot be template functions... right?)
It refers to parametric polymorphism, which is indeed obtained through the use of templates in C++.
And yes, as you mentioned, Boo.Local local functions (and also C++0x lambdas) unfortunately cannot have template parameters (because they are implemented using local classes -- this limitation is spelled out in the library docs with also a Rationale note). -- Lorenzo

On 02/01/2011 11:00 PM, Thomas Heller wrote:
I would be interested in what limitations you ran into using Boost.Lambda and if you are aware of the recent efforts that were put into Boost.Phoenix?
I ran into two problems specifically. The first was that my functions had just over three arguments. The second was that I wanted my function to have a nested function inside of it --- that is, another closure that it could pass to an STL algorithm such as for_each --- and although I saw that this was doable in principle I couldn't figure out how to make it work even though I could have sworn I was following the documentation, and the error messages gave me no insight at all into what I was doing wrong. Also, one of the things that I really liked about Boost.Local was that I didn't have to figure out how to cram what I wanted into special syntax; after writing the boiler-plate to create the closure function, I could program in normal C++ syntax, which made life easy. I hadn't looked at the latest version of Phoenix until just now, so I didn't realize that so much had changed --- thank you very much for directing my attention towards it! It looks like it might actually fit the bill for most of my uses, so when I get a chance I will experiment with using it to replace Boost.Local in my code. There are some cases where the function body is sufficiently non-trivial that translating everything into the special syntax of Phoenix might be a pain, but I could very well be wrong. I'll let you know what I think about how how well it solves the problem I faced versus Boost.Local after I've tried it out. Cheers, Greg

At Wed, 02 Feb 2011 14:41:50 -0800, Gregory Crosswhite wrote:
I hadn't looked at the latest version of Phoenix until just now, so I didn't realize that so much had changed --- thank you very much for directing my attention towards it! It looks like it might actually fit the bill for most of my uses, so when I get a chance I will experiment with using it to replace Boost.Local in my code. There are some cases where the function body is sufficiently non-trivial that translating everything into the special syntax of Phoenix might be a pain, but I could very well be wrong. I'll let you know what I think about how how well it solves the problem I faced versus Boost.Local after I've tried it out.
That'll be very interesting information. If you can get compilation-time results as part of it, doubly so. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

Thomas Heller wrote:
Gregory Crosswhite wrote:
To my mind this example looks a lot clearer if you reformat it as follows:
BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) (bind)((&sum)) ) ) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0);
As far is a am concerned, I still find this syntax overly verbose. I do realize though that this is just a toy example. For better comparison, Here is how the same thing would like in Boost.Phoenix:
Steven and I were playing with different syntaxes few years ago We came up with something like this: void BOOST_LOCAL_FUNCTION ( BOOST_BIND((factor)(&sum)), double num ) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_DECL(add) http://thread.gmane.org/gmane.comp.lib.boost.devel/168612/focus=168694 Alex

On 2/5/11 6:03 AM, Alexander Nasonov wrote:
As far is a am concerned, I still find this syntax overly verbose. I do realize though that this is just a toy example. For better comparison, Here is how the same thing would like in Boost.Phoenix:
Steven and I were playing with different syntaxes few years ago
We came up with something like this:
void BOOST_LOCAL_FUNCTION ( BOOST_BIND((factor)(&sum)), double num ) { sum += factor * num; std::clog<< "Summed:"<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_DECL(add)
http://thread.gmane.org/gmane.comp.lib.boost.devel/168612/focus=168694
That is nice! Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On 2/5/11 6:03 AM, Alexander Nasonov wrote:
We came up with something like this: void BOOST_LOCAL_FUNCTION( BOOST_BIND((factor)(&sum)), double num ) { sum += factor *num; std::clog<< "Summed:"<< sum << std::endl; } BOOST_LOCAL_FUNCTION_DECL(add)
Joel de Guzman wrote :
That is nice!
+1 Best regards, Pierre Morcello

On Fri, Feb 4, 2011 at 5:03 PM, Alexander Nasonov <alnsn@yandex.ru> wrote:
Thomas Heller wrote:
Gregory Crosswhite wrote:
To my mind this example looks a lot clearer if you reformat it as follows:
BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) (bind)((&sum)) ) ) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0);
As far is a am concerned, I still find this syntax overly verbose. I do realize though that this is just a toy example. For better comparison, Here is how the same thing would like in Boost.Phoenix:
Steven and I were playing with different syntaxes few years ago
We came up with something like this:
void BOOST_LOCAL_FUNCTION ( BOOST_BIND((factor)(&sum)), double num ) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_DECL(add)
http://thread.gmane.org/gmane.comp.lib.boost.devel/168612/focus=168694
Yes, Alex that is exactly where I started and I cannot thank you enough for your Boost.ScopeExit work which has served as a solid basis for my Boost.Local development. However: 1) How is this syntax is preferable to Boost.Local parenthesized syntax? To me, there is not much difference.* 2) How would you pass multiple local function parameters (not just the one parameter `num`) using this syntax? 3) Can you generate local function that are passed as template parameters using this syntax? (*) I personally find the parenthesized syntax actually simpler because it's -- more or less ;) -- like normal C++ syntax but with all tokens wrapped within extra parenthesis. Furthermore, the parenthesized syntax is more general than the above macro syntax because it can be extended to specify concepts, preconditions, postconditions, named parameters, etc. This might not be so relevant for Boost.Local discussions but for example you can re-write all Boost.Parameter (can Boost.ConceptCheck) macros to use the same parenthesized syntax that Boost.Local uses. Therefore, the API of all Boost libraries that spoil function declarations using macros could be unified under the parenthesized syntax... if there were an interest in doing so (as originally questioned by Andrzej Krzemienski http://lists.boost.org/Archives/boost/2010/05/166098.php). -- Lorenzo

AMDG On 2/5/2011 9:26 AM, Lorenzo Caminiti wrote:
On Fri, Feb 4, 2011 at 5:03 PM, Alexander Nasonov<alnsn@yandex.ru> wrote:
Steven and I were playing with different syntaxes few years ago
We came up with something like this:
void BOOST_LOCAL_FUNCTION ( BOOST_BIND((factor)(&sum)), double num ) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_DECL(add)
http://thread.gmane.org/gmane.comp.lib.boost.devel/168612/focus=168694
Yes, Alex that is exactly where I started and I cannot thank you enough for your Boost.ScopeExit work which has served as a solid basis for my Boost.Local development.
However: 1) How is this syntax is preferable to Boost.Local parenthesized syntax? To me, there is not much difference.*
The argument list is more readable, because it's closer to normal C++ syntax.
2) How would you pass multiple local function parameters (not just the one parameter `num`) using this syntax?
Black magic. I don't remember how, but I know we did figure this out.
3) Can you generate local function that are passed as template parameters using this syntax?
I think so. It wouldn't be very useful otherwise would it? In Christ, Steven Watanabe

On Wed, Feb 2, 2011 at 2:00 AM, Thomas Heller <thom.heller@googlemail.com> wrote:
Gregory Crosswhite wrote:
Hey everyone,
The purpose of this e-mail is to rave about Lorenzo's proposed Boost.Local library in the hopes of inspiring people to start the review process for it. :-)
I have been experimenting with using this library in my own code, and it has been a godsend for me. In one of the projects I have been working on I ran into many situations where I needed to call a higher-order function with a closure, and the closure was just complicated enough that I couldn't use Boost.Lambda. Before using this library I frequently found myself either writing a lot of extra code to work-around the need for a higher-order function, or writing a lot of boilerplate to create classes that would only be used by a single function in order to create a function object. This library has let me write the closures that I need in a fairly painless fashion and so has made my life a lot easier!
I would be interested in what limitations you ran into using Boost.Lambda and if you are aware of the recent efforts that were put into Boost.Phoenix?
To my mind this example looks a lot clearer if you reformat it as follows:
BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) (bind)((&sum)) ) ) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0);
As far is a am concerned, I still find this syntax overly verbose. I do realize though that this is just a toy example. For better comparison, Here is how the same thing would like in Boost.Phoenix:
boost::function<void(double)> add =( ref(sum) += factor * _1, std::clog << var("Summed: ") << sum << std::endl ) ; add(100.0);
Can you make factor constant within add() body using Boost.Phoenix? If not, then I could not use Boost.Phoenix for my original use case* that motived Boost.Local (local constant blocks). And that's why C++0x lambdas are also not useful for me because they do not support constant binding -- why don't they?? :(( -- plus I use an oldish gcc-based tool chain for an embedded system and there is no plan to get a C++0x release for it at the moment... (*) My original use case required (1) to write the body is normal C++ syntax (so I could not use Boost.Phoenix) and (2) to use constant binding (I am not sure but I don't think Boost.Phoenix can do constant binding, I know C++0x lambdas cannot) to check assertions in a constant correct context: void f(int& zero) { BLOCK_INVARIANT( (const (zero) (zero == 0)) ) // Compiler error if programmers mistake `==` with `=`. ... } I can do this with Boost.Local: void f(int& zero) { BOOST_LOCAL_BLOCK( (const bind)(&zero) ) { assert(zero == 0); } BOOST_LOCAL_BLOCK_END } How can I do this in Boost.Phoenix? How can I do this in C++0x lambdas? (Note requirements (1) and (2).) Maybe this use case is not very interesting to other people but it was important for me.
Despite the Local Blocks and Local Exits feature, I can't see much difference to the already existing lambda libraries. I just looked through the Boost.Local documentation and immediately navigated to the "Alternatives" section and its not really correct regarding the features of Boost.Lambda and Boost.Phoenix. I am specifically talking about the "Bind variables in scope" and "Program body using usual C++
The Alternatives section is based on this previous Boost discussion http://permalink.gmane.org/gmane.comp.lib.boost.devel/212255 . I also think it is not a complete comparison. For example, I wanted to add the add() example -- add add() ;) -- reworked in Boost.Phoenix, Boost.Lambda, C++0x lambdas, and C++ local classes but I didn't have time yet... Thanks a lot of the above code in Boost.Phoenix, I'll add it to Boost.Local doc :)
syntax" part. The last is debatable, but how are the above examples (both of Boost.Local and Boost.Phoenix) not C++ syntax? Can you highlight the advantages/disadvantages again?
Yes, this is debatable and at the end it's of course all C++. But the Boost.Local function body defined within `{ ... }` it's the normal C++ syntax for function definitions. For example, Boost.Phoenix uses `,` where C++ and Boost.Local use `;` to terminate and instruction, Boost.Phoenix uses `var("Summed:")` where C++ and Boost.Local use `"Summed:"`, etc. Plus, how would local variables and local classes look in Boost.Pheenix? In Boost.Local it's like in normal C++: BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) (bind)((&sum)) ) ) { const std::string msg = "Summed: "; // A const local var. struct text { std::string say; } // A local struct. test t; // A local var. t.say = msg; sum += factor * num; std::clog<< t.say << sum<< std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0); How would this look in Boost.Phoenix? I wish I knew Phoenix better :) so I could provide the answers myself... -- Lorenzo

On 2/6/11 1:03 AM, Lorenzo Caminiti wrote:
On Wed, Feb 2, 2011 at 2:00 AM, Thomas Heller
As far is a am concerned, I still find this syntax overly verbose. I do realize though that this is just a toy example. For better comparison, Here is how the same thing would like in Boost.Phoenix:
boost::function<void(double)> add =( ref(sum) += factor * _1, std::clog<< var("Summed: ")<< sum<< std::endl ) ; add(100.0);
Can you make factor constant within add() body using Boost.Phoenix? If
Yes! [snip irrelevant text]
Maybe this use case is not very interesting to other people but it was important for me.
Despite the Local Blocks and Local Exits feature, I can't see much difference to the already existing lambda libraries. I just looked through the Boost.Local documentation and immediately navigated to the "Alternatives" section and its not really correct regarding the features of Boost.Lambda and Boost.Phoenix. I am specifically talking about the "Bind variables in scope" and "Program body using usual C++
The Alternatives section is based on this previous Boost discussion http://permalink.gmane.org/gmane.comp.lib.boost.devel/212255 . I also think it is not a complete comparison. For example, I wanted to add the add() example -- add add() ;) -- reworked in Boost.Phoenix, Boost.Lambda, C++0x lambdas, and C++ local classes but I didn't have time yet... Thanks a lot of the above code in Boost.Phoenix, I'll add it to Boost.Local doc :)
syntax" part. The last is debatable, but how are the above examples (both of Boost.Local and Boost.Phoenix) not C++ syntax? Can you highlight the advantages/disadvantages again?
Yes, this is debatable and at the end it's of course all C++. But the Boost.Local function body defined within `{ ... }` it's the normal C++ syntax for function definitions. For example, Boost.Phoenix uses `,` where C++ and Boost.Local use `;` to terminate and instruction, Boost.Phoenix uses `var("Summed:")` where C++ and Boost.Local use `"Summed:"`, etc.
Plus, how would local variables and local classes look in Boost.Pheenix? In Boost.Local it's like in normal C++:
BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) (bind)((&sum)) ) ) { const std::string msg = "Summed: "; // A const local var. struct text { std::string say; } // A local struct. test t; // A local var. t.say = msg;
sum += factor * num; std::clog<< t.say<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0);
How would this look in Boost.Phoenix? I wish I knew Phoenix better :) so I could provide the answers myself...
Look, let us please stop this syntax nonsense. As mentioned, phoenix can have all those above (pure c++ function syntax, local classes, local variables, etc.) in the form of offline phoenix::function. Why offline? I argue, and I am sure many agree, that overly complex inlined lambdas add clutter to the enclosing function. Local function emulation is at best a poor rendition of what it should be anyway (e.g. like Pascal's local function) since it doesn't have direct access to the enclosing scope and thus have to resort to argument binding and some such and add *A LOT* of clutter. At any rate, I repeatedly say: I am not against Boost.Local. As I said, in as much as we have BOOST_FOREACH and std::bind, I see no reason why we can't have Boost.Local. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On 2/5/11 12:35 PM, Joel de Guzman wrote:
Look, let us please stop this syntax nonsense.
It isn't nonsense. Inline Phoenix functions have a special syntax which does not come naturally but requires training to use and understand. This is a fact. Having said that, I think that you are misconstruing us as saying that this is a bad thing. Nobody here is claiming that this is a bad thing --- and in fact, I think that the syntax is very impressively designed because of the way it allows one to construct very nice-looking functions within the limitations of being based on C++! All we are saying that it isn't always a good thing, which I am sure you agree with. Furthermore, I agree with Lorenzo's sentiment that I wish I understood it better, and if I have the time I may see if I can learn to be more effective in using it. :-)
As mentioned, phoenix can have all those above (pure c++ function syntax, local classes, local variables, etc.) in the form of offline phoenix::function.
Yes, one can do that, but looking at the documentation (and please correct me if I am mistaken!) it looks like writing such a function is equivalent to writing a function object but with even more boilerplate to make it lazy. I am sure that there are many situations where this is incredibly useful (in particular because it means that you don't need to use boost::bind, which is very nice!), but by itself it does not seem to me that it provides the same features as Boost.Local. This, again, is not a criticism; the whole point of this discussion was just to show that Boost.Local is complimentary to Boost.Phoenix rather than being made redundant by Boost.Phoenix, that's all. Having said that, you have mentioned that with a few macros one could construct pheonix::functions without needing the extra boilerplate, just as Boost.Local does. If this is the case, then I would look forward to seeing it. I am certainly not against using Boost.Phoenix when it is the best tool available. :-)
At any rate, I repeatedly say: I am not against Boost.Local. As I said, in as much as we have BOOST_FOREACH and std::bind, I see no reason why we can't have Boost.Local.
Great, then we are actually in agreement! If you think that you or Boost.Phoenix is being criticized, then I think that there might just be a miscommunication at work here, since I have been attempting (perhaps unsuccessfully) to make clear that at least for me there is only admiration for Boost.Phoenix, not loathing, and I suspect that Lorenzo feels the same way. :-) Cheers, Greg

On Sat, Feb 5, 2011 at 3:35 PM, Joel de Guzman <joel@boost-consulting.com> wrote:
On 2/6/11 1:03 AM, Lorenzo Caminiti wrote:
Plus, how would local variables and local classes look in Boost.Pheenix? In Boost.Local it's like in normal C++:
BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) (bind)((&sum)) ) ) { const std::string msg = "Summed: "; // A const local var. struct text { std::string say; } // A local struct. test t; // A local var. t.say = msg;
sum += factor * num; std::clog<< t.say<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0);
How would this look in Boost.Phoenix? I wish I knew Phoenix better :) so I could provide the answers myself...
Look, let us please stop this syntax nonsense. As mentioned, phoenix can have all those above (pure c++ function syntax, local classes, local variables, etc.) in the form of offline phoenix::function. Why offline? I argue, and I am sure many agree, that overly complex inlined lambdas add clutter to the enclosing function. Local function emulation is at best a poor rendition of what it should be anyway (e.g. like Pascal's local function) since it doesn't have direct access to the enclosing scope and thus have to resort to argument binding and some such and add *A LOT* of clutter.
At any rate, I repeatedly say: I am not against Boost.Local. As I said, in as much as we have BOOST_FOREACH and std::bind, I see no reason why we can't have Boost.Local.
Agreed. I think we discussed the syntax stuff enough. (Sorry but I wrote the email above before reading the related discussions in Greg's "Case study: Boost.Local versus Boost.Phoenix" so my comments were out of sync with the status of the discussion :) .) -- Lorenzo

On 2/6/11 7:32 AM, Lorenzo Caminiti wrote:
On Sat, Feb 5, 2011 at 3:35 PM, Joel de Guzman
At any rate, I repeatedly say: I am not against Boost.Local. As I said, in as much as we have BOOST_FOREACH and std::bind, I see no reason why we can't have Boost.Local.
Of course I meant: BOOST_FOREACH and std::for_each. Sorry if that was confusing.
Agreed. I think we discussed the syntax stuff enough. (Sorry but I wrote the email above before reading the related discussions in Greg's "Case study: Boost.Local versus Boost.Phoenix" so my comments were out of sync with the status of the discussion :) .)
Not a problem at all. Good luck with your library. I'm all for it. Please keep an open mind on alternate syntax though. We might have something similar for phoenix function so I'll be very keen on uniformity of syntax. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

At Sat, 5 Feb 2011 18:32:06 -0500, Lorenzo Caminiti wrote:
Agreed. I think we discussed the syntax stuff enough.
Well, just one thing I'd like to add: it would be a shame if your Boost library doesn't provide alternate macros usable by anyone who is willing to depend on the C99 preprocessor, that take advantage of variadics. BOOST_LOCAL_FUNCTION_(...) anyone? -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On Sun, Feb 6, 2011 at 4:02 PM, Dave Abrahams <dave@boostpro.com> wrote:
At Sat, 5 Feb 2011 18:32:06 -0500, Lorenzo Caminiti wrote:
Agreed. I think we discussed the syntax stuff enough.
Well, just one thing I'd like to add: it would be a shame if your Boost library doesn't provide alternate macros usable by anyone who is willing to depend on the C99 preprocessor, that take advantage of variadics.
Sure, I agree. As I mentioned in previous emails, I am taking on the assignments to: 1) Look into how variadics, empty sequences, and other C99-like preprocessor extensions might simply the parenthesized syntax. 2) Look into how Alex-Steven's macro syntax can simplify the parenthesized syntax. At the same time, I would like to encourage people to try out the parenthesized syntax of Boost.Local as is and tell me its pros and cons. Thanks :) -- Lorenzo

On Sun, Feb 6, 2011 at 4:02 PM, Dave Abrahams <dave@boostpro.com> wrote:
At Sat, 5 Feb 2011 18:32:06 -0500, Lorenzo Caminiti wrote:
Agreed. I think we discussed the syntax stuff enough.
Well, just one thing I'd like to add: it would be a shame if your Boost library doesn't provide alternate macros usable by anyone who is willing to depend on the C99 preprocessor, that take advantage of variadics.
BOOST_LOCAL_FUNCTION_(...)
anyone?
Hello all, I have reworked Boost.Local macro syntax to take advantage of variadics. The latest code is in the sandbox http://svn.boost.org/svn/boost/sandbox/local/. I still have to update the docs and polish the code but I would like your early feedback. I would also like to hear from people that have used the older syntax so they can compare it with the new one. For example, if variadic macros are supported by your compiler: #include <boost/local/function.hpp> #include <iostream> int main() { double sum = 0.0; int factor = 10; void BOOST_LOCAL_FUNCTION_PARAMS(double num, const bind factor, bind& sum) { sum += factor * num; std::clog << "Summed: " << sum << std::endl; } BOOST_LOCAL_FUNCTION_NAME(add) add(100.0); return 0; } In any case, regardless of varidic macros or not, and for all compilers, the same macros also support this syntax: #include <boost/local/function.hpp> #include <iostream> int main() { double sum = 0.0; int factor = 10; void BOOST_LOCAL_FUNCTION_PARAMS( (double num) (const bind factor) (bind& sum) ) { sum += factor * num; std::clog << "Summed: " << sum << std::endl; } BOOST_LOCAL_FUNCTION_NAME(add) add(100.0); return 0; } The syntax of local exits and blocks also changed accordingly: http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/index.html#... IMO, the new syntax is much simpler and it greatly reduces (and with variadics it completely eliminates) the number of extra parenthesis. This simplification comes to the cost of generality: The new syntax cannot be used as a general syntax to unify the syntax of all macros that spoil function declarations but this is not a requirement for Boost.Local so this lack of generality is not a problem. Many thanks for pushing me in improving Boost.Local syntax and for all your suggestions! -- Lorenzo

I converted all of my code to use the Sequencing Macro Syntax, and then after that I converted it all to the Variadic Macro Syntax. The process was completely painless and took probably about 10-15 minutes total for each conversion. It is always satisfying when one gets to make heavy use of the backspace key to eliminate now-unneeded code. :-) I think that you've got a good compromise with supporting both legacy C++ compilers with the sequencing syntax and C99 compilers with the variadic syntax; the variadic syntax is a little nicer, but the sequencing syntax feels just fine to use as well. (I am impressed that you managed to work a way so that the same macro can accept both syntaxes!) The one part that has become slightly more verbose is where I had multiple variables that I was binding, since now I need to retype "const bind" for each variable rather than supplying them as a list (unless I am misunderstanding something). I think that is a fair trade-off, though, since the nested list inside the const bind used in the old syntax feels a bit unnatural unless you are used to preprocessor metaprogramming; it took me a while of peering at the documentation to realize that my mistake was that I needed two layers of parentheses instead of one to bind a variable (that is "(const bind)((x))" instead of "(const bind)(x)"), and even after I got used to the syntax (and understood why you did it that way) my most common mistake was to forget and only use a single layer of parentheses until the compiler yelled at me. :-) I would recommend that when you polish up the documentation that you make sure to include an example of the case where multiple variable are bound, though, since it is not immediately obvious looking at the examples how to extrapolate to that case. (Incidentally, you should definitely update and keep around the Grammar appendix since I found it incredibly helpful in figuring out exactly how the syntax worked when I got confused!) By-the-way, if you want to see how I have been using your code you can check out my repository from https://github.com/gcross/CodeSearch and use grep to see where I've been using your library. I explicitly logged in the revision history where I changed to use the new sequencing syntax and the new variadic syntax (which at this time are the two most recent commits) so you can see the difference in how it looks for yourself. Cheers, Greg On 2/24/11 12:01 PM, Lorenzo Caminiti wrote:
On Sun, Feb 6, 2011 at 4:02 PM, Dave Abrahams<dave@boostpro.com> wrote:
Agreed. I think we discussed the syntax stuff enough. Well, just one thing I'd like to add: it would be a shame if your Boost library doesn't provide alternate macros usable by anyone who is willing to depend on
At Sat, 5 Feb 2011 18:32:06 -0500, Lorenzo Caminiti wrote: the C99 preprocessor, that take advantage of variadics.
BOOST_LOCAL_FUNCTION_(...)
anyone? Hello all,
I have reworked Boost.Local macro syntax to take advantage of variadics.
The latest code is in the sandbox http://svn.boost.org/svn/boost/sandbox/local/. I still have to update the docs and polish the code but I would like your early feedback. I would also like to hear from people that have used the older syntax so they can compare it with the new one.
For example, if variadic macros are supported by your compiler:
#include<boost/local/function.hpp> #include<iostream>
int main() { double sum = 0.0; int factor = 10;
void BOOST_LOCAL_FUNCTION_PARAMS(double num, const bind factor, bind& sum) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_NAME(add)
add(100.0); return 0; }
In any case, regardless of varidic macros or not, and for all compilers, the same macros also support this syntax:
#include<boost/local/function.hpp> #include<iostream>
int main() { double sum = 0.0; int factor = 10;
void BOOST_LOCAL_FUNCTION_PARAMS( (double num) (const bind factor) (bind& sum) ) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_NAME(add)
add(100.0); return 0; }
The syntax of local exits and blocks also changed accordingly: http://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/index.html#...
IMO, the new syntax is much simpler and it greatly reduces (and with variadics it completely eliminates) the number of extra parenthesis. This simplification comes to the cost of generality: The new syntax cannot be used as a general syntax to unify the syntax of all macros that spoil function declarations but this is not a requirement for Boost.Local so this lack of generality is not a problem.
Many thanks for pushing me in improving Boost.Local syntax and for all your suggestions!

On Fri, Feb 25, 2011 at 2:10 PM, Gregory Crosswhite <gcross@phys.washington.edu> wrote:
I converted all of my code to use the Sequencing Macro Syntax, and then after that I converted it all to the Variadic Macro Syntax. The process was completely painless and took probably about 10-15 minutes total for each conversion. It is always satisfying when one gets to make heavy use of the backspace key to eliminate now-unneeded code. :-)
I think that you've got a good compromise with supporting both legacy C++ compilers with the sequencing syntax and C99 compilers with the variadic syntax; the variadic syntax is a little nicer, but the sequencing syntax feels just fine to use as well. (I am impressed that you managed to work a way so that the same macro can accept both syntaxes!)
The one part that has become slightly more verbose is where I had multiple variables that I was binding, since now I need to retype "const bind" for each variable rather than supplying them as a list (unless I am misunderstanding something). I think that is a fair trade-off, though, since the nested list inside the const bind used in the old syntax feels a bit unnatural unless you are used to preprocessor metaprogramming; it took me a while of peering at the documentation to realize that my mistake was that I needed two layers of parentheses instead of one to bind a variable (that is "(const bind)((x))" instead of "(const bind)(x)"), and even after I got used to the syntax (and understood why you did it that way) my most common mistake was to forget and only use a single layer of parentheses until the compiler yelled at me. :-)
I would recommend that when you polish up the documentation that you make sure to include an example of the case where multiple variable are bound, though, since it is not immediately obvious looking at the examples how to extrapolate to that case. (Incidentally, you should definitely update and keep around the Grammar appendix since I found it incredibly helpful in figuring out exactly how the syntax worked when I got confused!)
By-the-way, if you want to see how I have been using your code you can check out my repository from
I notice that "non_trivial_columns.cpp" still contains the old syntax -- probably because you are no longer compiling this file... Also I noticed that you haven't happened to use `const bind&` and `[const] bind this`. You have used either `const bind` (constant bind by value) or `bind&` (non-constant bind by reference). I think your application just did not need const bind by reference `const bind&` and to bind the object this `[const] bind this`. However, I wanted to ask you to make sure that my library docs clearly indicates that these other types of bindings are possible. A key difference when you bind by constant reference instead that by (constant) value, is that binding by value (constant or not) makes a copy of the bound variable value when the local function is *declared*. Instead biding by constant reference will use the (constant) value that the bound variable has when the local function is *called*. For example: void f() { int x = 10; void BOOST_LOCAL_FUNCTION(const bind x) { // make a copy of `x` here std::cout << x << std::endl; } BOOST_LOCAL_NAME(print) x = 11; print(); // prints 10 (not 11) } Instead: void f() { int x = 10; void BOOST_LOCAL_FUNCTION(const bind& x) { // doesn't copy `x` std::cout << x << std::endl; } BOOST_LOCAL_NAME(print) x = 11; print(); // prints 11 (not 10) } In your experience with my library, is this semantic clearly explained in the docs? Overall, it looks like your code make a pretty extensive use of my library. I'm glad you found it useful! Thanks, -- Lorenzo

On Tue, Feb 1, 2011 at 6:04 PM, Gregory Crosswhite <gcross@phys.washington.edu> wrote:
Hey everyone,
The purpose of this e-mail is to rave about Lorenzo's proposed Boost.Local library in the hopes of inspiring people to start the review process for it. :-)
I have been experimenting with using this library in my own code, and it has been a godsend for me. In one of the projects I have been working on I ran
I'm glad my library is helping :)
At first I thought that the interface needed to use it was ugly, but as I have gotten used to it I have changed my mind. Part of why I thought it was
Other people (but not Boosters) have made a similar comment about the "parenthesized syntax". It's (very) strange at first but it's not bad at all after the 1st week of using it.
ugly was because of the way that whitespace was used in the example included in the original e-mail:
BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) (bind)((&sum)) ) ) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0);
I personally use this version when the parameters can fit in a single line and...
To my mind this example looks a lot clearer if you reformat it as follows:
BOOST_LOCAL_FUNCTION( (void) (add)( (double)(num) (const bind)((factor)) (bind)((&sum)) ) ) { sum += factor * num; std::clog<< "Summed: "<< sum<< std::endl; } BOOST_LOCAL_FUNCTION_END(add) add(100.0);
... this other version when the parameters are too long to fit in one line. Programmers can use the white spaces as they wish (as white spaces do not matter in the parenthesized syntax). I am happy to rework all the library examples to comply with the white space formatting that Boosters find most readable by default. Hello all, Sorry for the late reply (and many thanks to Pierre for letting me know that Boost.Local discussions resumed). I will reply to all your comments separately in a few emails that will follow shortly. I hope my replies do not appear too disorganized given that I haven't been able to send them in real-time. (I also have to review the Boost.Phoenix vs. Boost.Local email thread...) Thanks in advance for all you comments on Boost.Local! -- Lorenzo
participants (13)
-
Alexander Nasonov
-
Dave Abrahams
-
Gregory Crosswhite
-
Jeffrey Lee Hellrung, Jr.
-
Joel de Guzman
-
Lorenzo Caminiti
-
Loïc Joly
-
Mathias Gaunard
-
Michael Caisse
-
Phil Endecott
-
Pierre Morcello
-
Steven Watanabe
-
Thomas Heller