[local] Simplifying the parenthesized syntax

On Sun, Feb 6, 2011 at 10:26 AM, Vicente Botet <vicente.botet@wanadoo.fr> wrote:
The fact that you can not use variadic macros at work doesn't means that your library can not provide in addition variadic macros on compilers supporting them. I have no idea the work that this suppose, but if the interface could be more appealing your library will have much more people interested in.
Have you an idea of how the interface could be simplified if variadic macros were used?
The purpose of this email if to brainstorm possible ideas to simplify the parenthesized syntax. Sorry in advance if not all that I say is correct -- I haven't implemented it yet so I might be saying inaccurate/unfeasible things here and there. As always, your feedback is very welcome :) PRELIMINARY IDEAS TO SIMPLIFY THE PARENTHESIZED SYNTAX Consider the following parenthesized syntax for local functions: (void) (f)( (int)(x) (double&)(y) (const bind)((a)(&b)) (bind)((&c)(d)) ) // [0] The followings are possible ways to simply this syntax. 1 MERGING PARAMETER TYPES AND NAMES (C++ preprocessor) Parameter names can be passed to function types so I can transform `int x` into `int` at compile-time: int x --[make function type]--> void (int x) --[get 1st parm type]--> int This should allow me to simplify the parenthesized syntax [0] to: (void) (f)( (int x) (double& y) (const bind)((a)(&b)) (bind)((&c)(d)) ) // [1] Note that the (unbound) parameter type and name are merged into a single sequence element. The following should also be possible: (void) (f)( (int x) (double& y) (const bind a) (const bind& b) (bind& c) (bind d) ) // [1a] Is [1a] simpler than [1]? Maybe it is... 2 TOWARD THE NORMAL PARAMETER LIST SYNTAX (C99 preprocessor) Using variadic macros I _might_ be able to use a variable length tuple (can I? I am not very familiar with these yet...) instead of a sequence to represent the function parameters: (void) (f)(int x, double& y, const bind a, const bind& b, bind& c, bind d) // [2] I think, this is a great simplification over [0] because it is the exact same syntax used by C++ to declare function parameters! Note that `const bind` and `bind` have been distributed to all the bound parameters. Given that sequences are best avoided here (to reduce extra parenthesis), I do not think there is a less verbose way to enumerate the bound parameters. The followings could also be possible: (void) (f)(int x, double& y, const bind (a, &b), bind (&c, d) ) // [3] (void) (f)(int x, double& y) (const bind)(a, &b) (bind)(&c, d) // [4] But I think enumerating every bound variable separately as in [2] makes the parameter list syntax look the closet to normal C++ syntax even if it requires the repetition of `const bind` and `bind` as the types of the bound variables. Therefore, I would prefer [2] over both [3] and [4]. 3 RETURN TYPE AND FUNCTION NAME (C++ and C99 preprocessors) I don't know how/if I can simplify the passing of the return type and function name because I do need the function name as a separate token within the preprocessor to do token concatenation and generate unique names that refer to the function name... Something like this should be possible (using tuples instead of sequences): void, f, ( (int)(x) (double&)(y) (const bind)((a)(&b)) (bind)((&c)(d)) ) // [5] void, (f)( (int)(x) (double&)(y) (const bind)((a)(&b)) (bind)((&c)(d)) ) // [6] And again, on C99: void, f, (int x, double& y, const bind a, const bind& b, bind& c, bind d) // [7] void, (f)(int x, double& y, const bind a, const bind& b, bind& c, bind d) // [8] However, I don't see how these are simpler than [0] and [2]. I need to think about this more to see if other syntaxes are possible... 4 DEFAULT PARAMETER VALUES (C++ and C99 preprocessors) Currently local functions support default parameters via the following parenthesized syntax: (void) (f)( (int)(x)(default)(-1) (double)(y)(default)(1.23) ) // [9] I think this could be simplified to (note the removal of the parenthesis around the default value): (void) (f)( (int)(x)(default -1) (double)(y)(default 1.23) ) // [10] An additional simplification could be to merge parameter types and names together as in [1]: (void) (f)( (int x)(default -1) (double y)(default 1.23) ) // [10a] Plus using C99 variadics as in [2]: (void) (f)(int x, default -1, double y, default 1.23) // [11] I am not a big fan of this because `default` is separated from its parameter by the comma `,`... but I don't think I can do better than this. 5 OTHERS CONSIDERATIONS These considerations are not directly relevant to local functions but the parenthesized syntax [0] was designed as a general syntax that makes *all* the elements of a function declaration available for preprocessor metaprogramming. Instead, syntaxes [1] and [2] cannot separate the parameter type token from the parameter name token at preprocessing time. Therefore: a) I don't think [1] and [2] allow to generate a parameter with the specified name but a different type. For example, say I want to add `const&` to `int x`, how can I do that unless `int x` is specified as `(int)(x)` or `(int, x)`? int x --[how can I do this??]--> add_reference<add_const<int>::type>::type x (I have to double check, but I don't think local functions need to manipulate parameter types retaining instead the parameter names so I don't think this is an issue for local functions.) b) Having the parameter names as separate tokens (which is possible with [0] but not with [1] or [2]) could be useful to generate unique names to handle function overloading (even if with some limitations). For example, in another library, I concatenate the function name token with the parameter name tokens to generate unique names for overloaded functions. As long as the overloaded functions use different parameter names (and not just different parameter types) this mechanism works. (Overloading is not supported for local functions -- see Rationale in library docs -- so this is not an issue for local functions.) Therefore, *IF* there was an interest in defining the parenthesized syntax to be as general as possible so it could be adopted everywhere macros spoil function definitions (to avoid requiring programmers to learn different syntaxes for the different macros), [0] is more general because it separates the parameter types from their names (at the cost of the extra parenthesis of course). Of all of these syntaxes, I _personally_ like [0] because it is pure C++ preprocessor and it is the most general (maybe with simplification [10] for default parameters). I also would like to provide [2] if the C99 preprocessor is detected -- ideally, the same parsing macros will be smart enough to accept both [2] and [0] on C99 and just [0] on pure C++ preprocessors. -- Lorenzo

On 2/7/2011 8:08 AM, Lorenzo Caminiti wrote: [...]
The purpose of this email if to brainstorm possible ideas to simplify the parenthesized syntax. Sorry in advance if not all that I say is correct -- I haven't implemented it yet so I might be saying inaccurate/unfeasible things here and there. As always, your feedback is very welcome :)
PRELIMINARY IDEAS TO SIMPLIFY THE PARENTHESIZED SYNTAX
Consider the following parenthesized syntax for local functions:
(void) (f)( (int)(x) (double&)(y) (const bind)((a)(&b)) (bind)((&c)(d)) ) // [0]
The followings are possible ways to simply this syntax. [...snip various options...]
There's also maybe something like (void) (f) ( ( int, x ) ( double&, y ) ( const bind, (a)(&b) ) ( bind, (&c)(d) ) ) (if that can be made to work). But otherwise, I agree with your points on [0] (does not make use of technically C99-only features and allows the most information to be extracted by the preprocessor). - Jeff

Lorenzo Caminiti wrote:
On Sun, Feb 6, 2011 at 10:26 AM, Vicente Botet <vicente.botet@wanadoo.fr> wrote:
The fact that you can not use variadic macros at work doesn't means that your library can not provide in addition variadic macros on compilers supporting them. I have no idea the work that this suppose, but if the interface could be more appealing your library will have much more people interested in.
Have you an idea of how the interface could be simplified if variadic macros were used?
The purpose of this email if to brainstorm possible ideas to simplify the parenthesized syntax. Sorry in advance if not all that I say is correct -- I haven't implemented it yet so I might be saying inaccurate/unfeasible things here and there. As always, your feedback is very welcome :)
PRELIMINARY IDEAS TO SIMPLIFY THE PARENTHESIZED SYNTAX
Consider the following parenthesized syntax for local functions:
(void) (f)( (int)(x) (double&)(y) (const bind)((a)(&b)) (bind)((&c)(d)) ) // [0]
The followings are possible ways to simply this syntax.
1 MERGING PARAMETER TYPES AND NAMES (C++ preprocessor)
Parameter names can be passed to function types so I can transform `int x` into `int` at compile-time:
int x --[make function type]--> void (int x) --[get 1st parm type]--> int
This should allow me to simplify the parenthesized syntax [0] to:
(void) (f)( (int x) (double& y) (const bind)((a)(&b)) (bind)((&c)(d)) ) // [1]
Note that the (unbound) parameter type and name are merged into a single sequence element.
The following should also be possible:
(void) (f)( (int x) (double& y) (const bind a) (const bind& b) (bind& c) (bind d) ) // [1a]
Is [1a] simpler than [1]? Maybe it is...
It is simpler for me.
2 TOWARD THE NORMAL PARAMETER LIST SYNTAX (C99 preprocessor)
Using variadic macros I _might_ be able to use a variable length tuple (can I? I am not very familiar with these yet...) instead of a sequence to represent the function parameters:
(void) (f)(int x, double& y, const bind a, const bind& b, bind& c, bind d) // [2]
Yeah. This is looking quite close to a C++ function signature. What do you think of spiting the parameters part from the binding part (void) (f)(int x, double& y)(const bind a, const bind& b, bind& c, bind d) // [2a]
I think, this is a great simplification over [0] because it is the exact same syntax used by C++ to declare function parameters!
Note that `const bind` and `bind` have been distributed to all the bound parameters. Given that sequences are best avoided here (to reduce extra parenthesis), I do not think there is a less verbose way to enumerate the bound parameters. The followings could also be possible:
(void) (f)(int x, double& y, const bind (a, &b), bind (&c, d) ) // [3] (void) (f)(int x, double& y) (const bind)(a, &b) (bind)(&c, d) // [4]
But I think enumerating every bound variable separately as in [2] makes the parameter list syntax look the closet to normal C++ syntax even if it requires the repetition of `const bind` and `bind` as the types of the bound variables. Therefore, I would prefer [2] over both [3] and [4].
I don't like [3]. [4] is close to my 2a proposition and is quite short. I like. (void) (f)(int x, double& y) (const bind a, const bind& b, bind& c, bind d) // [2a] (void) (f)(int x, double& y) (const bind)(a, &b) (bind)(&c, d) // [4]
3 RETURN TYPE AND FUNCTION NAME (C++ and C99 preprocessors)
I don't know how/if I can simplify the passing of the return type and function name because I do need the function name as a separate token within the preprocessor to do token concatenation and generate unique names that refer to the function name...
Something like this should be possible (using tuples instead of sequences):
void, f, ( (int)(x) (double&)(y) (const bind)((a)(&b)) (bind)((&c)(d)) ) // [5] void, (f)( (int)(x) (double&)(y) (const bind)((a)(&b)) (bind)((&c)(d)) ) // [6]
And again, on C99:
void, f, (int x, double& y, const bind a, const bind& b, bind& c, bind d) // [7] void, (f)(int x, double& y, const bind a, const bind& b, bind& c, bind d) // [8]
However, I don't see how these are simpler than [0] and [2]. I need to think about this more to see if other syntaxes are possible...
Using tuple instead of sequences, could [4] (void) (f)(int x, double& y) (const bind)(a, &b) (bind)(&c, d) // [4] become void, f, (int x, double& y) (const bind a, &b) (bind)(&c, d) // [4a] ?
4 DEFAULT PARAMETER VALUES (C++ and C99 preprocessors)
Currently local functions support default parameters via the following parenthesized syntax:
(void) (f)( (int)(x)(default)(-1) (double)(y)(default)(1.23) ) // [9]
I think this could be simplified to (note the removal of the parenthesis around the default value):
(void) (f)( (int)(x)(default -1) (double)(y)(default 1.23) ) // [10]
An additional simplification could be to merge parameter types and names together as in [1]:
(void) (f)( (int x)(default -1) (double y)(default 1.23) ) // [10a]
Plus using C99 variadics as in [2]:
(void) (f)(int x, default -1, double y, default 1.23) // [11]
I am not a big fan of this because `default` is separated from its parameter by the comma `,`... but I don't think I can do better than this.
Why you can not use the = symbol? Could this be (void) (f)(int x = -1, double y = 1.23) // [11a]
5 OTHERS CONSIDERATIONS
These considerations are not directly relevant to local functions but the parenthesized syntax [0] was designed as a general syntax that makes *all* the elements of a function declaration available for preprocessor metaprogramming. Instead, syntaxes [1] and [2] cannot separate the parameter type token from the parameter name token at preprocessing time. Therefore: <snip> Therefore, *IF* there was an interest in defining the parenthesized syntax to be as general as possible so it could be adopted everywhere macros spoil function definitions (to avoid requiring programmers to learn different syntaxes for the different macros), [0] is more general because it separates the parameter types from their names (at the cost of the extra parenthesis of course).
Of all of these syntaxes, I _personally_ like [0] because it is pure C++ preprocessor and it is the most general (maybe with simplification [10] for default parameters). I also would like to provide [2] if the C99 preprocessor is detected -- ideally, the same parsing macros will be smart enough to accept both [2] and [0] on C99 and just [0] on pure C++ preprocessors.
Lorenzo I understand your concern and that you need the general syntax for Boost.Contract. Whether this general syntax is adapted to Boost.Local also is what you are trying to analyze in this post. Best, Vicente -- View this message in context: http://boost.2283326.n4.nabble.com/local-Simplifying-the-parenthesized-synta... Sent from the Boost - Dev mailing list archive at Nabble.com.

On Mon, Feb 7, 2011 at 12:37 PM, Vicente Botet <vicente.botet@wanadoo.fr> wrote:
Lorenzo Caminiti wrote:
3 RETURN TYPE AND FUNCTION NAME (C++ and C99 preprocessors)
I don't know how/if I can simplify the passing of the return type and function name because I do need the function name as a separate token within the preprocessor to do token concatenation and generate unique names that refer to the function name...
Something like this should be possible (using tuples instead of sequences):
void, f, ( (int)(x) (double&)(y) (const bind)((a)(&b)) (bind)((&c)(d)) ) // [5] void, (f)( (int)(x) (double&)(y) (const bind)((a)(&b)) (bind)((&c)(d)) ) // [6]
And again, on C99:
void, f, (int x, double& y, const bind a, const bind& b, bind& c, bind d) // [7] void, (f)(int x, double& y, const bind a, const bind& b, bind& c, bind d) // [8]
However, I don't see how these are simpler than [0] and [2]. I need to think about this more to see if other syntaxes are possible...
Using tuple instead of sequences, could [4]
(void) (f)(int x, double& y) (const bind)(a, &b) (bind)(&c, d) // [4]
become
void, f, (int x, double& y) (const bind a, &b) (bind)(&c, d) // [4a]
?
Yep. Plus a few more _UNTESTED_ thoughts on results type and function name follow. Actually, the function name is not really needed as it can be specified just in the END macro (like END_RENAME does) so I could take it out: BOOST_LOCAL_FUNCTION( // [12] (void) (int x, double& y, const bind a, const bind& b, bind& c, bind d) ) { ... } BOOST_LOCAL_FUNCTION_END(f) f(1, 1.23); If I could remove also the parenthesis around the return type, it would be really cool because the macro parameter would match 100% the usual C++ syntax for function types :)) BOOST_LOCAL_FUNCTION( // [13] void (int x, double& y, const bind a, const bind& b, bind& c, bind d) ) { ... } BOOST_LOCAL_FUNCTION_END(f) f(1, 1.23); Too bad I don't think I can actually do this :( (given that `void` can be _any_ token so I cannot strip it out with the pp...). I might be able however to pull the return type outside the macro as in Alex-Steven's syntax: void BOOST_LOCAL_FUNCTION(int x, double& y, const bind a, // [14] const bind& b, bind& c, bind d) { ... } BOOST_LOCAL_FUNCTION_END(f) f(1, 1.23); And regardless of what Alex-Steven did, I could do this by expanding to a dummy variable/expression and then get its type with typeof (but the library will then require typeof to determine the result type even when no bound parameter is used and for a type which is specified by programmes as a type -- that'd be strange): void *result_ptr; // Plus append __LINE__... typedef typeof(*result_ptr) result_type; ... Then it would be better to pull the function name outside the end macro if I could (i.e., if I can program the correct default constructor for the local `function_ref`... which maybe I can't...): void BOOST_LOCAL_FUNCTION(int x, double& y, const bind a, // [15] const bind& b, bind& c, bind d) { ... } BOOST_LOCAL_FUNCTION_END f; f(1, 1.23); For non C99: void BOOST_LOCAL_FUNCTION( (int x) (double& y) (const bind a) // [16] (const bind& b) (bind& c) (bind d) ) { ... } BOOST_LOCAL_FUNCTION_END f; f(1, 1.23); With respect to the parenthesized syntax, this ad-hoc syntax for local functions does not make available to the preprocessor the followings: (1) return type; (2) function name; (3) separation between parameter type and name; But programmers might find this syntax more attractive. BTW, can I still specify the function parameters `auto` and `register` with this syntax as I can do with the parenthesized syntax? I don't know... Also, I don't think I can specify `inline` anymore... (but it's not clear if using `inline` optimizes local functions anyway so maybe not a big deal).
4 DEFAULT PARAMETER VALUES (C++ and C99 preprocessors)
Currently local functions support default parameters via the following parenthesized syntax:
(void) (f)( (int)(x)(default)(-1) (double)(y)(default)(1.23) ) // [9]
I think this could be simplified to (note the removal of the parenthesis around the default value):
(void) (f)( (int)(x)(default -1) (double)(y)(default 1.23) ) // [10]
An additional simplification could be to merge parameter types and names together as in [1]:
(void) (f)( (int x)(default -1) (double y)(default 1.23) ) // [10a]
Plus using C99 variadics as in [2]:
(void) (f)(int x, default -1, double y, default 1.23) // [11]
I am not a big fan of this because `default` is separated from its parameter by the comma `,`... but I don't think I can do better than this.
Why you can not use the = symbol? Could this be
(void) (f)(int x = -1, double y = 1.23) // [11a]
I tried a while back but it didn't work. I'll try again (i'll say why if I can't get `=` to work).
5 OTHERS CONSIDERATIONS
These considerations are not directly relevant to local functions but the parenthesized syntax [0] was designed as a general syntax that makes *all* the elements of a function declaration available for preprocessor metaprogramming. Instead, syntaxes [1] and [2] cannot separate the parameter type token from the parameter name token at preprocessing time. Therefore: <snip> Therefore, *IF* there was an interest in defining the parenthesized syntax to be as general as possible so it could be adopted everywhere macros spoil function definitions (to avoid requiring programmers to learn different syntaxes for the different macros), [0] is more general because it separates the parameter types from their names (at the cost of the extra parenthesis of course).
Of all of these syntaxes, I _personally_ like [0] because it is pure C++ preprocessor and it is the most general (maybe with simplification [10] for default parameters). I also would like to provide [2] if the C99 preprocessor is detected -- ideally, the same parsing macros will be smart enough to accept both [2] and [0] on C99 and just [0] on pure C++ preprocessors.
Lorenzo I understand your concern and that you need the general syntax for Boost.Contract. Whether this general syntax is adapted to Boost.Local also is what you are trying to analyze in this post.
I do think that Boost.Local should seek, at least in principle, the best syntax for local functions regardless of other libraries (Boost.Contract included). However, if a more general syntax could be adopted that would unify Boost.Local with the syntax of all other libraries that spoil function declaration at the cost of a few extra parenthesis, I think it would be a trade off to take into consideration. Also the only two Boosters that have actually used the parenthesized syntax so far (myself and Greg) said "the syntax was strange at first but I got used to it quickly" (Greg, please comment if that's not what you meant) -- I think that's important feedback to take into consideration and I would be interested to hear what others have to say after using the parenthesized syntax for a few days. Anyway, for now I am going back to the drawing board to seek the best syntax (including C99 features) for Boost.Local so after that we can compare it with the more general parenthesized syntax and decide together :) P.S. Parenthesized syntax for local functions (proposed Boost.Local): (void) (f)( (int)(x) (double&)(y) ) named parameters (adding parenthesized syntax support to Boost.Parameter): (void) (f)( (in)(int)(x) (inout)(double)(y) ) // I think this is cool! and contracts with named parameters (work-in-(slow)-progress Boost.Contract): (void) (f)( (in)(int)(x) (inout)(double)(y) ) (precondition)( (x > 0) ) (postcondition (old_y = CONTRACT_OLDOF(y) )( (y == x + old_y) ) concepts (adding parenthesized syntax support to Boost.ConceptCheck): (template)( (typename)(T) ) (requires)( (Addable<T>) ) (void) (f)( (T)(x) ) I know you guys think I'm crazy ;) -- Lorenzo

On 2/7/11 1:52 PM, Lorenzo Caminiti wrote:
Also the only two Boosters that have actually used the parenthesized syntax so far (myself and Greg) said "the syntax was strange at first but I got used to it quickly" (Greg, please comment if that's not what you meant) -- I think that's important feedback to take into consideration and I would be interested to hear what others have to say after using the parenthesized syntax for a few days.
You got it right, that was exactly what I meant. Thank you for all the work you have been putting into this project! :-) Cheers, Greg

AMDG On 2/7/2011 1:52 PM, Lorenzo Caminiti wrote:
Too bad I don't think I can actually do this :( (given that `void` can be _any_ token so I cannot strip it out with the pp...). I might be able however to pull the return type outside the macro as in Alex-Steven's syntax:
void BOOST_LOCAL_FUNCTION(int x, double& y, const bind a, // [14] const bind& b, bind& c, bind d) { ... } BOOST_LOCAL_FUNCTION_END(f) f(1, 1.23);
And regardless of what Alex-Steven did, I could do this by expanding to a dummy variable/expression and then get its type with typeof (but the library will then require typeof to determine the result type even when no bound parameter is used and for a type which is specified by programmes as a type -- that'd be strange):
void *result_ptr; // Plus append __LINE__... typedef typeof(*result_ptr) result_type; ...
That's almost what we did. void deduce_result(); typedef boost::function_traits< typeof(&deduce_result)>::result_type result_type; is a little better. (It can handle references.) In Christ, Steven Watanabe

On Mon, Feb 7, 2011 at 5:29 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
On 2/7/2011 1:52 PM, Lorenzo Caminiti wrote:
Too bad I don't think I can actually do this :( (given that `void` can be _any_ token so I cannot strip it out with the pp...). I might be able however to pull the return type outside the macro as in Alex-Steven's syntax:
void BOOST_LOCAL_FUNCTION(int x, double& y, const bind a, // [14] const bind& b, bind& c, bind d) { ... } BOOST_LOCAL_FUNCTION_END(f) f(1, 1.23);
And regardless of what Alex-Steven did, I could do this by expanding to a dummy variable/expression and then get its type with typeof (but the library will then require typeof to determine the result type even when no bound parameter is used and for a type which is specified by programmes as a type -- that'd be strange):
void *result_ptr; // Plus append __LINE__... typedef typeof(*result_ptr) result_type; ...
That's almost what we did.
void deduce_result(); typedef boost::function_traits< typeof(&deduce_result)>::result_type result_type;
is a little better. (It can handle references.)
This code doesn't compile on GCC (but it compiles on MSVC) within function template: #include <boost/typeof/typeof.hpp> #include <boost/type_traits.hpp> template<typename T> void g(T x) { T (deduce_result)(); typedef typename boost::function_traits< // Line 8 BOOST_TYPEOF(deduce_result)>::result_type result_type; struct s { result_type f(T& x) { return x; } // Line 12 } ss; ss.f(x); } void f(int x) { int& (deduce_result)(); typedef boost::function_traits< BOOST_TYPEOF(deduce_result)>::result_type result_type; struct s { result_type f(int& x) { return x; } } ss; ss.f(x); } int main() { g(1); f(1); return 0; } $ g++ -Wall -Werror -I../../.. r00.cpp r00.cpp: In member function ‘typename boost::function_traits<__typeof__ (boost::type_of::ensure_obj(deduce_result))>::result_type g(T)::s::f(T&) [with T = int]’: r00.cpp:14: instantiated from ‘void g(T) [with T = int]’ r00.cpp:29: instantiated from here r00.cpp:12: error: ‘deduce_result’ was not declared in this scope It looks like GCC expands `deduce_result` within the struct on line 12 when typename is used instead of resolving the type at the typedef on line 8... I don't really understand what is going on... any idea? $ g++ --version g++ (GCC) 4.3.4 20090804 (release) 1 Copyright (C) 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Thanks a lot! -- Lorenzo

Lorenzo Caminiti wrote:
On Mon, Feb 7, 2011 at 12:37 PM, Vicente Botet <vicente.botet@wanadoo.fr> wrote:
Lorenzo Caminiti wrote: Lorenzo I understand your concern and that you need the general syntax for Boost.Contract. Whether this general syntax is adapted to Boost.Local also is what you are trying to analyze in this post.
I do think that Boost.Local should seek, at least in principle, the best syntax for local functions regardless of other libraries (Boost.Contract included). However, if a more general syntax could be adopted that would unify Boost.Local with the syntax of all other libraries that spoil function declaration at the cost of a few extra parenthesis, I think it would be a trade off to take into consideration. Also the only two Boosters that have actually used the parenthesized syntax so far (myself and Greg) said "the syntax was strange at first but I got used to it quickly" (Greg, please comment if that's not what you meant) -- I think that's important feedback to take into consideration and I would be interested to hear what others have to say after using the parenthesized syntax for a few days.
The fact that not too many people has tried it is a symptom that people don't like it too much.
Anyway, for now I am going back to the drawing board to seek the best syntax (including C99 features) for Boost.Local so after that we can compare it with the more general parenthesized syntax and decide together :)
I don't think we will need to decide between them. Maybe you can provide two alternative syntax: one general that allows to declare functions with contracts, concepts, named parameters, local functions ... and more restrictive that can be used just to define simple local functions without adornments. I really think with this approach your library will have much more chances to be accepted and once your library accepted people would have the possibility to choose between both alternatives.
I know you guys think I'm crazy ;)
I need to recognize that I will never tried it, but only crazy people explores crazy domains showing that there is no limits to the innovation (The first exception library was done using macros and now we have them on the language) Thanks for the hard work you are doing, Vicente -- View this message in context: http://boost.2283326.n4.nabble.com/local-Simplifying-the-parenthesized-synta... Sent from the Boost - Dev mailing list archive at Nabble.com.

On 2/7/2011 11:08 AM, Lorenzo Caminiti wrote:
On Sun, Feb 6, 2011 at 10:26 AM, Vicente Botet<vicente.botet@wanadoo.fr> wrote:
The fact that you can not use variadic macros at work doesn't means that your library can not provide in addition variadic macros on compilers supporting them. I have no idea the work that this suppose, but if the interface could be more appealing your library will have much more people interested in.
Have you an idea of how the interface could be simplified if variadic macros were used?
The purpose of this email if to brainstorm possible ideas to simplify the parenthesized syntax. Sorry in advance if not all that I say is correct -- I haven't implemented it yet so I might be saying inaccurate/unfeasible things here and there. As always, your feedback is very welcome :)
PRELIMINARY IDEAS TO SIMPLIFY THE PARENTHESIZED SYNTAX
Consider the following parenthesized syntax for local functions:
(void) (f)( (int)(x) (double&)(y) (const bind)((a)(&b)) (bind)((&c)(d)) ) // [0]
The followings are possible ways to simply this syntax.
1 MERGING PARAMETER TYPES AND NAMES (C++ preprocessor)
Parameter names can be passed to function types so I can transform `int x` into `int` at compile-time:
int x --[make function type]--> void (int x) --[get 1st parm type]--> int
This should allow me to simplify the parenthesized syntax [0] to:
(void) (f)( (int x) (double& y) (const bind)((a)(&b)) (bind)((&c)(d)) ) // [1]
Note that the (unbound) parameter type and name are merged into a single sequence element.
The following should also be possible:
(void) (f)( (int x) (double& y) (const bind a) (const bind& b) (bind& c) (bind d) ) // [1a]
Is [1a] simpler than [1]? Maybe it is...
2 TOWARD THE NORMAL PARAMETER LIST SYNTAX (C99 preprocessor)
Using variadic macros I _might_ be able to use a variable length tuple (can I? I am not very familiar with these yet...) instead of a sequence to represent the function parameters:
(void) (f)(int x, double& y, const bind a, const bind& b, bind& c, bind d) // [2]
I think, this is a great simplification over [0] because it is the exact same syntax used by C++ to declare function parameters!
Please look at my variadic_macro_data library in the sandbox for how you can use variadic macros with the Boost PP library. And yes, variadic macros can give you a variable length number of elements. You can also use my library to get the number of elements of a Boost PP tuple as well as any element within the Boost PP tuple, and you can use my library to get the number of elements of variadic data as well as any element of the variadic data. The main thing to remember about variadic macros, which is their main limitation, is that within any variadic macro specified the variadic data must come at the end of the macro when the macro is defined using the ... notation.

On Mon, Feb 7, 2011 at 2:23 PM, Edward Diener <eldiener@tropicsoft.com> wrote:
On 2/7/2011 11:08 AM, Lorenzo Caminiti wrote:
2 TOWARD THE NORMAL PARAMETER LIST SYNTAX (C99 preprocessor)
Using variadic macros I _might_ be able to use a variable length tuple (can I? I am not very familiar with these yet...) instead of a sequence to represent the function parameters:
(void) (f)(int x, double& y, const bind a, const bind& b, bind& c, bind d) // [2]
I think, this is a great simplification over [0] because it is the exact same syntax used by C++ to declare function parameters!
Please look at my variadic_macro_data library in the sandbox for how you can
Yes, I will use your library when I start coding. Thanks a lot!
use variadic macros with the Boost PP library. And yes, variadic macros can give you a variable length number of elements. You can also use my library to get the number of elements of a Boost PP tuple as well as any element within the Boost PP tuple, and you can use my library to get the number of elements of variadic data as well as any element of the variadic data.
The main thing to remember about variadic macros, which is their main limitation, is that within any variadic macro specified the variadic data must come at the end of the macro when the macro is defined using the ... notation.
-- Lorenzo

On Mon, Feb 7, 2011 at 11:08 AM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
On Sun, Feb 6, 2011 at 10:26 AM, Vicente Botet <vicente.botet@wanadoo.fr> wrote:
The fact that you can not use variadic macros at work doesn't means that your library can not provide in addition variadic macros on compilers supporting them. I have no idea the work that this suppose, but if the interface could be more appealing your library will have much more people interested in.
Have you an idea of how the interface could be simplified if variadic macros were used?
Hello all, Based on some prototyping that I have done so far, I think I can simplify the local function macro syntax as follows using C99 variadics: void BOOST_LOCAL_FUNCTION_PARAMS(int x, double y, // [1] bind a, bind& b, const bind c, const bind& d) { ... } BOOST_LOCLA_FUNCTION_NAME(f) f(1, 1.23); ** Note that there are NO extra parenthesis!! :-)) ** What do you think? Is this simple enough? On non-C99 preprocessors, the above will need to use sequences instead of variable length tuples: void BOOST_LOCAL_FUNCTION_PARAMS( (int x) (double y) // [2] (bind a) (bind& b) (const bind c) (const bind& d) ) { ... } BOOST_LOCLA_FUNCTION_NAME(f) f(1, 1.23); This essentially introduces the same amount of extra parenthesis as Boost.ScopeExit does -- I hope it is acceptable especially because if you have C99 you can just use [1]. I can program the _same_ macros to accept both [1] and [2] on C99, and only [2] on non-C99 preprocessors. RECURSION, ETC The above macros have the important advantage of using NO extra parenthesis on C99 but they also have the following (small?) limitations: 1) They do not allow the local function to recursively call itself (because the function name is not specified until after the body is programmed so it is not available within the body for recursive calls). 2) They always require the use of Boost.Typeof to deduce the function result type (the library already requires Boost.Typeof for variable binding anyways). 3) They do not allow to specify the local function `inline` (I still have to confirm if making a local function `inline` -- which makes all the members of the local function's local class `inline` -- actually allows the compiler to optimize something... if not, this is a mud point). In most cases these limitations might not be significant. Regardless, programmers can always use the following alternative macros to eliminate these limitations (at the cost of some extra parenthesis in the syntax). On C99 (still no extra parenthesis in the parameter list): BOOST_LOCAL_FUNCTION( // [3] (int) (inline) (factorial)(int n, bind& calculations) { int result = 1; if (n > 1) result = n * factorial(n - 1); calculations << result << std::endl; } BOOST_LOCAL_FUNCTION_END(factorial) And, on non-C99 preprocessor (extra parenthesis also in the parameter list): BOOST_LOCAL_FUNCTION( // [4] (int) (inline) (factorial)( (int n) (bind& calculations) ) { int result = 1; if (n > 1) result = n * factorial(n - 1); calculations << result << std::endl; } BOOST_LOCAL_FUNCTION_END(factorial) Again, I can program the _same_ macros to accept both [3] and [4] on C99, and only [4] on non-C99 preprocessors. DEFAULTS Default parameter values can also be specified for both set of macros (but IMO defaults look a strange on C99...). On C99 with no recursion, Boost.Typeof for result type, and no inline: void BOOST_LOCAL_FUNCTION_PARAMS(int x, default -1, const bind& a) { // [5] ... } BOOST_LOCAL_FUNCTION_NAME(f) And, on non-C99 with same limitations: void BOOST_LOCAL_FUNCTION_PARAMS( (int x)(default -1) (const bind& a) ) { // [6] ... } BOOST_LOCAL_FUNCTION_NAME(f) Or, on C99 without the recursion, etc limitations: BOOST_LOCAL_FUNCTION( // [7] (int) (inline) (factorial)(int n, default 6, bind& calculations) { ... } BOOST_LOCAL_FUNCTION_END(factorial) And on non-C99 without the recursion, etc limitations: BOOST_LOCAL_FUNCTION( // [8] (int) (inline) (factorial)( (int n)(default 6) (bind& calculations) ) { ... } BOOST_LOCAL_FUNCTION_END(factorial) IMO the parenthesis `(int n)(default 6)` make the default value look better then the comma `int n, default 6`. The following could also be possible on C99: void BOOST_LOCAL_FUNCTION_PARAMS( (int x, default -1), const bind& a) { // [9] ... } BOOST_LOCAL_FUNCTION_NAME(f) But the introduced parenthesis are not necessary and I personally find the mixed use of the parenthesis and commas confusing. What do you think? NOTE: I need to separate defaults from the parameter type-name because defaults cannot be part of a function type. I need to use `default ...` instead of `= ...` because tokens need to start with alphanumeric symbols so I can concatenate them (PP_CAT) to program something like this "if the token starts with 'default' then do ..." in the preprocessor parsing macros. I am writing a Syntax Rationale section in the library documentation that lists all the alternative syntaxes that I have been exploring, their feasibility, and the reasons behind their adoption or rejection. Thanks! -- Lorenzo

On 10/02/11 15:59, Lorenzo Caminiti wrote:
On Mon, Feb 7, 2011 at 11:08 AM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
On Sun, Feb 6, 2011 at 10:26 AM, Vicente Botet <vicente.botet@wanadoo.fr> wrote:
The fact that you can not use variadic macros at work doesn't means that your library can not provide in addition variadic macros on compilers supporting them. I have no idea the work that this suppose, but if the interface could be more appealing your library will have much more people interested in.
Have you an idea of how the interface could be simplified if variadic macros were used?
Hello all,
Based on some prototyping that I have done so far, I think I can simplify the local function macro syntax as follows using C99 variadics:
void BOOST_LOCAL_FUNCTION_PARAMS(int x, double y, // [1] bind a, bind& b, const bind c, const bind& d) { ... } BOOST_LOCLA_FUNCTION_NAME(f) f(1, 1.23);
** Note that there are NO extra parenthesis!! :-)) ** What do you think? Is this simple enough?
Amazing! (I might argue that the parentheses around "f" are extra, but that would be churlish ;)) <snip>
The above macros have the important advantage of using NO extra parenthesis on C99 but they also have the following (small?) limitations:
1) They do not allow the local function to recursively call itself (because the function name is not specified until after the body is programmed so it is not available within the body for recursive calls). 2) They always require the use of Boost.Typeof to deduce the function result type (the library already requires Boost.Typeof for variable binding anyways).
You shouldn't need to use Typeof if you extract the return type in the manner Steven Watanabe suggested: #include <boost/mpl/assert.hpp> #include <boost/type_traits/function_traits.hpp> #include <boost/type_traits/is_same.hpp> #define EXTRACT_TYPE_BEFORE \ deduce_result(); \ typedef boost::function_traits< \ typeof(deduce_result)>::result_type result_type; int main() { void EXTRACT_TYPE_BEFORE BOOST_MPL_ASSERT((boost::is_same<result_type, void>)); } It even gives a (relatively) nice error when the user forgets the return type (on gcc 4.4): ‘deduce_result’ was not declared in this scope I share your hope that this syntax is enough to satisfy most of the objectors! Do check how they respond when misused, though; a little effort to improve error messages might go a long way. John

On Thu, Feb 10, 2011 at 4:13 PM, John Bytheway <jbytheway+boost@gmail.com> wrote:
You shouldn't need to use Typeof if you extract the return type in the manner Steven Watanabe suggested:
Also I think I have figured out a way for the PARAMS/NAME macros to support recursive calls so I am thinking not to provide the parenthesized syntax macros at all. The following code for C99: int main () { std::ostringstream output; int BOOST_LOCAL_FUNCTION_PARAMS(int n, bool recursion, default false, bind& output) { int result = 0; if (n < 2 ) result = 1; else result = n * factorial(n - 1, true); // Recursive call. if (!recursion) output << result << " "; return result; } BOOST_LOCAL_FUNCTION_NAME(factorial) std::vector<int> v; v.resize(3); v[0] = 1; v[1] = 4; v[2] = 7; std::for_each(v.begin(), v.end(), factorial); std::cout << output.str() << std::endl; return 0; } or for C++: ... int BOOST_LOCAL_FUNCTION_PARAMS( (int n) (bool recursion)(default false) (bind& output) ) { ... Expands to code equivalent to: int main () { std::ostringstream output; int // Result type (outside the `PARAMS` macro). // On all C++ preprocessors (including C99 preprocessors) the macro: // // int BOOST_LOCAL_FUNCTION_PARAMS( // (int n) (bool recursion)(default false) (bind& output) ) // // Or, on C99 preprocessors only the macro: // // int BOOST_LOCAL_FUNCTION_PARAMS( // int n, bool recursion, default false, bind& output) // // Expands to code equivalent to the following. // // NOTE: // * Use line number __LINE__ (e.g., 29) to generate unique symbols. // * Parameter name not available separately from its type. // * Function name NOT available. // In actual expansion, the following tokens are made available as macro // parameters (and not as macro symbols) by the `PARAMS` macro: #define PARAMS_arg_0 int n #define PARAMS_arg_with_dflt_0 PARAMS_arg_0 // No default. #define PARAMS_arg_1 bool recursion #define PARAMS_arg_with_dflt_1 PARAMS_arg_1 = false #define PARAMS_bind_0 &output #define PARAMS_is_const_bind_0 0 // Not a constant bind. // Function traits. // NOTE: Following result type specified just before the `PARAMS` macro. // Default parameter values need to be separated from their parameter types // and names because they are not part of the function type so they cannot // be used by the following expressions and their number cannot be count // at compile-time using template metaprogramming. ERROR_missing_result_type_at_line_29(PARAMS_arg_0, PARAMS_arg_1); /** @todo This typeof requires registration of result, arg, etc type? */ typedef BOOST_TYPEOF(ERROR_missing_result_type_at_line_29) function_type_29; typedef boost::function_traits<function_type_29>::result_type result_type_29; typedef boost::function_traits<function_type_29>::arg1_type arg_type_0_29; typedef boost::function_traits<function_type_29>::arg2_type arg_type_1_29; // Handle bound parameters as done by Boost.ScopeEixt, deducing their types // (using Boost.Typeof) and storing them by reference or by value. typedef void (*bind_deduce_type_0_29)(int PARAMS_bind_0); typedef BOOST_TYPEOF(boost::type_of::ensure_obj( boost::scope_exit::aux::wrap(boost::scope_exit::aux::deref( PARAMS_bind_0, static_cast<bind_deduce_type_0_29>(0))))) bind_wrapped_type_0_29; typedef bind_wrapped_type_0_29::type capture_bind_type_0_29; // Hold bound parameter types and values. struct binds_29 { typedef capture_bind_type_0_29 bind_type_0_29; boost::scope_exit::aux::member<bind_type_0_29, bind_deduce_type_0_29> bind_value_0_29; } params_29 = { { boost::scope_exit::aux::deref(PARAMS_bind_0, static_cast<bind_deduce_type_0_29>(0)) } }; // NOTE: The `args` variable is declared globally and not prefixed with // __LINE__ so it can be used by both the `PARAMS` and `NAME`. The special // template declaration type prevents this variable to be declared multiple // times within the same scope. boost::scope_exit::aux::declared<boost::scope_exit::aux::resolve< sizeof(boost_local_auxXargs)>::cmp1<0>::cmp2> boost_local_auxXargs; boost_local_auxXargs.value = ¶ms_29; // Functor for local function. class functor_29: // Base used to assign local functions to `function_ref` which can // then be passed as template parameter. public ::boost::local::aux::function_base<function_type_29, 1> { binds_29* binds; // Bound parameter values. public: explicit functor_29(): binds() {} result_type_29 operator()(arg_type_0_29 arg_0, arg_type_1_29 arg_1) { assert(binds); return body( binds->bind_value_0_29.value // Using general names `arg_i` because parameter types and // names are not separated by the preprocessor so the actual // argument name (e.g., `n`) is not available here. , arg_0, arg_1 ); } // Overloading to support default parameters. result_type_29 operator()(arg_type_0_29 arg_0) { assert(binds); return body( binds->bind_value_0_29.value , arg_0 ); } private: // LIMITATION: Body cannot be static because it has to access the // member named after the function name for recursive calls (the // function name is not know to this macro). However, ideally the body // will be static so to prevent using `this` instead of `this_` by // mistake (in most cases this will still cause a compile-time error // because when functor has a different structure than the bound object // `this_` -- but that is not the case if `this` is mistakenly used // instead of `this` to do pointer operations). Programmers need to // inspect the local function body code by eye and make sure that // `this` is not used by the body code. result_type_29 body( #if PARAMS_is_const_bind_0 ::boost::add_const< // Handle constant binding. #endif binds_29::bind_type_0_29 #if PARAMS_is_const_bind_0 >::type #endif PARAMS_bind_0 , PARAMS_arg_with_dflt_0 , PARAMS_arg_with_dflt_1) // Local function body (programmed outside the macros). { int result = 0; if (n < 2 ) result = 1; else result = n * factorial(n - 1, true); if (!recursion) output << result << " "; return result; } // All `..._29` and `PARAMS_...` symbols are only available for within `PARAMS` // macro expansion for the code above. #undef PARAMS_arg0 #undef PARAMS_dflt0 #undef PARAMS_arg1 #undef PARAMS_dflt1 #undef PARAMS_bind0 // The macro: // // BOOST_LOCAL_FUNCTION_NAME(factorial) // // Expands to code equivalent to the following. Note: // // * Use function name `factorial` to generate unique symbols. // * Function name `factorial` available. // * None of the `..._29` symbols are available (different __LINE__). // Public so it can be used to deduce local::function<> type to define // functor that can be passed as template parameter. public: // Member with function name for recursive calls. This cannot be // defined sooner because the function name is only available here. ::boost::local::function_ref<function_type_29, 1> factorial; // Cannot be programmed in the constructor because it also sets the // `factorial` member with name only known in this macro expansion. void init(void* bind_params) { binds = static_cast<binds_29*>(bind_params); factorial = *this; // For recursion. } } object_factorial; object_factorial.init(boost_local_auxXargs.value); BOOST_TYPEOF(object_factorial.factorial) factorial(object_factorial); // Rest of the program. std::vector<int> v; v.resize(3); v[0] = 1; v[1] = 4; v[2] = 7; std::for_each(v.begin(), v.end(), factorial); std::cout << output.str() << std::endl; return 0; } BTW, is there value in making functor_29's operator() and/or body functions inline? Thanks. -- Lorenzo

On 11/02/11 18:19, Lorenzo Caminiti wrote:
On Thu, Feb 10, 2011 at 4:13 PM, John Bytheway <jbytheway+boost@gmail.com> wrote:
You shouldn't need to use Typeof if you extract the return type in the manner Steven Watanabe suggested:
Also I think I have figured out a way for the PARAMS/NAME macros to support recursive calls so I am thinking not to provide the parenthesized syntax macros at all. <snip> // The macro: // // BOOST_LOCAL_FUNCTION_NAME(factorial) // // Expands to code equivalent to the following. Note: // // * Use function name `factorial` to generate unique symbols. // * Function name `factorial` available. // * None of the `..._29` symbols are available (different __LINE__).
// Public so it can be used to deduce local::function<> type to define // functor that can be passed as template parameter. public: // Member with function name for recursive calls. This cannot be // defined sooner because the function name is only available here. ::boost::local::function_ref<function_type_29, 1> factorial; // Cannot be programmed in the constructor because it also sets the // `factorial` member with name only known in this macro expansion. void init(void* bind_params) { binds = static_cast<binds_29*>(bind_params);
I'm puzzled; you say "None of the `..._29` symbols are available" but you're using both function_type_29 and binds_29 here...
factorial = *this; // For recursion. } } object_factorial; object_factorial.init(boost_local_auxXargs.value); BOOST_TYPEOF(object_factorial.factorial) factorial(object_factorial);
I imagine you can get rid of this TYPEOF call with function_traits too (with e.g. an appropriately defined member function in object_factorial?).
BTW, is there value in making functor_29's operator() and/or body functions inline?
It depends what you mean by "making" them inline. They're class member functions defined in a class body, so they're already *declared* inline. Adding the inline keyword will make no difference. However, IIRC from my previous experiments icc will not inline the virtual call through local::function<>, even though I think the standard allows it (and if icc won't do it, I doubt many other compilers will), so in practice they won't actually be inline (but should have only one indirection, which is good). I think two questions remain for you to consider: 1. Might anyone might want them *not* to be inline, because they're afraid of code bloat, and their compiler optimizer is so clever that it will inline them? I doubt this is an issue because (a) I don't know a compiler that clever and (b) a compiler that clever should be taking the risk of code bloat into effect. 2. Might anyone care so much about performance that they absolutely must have the code inlined? The answer is probably "yes" (or at least there will be people who *think* they care, which is also a problem). For these people you could, if you choose, provide an alternate implementation which doesn't indirect through local::function<>, and thus will only work in C++0x (or C++03 with non-standard extensions). Regardless, as I said last time, you should do some profiling and put the results in your docs so that both you and your users can make informed decisions. John Bytheway

On Fri, Feb 11, 2011 at 4:31 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
From: John Bytheway <jbytheway+boost@gmail.com>
Hi John, first of all, thank you very much for checking my code. Your feedback has been very helpful!
Date: Fri, 11 Feb 2011 20:36:40 +0000 Subject: Re: [boost] [local] Simplifying the parenthesized syntax To: boost@lists.boost.org
On 11/02/11 18:19, Lorenzo Caminiti wrote:
On Thu, Feb 10, 2011 at 4:13 PM, John Bytheway <jbytheway+boost@gmail.com> wrote: binds = static_cast<binds_29*>(bind_params);
I'm puzzled; you say "None of the `..._29` symbols are available" but you're using both function_type_29 and binds_29 here...
Yes, you are right. I cut-n-pasted the code with the `..._29`s from the constructor... Actually, I can move all the code into the constructor (this way the functors is also always well defined): int main () { std::ostringstream output; int // Result type (outside the `PARAMS` macro). // On all C++ preprocessors (including C99 preprocessors) the macro: // // int BOOST_LOCAL_FUNCTION_PARAMS( // (int n) (bool recursion)(default false) (bind& output) ) // // Or, on C99 preprocessors only the macro: // // int BOOST_LOCAL_FUNCTION_PARAMS( // int n, bool recursion, default false, bind& output) // // Expands to code equivalent to the following. // // NOTE: // * Use line number __LINE__ (e.g., 29) to generate unique symbols. // * Parameter name not available separately from its type. // * Function name NOT available. // In actual expansion, the following tokens are made available as macro // parameters (and not as macro symbols) by the `PARAMS` macro: #define PARAMS_arg_0 int n #define PARAMS_arg_with_dflt_0 PARAMS_arg_0 // No default. #define PARAMS_arg_1 bool recursion #define PARAMS_arg_with_dflt_1 PARAMS_arg_1 = false #define PARAMS_bind_0 &output #define PARAMS_is_const_bind_0 0 // Not a constant bind. // Function traits. // NOTE: Following result type specified just before the `PARAMS` macro. // Default parameter values need to be separated from their parameter types // and names because they are not part of the function type so they cannot // be used by the following expressions and their number cannot be count // at compile-time using template metaprogramming. ERROR_missing_result_type_at_line_29(PARAMS_arg_0, PARAMS_arg_1); /** @todo This typeof requires registration of result, arg, etc type? */ typedef BOOST_TYPEOF(ERROR_missing_result_type_at_line_29) function_type_29; typedef boost::function_traits<function_type_29>::result_type result_type_29; typedef boost::function_traits<function_type_29>::arg1_type arg_type_0_29; typedef boost::function_traits<function_type_29>::arg2_type arg_type_1_29; // Handle bound parameters as done by Boost.ScopeEixt, deducing their types // (using Boost.Typeof) and storing them by reference or by value. typedef void (*bind_deduce_type_0_29)(int PARAMS_bind_0); typedef BOOST_TYPEOF(boost::type_of::ensure_obj( boost::scope_exit::aux::wrap(boost::scope_exit::aux::deref( PARAMS_bind_0, static_cast<bind_deduce_type_0_29>(0))))) bind_wrapped_type_0_29; typedef bind_wrapped_type_0_29::type capture_bind_type_0_29; // Hold bound parameter types and values. struct binds_29 { typedef capture_bind_type_0_29 bind_type_0_29; boost::scope_exit::aux::member<bind_type_0_29, bind_deduce_type_0_29> bind_value_0_29; } params_29 = { { boost::scope_exit::aux::deref(PARAMS_bind_0, static_cast<bind_deduce_type_0_29>(0)) } }; // NOTE: The `args` variable is declared globally and not prefixed with // __LINE__ so it can be used by both the `PARAMS` and `NAME`. The special // template declaration type prevents this variable to be declared multiple // times within the same scope. boost::scope_exit::aux::declared<boost::scope_exit::aux::resolve< sizeof(boost_local_auxXargs)>::cmp1<0>::cmp2> boost_local_auxXargs; boost_local_auxXargs.value = ¶ms_29; // Functor for local function. class functor_29: // Base used to assign local functions to `function_ref` which can // then be passed as template parameter. public ::boost::local::aux::function_base<function_type_29, 1> { typedef ::boost::local::function_ref<function_type_29, 1> function_type; binds_29* binds_; // Bound parameter values. public: // Public so it can be used later to deduce function type where // __LINE__ postfixed symbols `..._29` are no longer available. function_type* deduce_function_type; explicit functor_29(void* binds): binds_(static_cast<binds_29*>(binds)) { init_recursion(); } result_type_29 operator()(arg_type_0_29 arg_0, arg_type_1_29 arg_1) { assert(binds_); return body( binds_->bind_value_0_29.value // Using general names `arg_i` because parameter types and // names are not separated by the preprocessor so the actual // argument name (e.g., `n`) is not available here. , arg_0, arg_1 ); } // Overloading to support default parameters. result_type_29 operator()(arg_type_0_29 arg_0) { assert(binds_); return body( binds_->bind_value_0_29.value , arg_0 ); } private: // LIMITATION: Body cannot be static because it has to access the // member named after the function name for recursive calls (the // function name is not know to this macro). However, ideally the body // will be static so to prevent using `this` instead of `this_` by // mistake (in most cases this will still cause a compile-time error // because when functor has a different structure than the bound object // `this_` -- but that is not the case if `this` is mistakenly used // instead of `this` to do pointer operations). Programmers need to // inspect the local function body code by eye and make sure that // `this` is not used by the body code. result_type_29 body( #if PARAMS_is_const_bind_0 ::boost::add_const< // Handle constant binding. #endif binds_29::bind_type_0_29 #if PARAMS_is_const_bind_0 >::type #endif PARAMS_bind_0 , PARAMS_arg_with_dflt_0 , PARAMS_arg_with_dflt_1) // Local function body (programmed outside the macros). { int result = 0; if (n < 2 ) result = 1; else result = n * factorial(n - 1, true); if (!recursion) output << result << " "; return result; } // All `..._29` and `PARAMS_...` symbols are only available for within `PARAMS` // macro expansion for the code above. #undef PARAMS_arg0 #undef PARAMS_dflt0 #undef PARAMS_arg1 #undef PARAMS_dflt1 #undef PARAMS_bind0 // The macro: // // BOOST_LOCAL_FUNCTION_NAME(factorial) // // Expands to code equivalent to the following. Note: // // * Use function name `factorial` to generate unique symbols. // * Function name `factorial` available. // * None of the `..._29` symbols are available (different __LINE__). // Member with function name for recursive calls. This cannot be // defined sooner because the function name is only available here. function_type factorial; // Cannot be programmed in the constructor because it sets the // `factorial` member with name only known in this macro expansion. void init_recursion() { factorial = *this; } } object_factorial(boost_local_auxXargs.value); // The struct type cannot be passed as template parameter but the function // type `function_ref<...>` deduced here can. BOOST_TYPEOF(*object_factorial.deduce_function_type) factorial( object_factorial); // Rest of the program. std::vector<int> v; v.resize(3); v[0] = 1; v[1] = 4; v[2] = 7; std::for_each(v.begin(), v.end(), factorial); std::cout << output.str() << std::endl; return 0; }
factorial = *this; // For recursion. } } object_factorial; object_factorial.init(boost_local_auxXargs.value); BOOST_TYPEOF(object_factorial.factorial) factorial(object_factorial);
I imagine you can get rid of this TYPEOF call with function_traits too (with e.g. an appropriately defined member function in object_factorial?).
I am not sure I understand... how would I do this? Even when I use function_traits above, the function type is determined using TYPEOF... int ERROR_missing_result_type_at_line_29(PARAMS_arg_0, PARAMS_arg_1); typedef BOOST_TYPEOF(ERROR_missing_result_type_at_line_29) function_type_29; // <-- Type of here. typedef boost::function_traits<function_type_29>::result_type result_type_29; typedef boost::function_traits<function_type_29>::arg1_type arg_type_0_29; typedef boost::function_traits<function_type_29>::arg2_type arg_type_1_29; Does this TYPEOF requires registration of the result, arg, etc types?
BTW, is there value in making functor_29's operator() and/or body functions inline?
It depends what you mean by "making" them inline. They're class member functions defined in a class body, so they're already *declared* inline. Adding the inline keyword will make no difference.
However, IIRC from my previous experiments icc will not inline the virtual call through local::function<>, even though I think the standard allows it (and if icc won't do it, I doubt many other compilers will), so in practice they won't actually be inline (but should have only one indirection, which is good).
Yes, I see. Then it is useless to provide a syntax that allows to optionally declare the local function inline: (int) (inline) (factorial)(...) // No use for this.
I think two questions remain for you to consider:
1. Might anyone might want them *not* to be inline, because they're afraid of code bloat, and their compiler optimizer is so clever that it will inline them? I doubt this is an issue because (a) I don't know a compiler that clever and (b) a compiler that clever should be taking the risk of code bloat into effect.
I agree.
2. Might anyone care so much about performance that they absolutely must have the code inlined? The answer is probably "yes" (or at least there will be people who *think* they care, which is also a problem). For these people you could, if you choose, provide an alternate implementation which doesn't indirect through local::function<>, and thus will only work in C++0x (or C++03 with non-standard extensions).
Without inheriting from local::function_base<> and then using local::function_ref<> the local struct cannot be passed as a template parameter in C++. Is this different for C++0x (C++03)? Otherwise, I am not sure I understand your point.
Regardless, as I said last time, you should do some profiling and put the results in your docs so that both you and your users can make informed decisions.
Yes, I will profile the code and add the analysis to the docs after I settle down the macro API and a reasonably stable implementation -- so hopefully soon :) Thanks again! -- Lorenzo

On 11/02/11 22:29, Lorenzo Caminiti wrote:
On Fri, Feb 11, 2011 at 4:31 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
From: John Bytheway <jbytheway+boost@gmail.com>
Hi John, first of all, thank you very much for checking my code. Your feedback has been very helpful!
:)
On 11/02/11 18:19, Lorenzo Caminiti wrote:
binds = static_cast<binds_29*>(bind_params);
I'm puzzled; you say "None of the `..._29` symbols are available" but you're using both function_type_29 and binds_29 here...
Yes, you are right. I cut-n-pasted the code with the `..._29`s from the constructor... Actually, I can move all the code into the constructor (this way the functors is also always well defined):
int main () { std::ostringstream output;
int // Result type (outside the `PARAMS` macro).
// On all C++ preprocessors (including C99 preprocessors) the macro: // // int BOOST_LOCAL_FUNCTION_PARAMS( // (int n) (bool recursion)(default false) (bind& output) ) // // Or, on C99 preprocessors only the macro: // // int BOOST_LOCAL_FUNCTION_PARAMS( // int n, bool recursion, default false, bind& output) // // Expands to code equivalent to the following. // // NOTE: // * Use line number __LINE__ (e.g., 29) to generate unique symbols. // * Parameter name not available separately from its type. // * Function name NOT available.
// In actual expansion, the following tokens are made available as macro // parameters (and not as macro symbols) by the `PARAMS` macro: #define PARAMS_arg_0 int n #define PARAMS_arg_with_dflt_0 PARAMS_arg_0 // No default. #define PARAMS_arg_1 bool recursion #define PARAMS_arg_with_dflt_1 PARAMS_arg_1 = false #define PARAMS_bind_0 &output #define PARAMS_is_const_bind_0 0 // Not a constant bind.
// Function traits. // NOTE: Following result type specified just before the `PARAMS` macro. // Default parameter values need to be separated from their parameter types // and names because they are not part of the function type so they cannot // be used by the following expressions and their number cannot be count // at compile-time using template metaprogramming. ERROR_missing_result_type_at_line_29(PARAMS_arg_0, PARAMS_arg_1); /** @todo This typeof requires registration of result, arg, etc type? */ typedef BOOST_TYPEOF(ERROR_missing_result_type_at_line_29) function_type_29; typedef boost::function_traits<function_type_29>::result_type result_type_29; typedef boost::function_traits<function_type_29>::arg1_type arg_type_0_29; typedef boost::function_traits<function_type_29>::arg2_type arg_type_1_29;
I'll suggest in passing that all of these names you're declaring at function scope should start "boost_local" to reduce the risk of clashing with any other libraries. I may be being excessively paranoid, given that you're already including the line number...
// Handle bound parameters as done by Boost.ScopeEixt, deducing their types
s/Eixt/Exit
// Functor for local function. class functor_29: // Base used to assign local functions to `function_ref` which can // then be passed as template parameter. public ::boost::local::aux::function_base<function_type_29, 1> { typedef ::boost::local::function_ref<function_type_29, 1> function_type; binds_29* binds_; // Bound parameter values.
Does the functor have this member when there are no bound values? I hope not.
public: // Public so it can be used later to deduce function type where // __LINE__ postfixed symbols `..._29` are no longer available. function_type* deduce_function_type;
I find it slightly distressing that this member is here, increasing sizeof(functor_29) even though it is only used for its type. I think it should still work as a static member, which might be better.
explicit functor_29(void* binds): binds_(static_cast<binds_29*>(binds)) { init_recursion(); } result_type_29 operator()(arg_type_0_29 arg_0, arg_type_1_29 arg_1) { assert(binds_); return body( binds_->bind_value_0_29.value // Using general names `arg_i` because parameter types and // names are not separated by the preprocessor so the actual // argument name (e.g., `n`) is not available here. , arg_0, arg_1 ); } // Overloading to support default parameters. result_type_29 operator()(arg_type_0_29 arg_0) { assert(binds_); return body( binds_->bind_value_0_29.value , arg_0 ); } private: // LIMITATION: Body cannot be static because it has to access the // member named after the function name for recursive calls (the // function name is not know to this macro). However, ideally the body // will be static so to prevent using `this` instead of `this_` by // mistake (in most cases this will still cause a compile-time error // because when functor has a different structure than the bound object // `this_` -- but that is not the case if `this` is mistakenly used // instead of `this` to do pointer operations). Programmers need to // inspect the local function body code by eye and make sure that // `this` is not used by the body code. result_type_29 body( #if PARAMS_is_const_bind_0 ::boost::add_const< // Handle constant binding. #endif binds_29::bind_type_0_29 #if PARAMS_is_const_bind_0 >::type #endif PARAMS_bind_0 , PARAMS_arg_with_dflt_0 , PARAMS_arg_with_dflt_1)
// Local function body (programmed outside the macros).
{ int result = 0; if (n < 2 ) result = 1; else result = n * factorial(n - 1, true);
if (!recursion) output << result << " "; return result; }
// All `..._29` and `PARAMS_...` symbols are only available for within `PARAMS` // macro expansion for the code above. #undef PARAMS_arg0 #undef PARAMS_dflt0 #undef PARAMS_arg1 #undef PARAMS_dflt1 #undef PARAMS_bind0
// The macro: // // BOOST_LOCAL_FUNCTION_NAME(factorial) // // Expands to code equivalent to the following. Note: // // * Use function name `factorial` to generate unique symbols. // * Function name `factorial` available. // * None of the `..._29` symbols are available (different __LINE__).
// Member with function name for recursive calls. This cannot be // defined sooner because the function name is only available here. function_type factorial;
Amusingly I think this member could be static too, although it would be rather odd and I'm not claiming it's a good idea. I'm just wondering whether minimizing sizeof(functor_29) could help optimizers. I have no particular evidence, and indeed it could make matters worse to have static members.
// Cannot be programmed in the constructor because it sets the // `factorial` member with name only known in this macro expansion. void init_recursion() { factorial = *this; } } object_factorial(boost_local_auxXargs.value);
You could declare object_factorial const. I feel you should.
// The struct type cannot be passed as template parameter but the function // type `function_ref<...>` deduced here can. BOOST_TYPEOF(*object_factorial.deduce_function_type) factorial( object_factorial);
This could be declared const too. Also, couldn't you use BOOST_TYPEOF(object_factorial.factorial) and omit deduce_function_type entirely? Perhaps you're doing it this way to support a non-recursive variant.
// Rest of the program.
std::vector<int> v; v.resize(3); v[0] = 1; v[1] = 4; v[2] = 7; std::for_each(v.begin(), v.end(), factorial);
std::cout << output.str() << std::endl; return 0; }
factorial = *this; // For recursion. } } object_factorial; object_factorial.init(boost_local_auxXargs.value); BOOST_TYPEOF(object_factorial.factorial) factorial(object_factorial);
I imagine you can get rid of this TYPEOF call with function_traits too (with e.g. an appropriately defined member function in object_factorial?).
I am not sure I understand... how would I do this? Even when I use function_traits above, the function type is determined using TYPEOF...
int ERROR_missing_result_type_at_line_29(PARAMS_arg_0, PARAMS_arg_1); typedef BOOST_TYPEOF(ERROR_missing_result_type_at_line_29) function_type_29; // <-- Type of here. typedef boost::function_traits<function_type_29>::result_type result_type_29; typedef boost::function_traits<function_type_29>::arg1_type arg_type_0_29; typedef boost::function_traits<function_type_29>::arg2_type arg_type_1_29;
Yes, you're right. I misread Steven's suggestion; sorry. You do indeed need typeof.
Does this TYPEOF requires registration of the result, arg, etc types?
I don't know. I've never used a compiler without proper typeof() support...
2. Might anyone care so much about performance that they absolutely must have the code inlined? The answer is probably "yes" (or at least there will be people who *think* they care, which is also a problem). For these people you could, if you choose, provide an alternate implementation which doesn't indirect through local::function<>, and thus will only work in C++0x (or C++03 with non-standard extensions).
Without inheriting from local::function_base<> and then using local::function_ref<> the local struct cannot be passed as a template parameter in C++. Is this different for C++0x (C++03)?
Yes, in C++0x local structs can be passed as template parameters. Obviously, in C++0x there are lambdas too, so you might think your library is useless, but I'd expect most compilers to support passing local structs as template parameters before they support lambdas, so there is some advantage in having this intermediate implementation. Also, your macros would allow writing code that worked in C++0x and C++03, with the virtual function business in only those compilers/modes where it is necessary. John

On Sat, Feb 12, 2011 at 5:50 AM, John Bytheway <jbytheway+boost@gmail.com> wrote:
On 11/02/11 22:29, Lorenzo Caminiti wrote:
On Fri, Feb 11, 2011 at 4:31 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
From: John Bytheway <jbytheway+boost@gmail.com>
typedef boost::function_traits<function_type_29>::arg1_type arg_type_0_29; typedef boost::function_traits<function_type_29>::arg2_type arg_type_1_29;
I'll suggest in passing that all of these names you're declaring at function scope should start "boost_local" to reduce the risk of clashing with any other libraries. I may be being excessively paranoid, given that you're already including the line number...
Yes, the macros generate symbols like `boost_local...<__LINE__>`. I tripped the prefixes in the code posted here just to make the code more readable.
class functor_29: // Base used to assign local functions to `function_ref` which can // then be passed as template parameter. public ::boost::local::aux::function_base<function_type_29, 1> { typedef ::boost::local::function_ref<function_type_29, 1> function_type; binds_29* binds_; // Bound parameter values.
Does the functor have this member when there are no bound values? I hope not.
No, it doesn't. I can strip all the unnecessary stuff.
public: // Public so it can be used later to deduce function type where // __LINE__ postfixed symbols `..._29` are no longer available. function_type* deduce_function_type;
I find it slightly distressing that this member is here, increasing sizeof(functor_29) even though it is only used for its type. I think it should still work as a static member, which might be better.
Yes, I can remove it. I can use the TYPEOF on the `factorial` member variable that is used to support recursion.
// Member with function name for recursive calls. This cannot be // defined sooner because the function name is only available here. function_type factorial;
Amusingly I think this member could be static too, although it would be rather odd and I'm not claiming it's a good idea. I'm just wondering whether minimizing sizeof(functor_29) could help optimizers. I have no particular evidence, and indeed it could make matters worse to have static members.
It could be static in theory but unfortunately local classes cannot have static member variables in C++ :( This is actually VERY unfortunate because if I can make the `factorial` member variable static then I can make the `body` function static so programmers cannot mistakenly use `this` instead of `this_` in the body code (yhe `body` needs to access the `factorial` member functor for recursive calls -- see LIMITATION in my code comments below).
// Cannot be programmed in the constructor because it sets the // `factorial` member with name only known in this macro expansion. void init_recursion() { factorial = *this; } } object_factorial(boost_local_auxXargs.value);
You could declare object_factorial const. I feel you should.
// The struct type cannot be passed as template parameter but the function // type `function_ref<...>` deduced here can. BOOST_TYPEOF(*object_factorial.deduce_function_type) factorial( object_factorial);
This could be declared const too. Also, couldn't you use
OK, I'll take a look at what can be declared const (maybe after I have fully implemented the new macros so I can regress the addition of const against all the examples).
BOOST_TYPEOF(object_factorial.factorial) and omit deduce_function_type entirely? Perhaps you're doing it this way to support a non-recursive variant.
Yep, done.
2. Might anyone care so much about performance that they absolutely must have the code inlined? The answer is probably "yes" (or at least there will be people who *think* they care, which is also a problem). For these people you could, if you choose, provide an alternate implementation which doesn't indirect through local::function<>, and thus will only work in C++0x (or C++03 with non-standard extensions).
Without inheriting from local::function_base<> and then using local::function_ref<> the local struct cannot be passed as a template parameter in C++. Is this different for C++0x (C++03)?
Yes, in C++0x local structs can be passed as template parameters. Obviously, in C++0x there are lambdas too, so you might think your library is useless, but I'd expect most compilers to support passing local structs as template parameters before they support lambdas, so there is some advantage in having this intermediate implementation. Also, your macros would allow writing code that worked in C++0x and C++03, with the virtual function business in only those compilers/modes where it is necessary.
OK, I understand. Yes, the code should be optimized for C++0x/C++03 (it should be easy to do). I'll work on these compiler-specific optimizations if the library gets accepted. Making the above changes, the code becomes: int main () { std::ostringstream output; int // Result type (outside the `PARAMS` macro). // On all C++ preprocessors (including C99 preprocessors) the macro: // // int BOOST_LOCAL_FUNCTION_PARAMS( // (int n) (bool recursion)(default false) (bind& output) ) // // Or, on C99 preprocessors only the macro: // // int BOOST_LOCAL_FUNCTION_PARAMS( // int n, bool recursion, default false, bind& output) // // Expands to code equivalent to the following. // // NOTE: // * Use line number `__LINE__` (e.g., `..._29`) to generate unique symbols. // * Parameter name not available separately from its type. // * Function name NOT available. // In actual expansion, the following tokens are made available as macro // parameters (and not as macro symbols) by the `PARAMS` macro: #define PARAMS_arg_0 auto int n #define PARAMS_arg_with_dflt_0 PARAMS_arg_0 // No default. #define PARAMS_arg_1 register bool recursion #define PARAMS_arg_with_dflt_1 PARAMS_arg_1 = false #define PARAMS_bind_0 &output #define PARAMS_is_const_bind_0 0 // Not a constant bind. // Function traits. // NOTE: Following result type specified just before the `PARAMS` macro. // Default parameter values need to be separated from their parameter types // and names because they are not part of the function type so they cannot // be used by the following expressions and their number cannot be count // at compile-time using template metaprogramming. ERROR_missing_result_type_at_line_29(PARAMS_arg_0, PARAMS_arg_1); /** @todo This typeof requires registration of result, arg, etc type? */ typedef BOOST_TYPEOF(ERROR_missing_result_type_at_line_29) function_type_29; typedef boost::function_traits<function_type_29>::result_type result_type_29; typedef boost::function_traits<function_type_29>::arg1_type arg_type_0_29; typedef boost::function_traits<function_type_29>::arg2_type arg_type_1_29; // Handle bound parameters as done by Boost.ScopeEixt, deducing their types // (using Boost.Typeof) and storing them by reference or by value. typedef void (*bind_deduce_type_0_29)(int PARAMS_bind_0); typedef BOOST_TYPEOF( boost::scope_exit::aux::wrap(boost::scope_exit::aux::deref( PARAMS_bind_0, static_cast<bind_deduce_type_0_29>(0)))) bind_wrapped_type_0_29; typedef bind_wrapped_type_0_29::type capture_bind_type_0_29; // Hold bound parameter types and values. struct binds_29 { typedef capture_bind_type_0_29 bind_type_0_29; boost::scope_exit::aux::member<bind_type_0_29, bind_deduce_type_0_29> bind_value_0_29; } params_29 = { // Must use this initializer because reference members. #if defined(__GNUC__) { // NOTE: Curly brakets are required by GCC but not supported by MSVC. #endif boost::scope_exit::aux::deref(PARAMS_bind_0, static_cast<bind_deduce_type_0_29>(0)) #if defined(__GNUC__) } // NOTE: Curly brakets are required by GCC but not supported by MSVC. #endif }; // NOTE: The `args` variable is declared globally and not prefixed with // __LINE__ so it can be used by both the `PARAMS` and `NAME`. The special // template declaration type prevents this variable to be declared multiple // times within the same scope. boost::scope_exit::aux::declared<boost::scope_exit::aux::resolve< sizeof(boost_local_auxXargs)>::cmp1<0>::cmp2> boost_local_auxXargs; boost_local_auxXargs.value = ¶ms_29; // Functor for local function. class functor_29: // Base used to assign local functions to `function_ref` which can // then be passed as template parameter. public ::boost::local::aux::function_base<function_type_29, 1> { public: explicit functor_29(void* binds): binds_(static_cast<binds_29*>(binds)) { init_recursion(); } result_type_29 operator()(arg_type_0_29 arg_0, arg_type_1_29 arg_1) { assert(binds_); return body( binds_->bind_value_0_29.value // Using general names `arg_i` because parameter types and // names are not separated by the preprocessor so the actual // argument name (e.g., `n`) is not available here. , arg_0, arg_1 ); } // Overloading to support default parameters. result_type_29 operator()(arg_type_0_29 arg_0) { assert(binds_); return body( binds_->bind_value_0_29.value , arg_0 ); } private: // Non local functor type that can be passed as template parameter. typedef ::boost::local::function_ref<function_type_29, 1> functor_type; // Hold bound parameter values. binds_29* binds_; // LIMITATION: Body cannot be static because it has to access the // member named after the function name for recursive calls (the // function name is not know to this macro). However, ideally the body // will be static so to prevent using `this` instead of `this_` by // mistake (in most cases this will still cause a compile-time error // because when functor has a different structure than the bound object // `this_` -- but that is not the case if `this` is mistakenly used // instead of `this` to do pointer operations). Programmers need to // inspect the local function body code by eye and make sure that // `this` is not used by the body code. result_type_29 body( #if PARAMS_is_const_bind_0 ::boost::add_const< // Handle constant binding. #endif binds_29::bind_type_0_29 #if PARAMS_is_const_bind_0 >::type #endif PARAMS_bind_0 , PARAMS_arg_with_dflt_0 , PARAMS_arg_with_dflt_1) // Local function body (specified by programmers outside the macros). { int result = 0; if (n < 2 ) result = 1; else result = n * factorial(n - 1, true); // Recursive call. if (!recursion) output << result << " "; return result; } // All `..._29` and `PARAMS_...` symbols are only available for within `PARAMS` // macro expansion for the code above. #undef PARAMS_arg0 #undef PARAMS_dflt0 #undef PARAMS_arg1 #undef PARAMS_dflt1 #undef PARAMS_bind0 // The macro: // // BOOST_LOCAL_FUNCTION_NAME(factorial) // // Expands to code equivalent to the following. Note: // // * Use function name `factorial` and/or line number `__LINE__` // (e.g., `..._31`) to generate unique symbols. // * Function name `factorial` available. // * None of the `..._29` symbols are available (different `__LINE__`). // Cannot be programmed in the constructor because it sets the // `factorial` member with name only known in this macro expansion. void init_recursion() { factorial = *this; } public: // Member with function name for recursive calls. This cannot be // defined sooner because the function name is only available here. // Also, it is public so it can be used to deduce the functor type // outside the expansion of the PARAMS macro (where the PARAMS symbols // are no longer available because of the different __LINE__ number). functor_type factorial; } functor_factorial_31(boost_local_auxXargs.value); // The struct type cannot be passed as template parameter but the function // type `function_ref<...>` deduced here can. BOOST_TYPEOF(functor_factorial_31.factorial) factorial( functor_factorial_31); // Rest of the program. // Factorial of a single number. factorial(3); // Call local function. std::vector<int> v; v.resize(3); v[0] = 1; v[1] = 4; v[2] = 7; // Factorials of all vector's elements. std::for_each(v.begin(), v.end(), factorial); // Pass as template parameter. std::cout << output.str() << std::endl; return 0; } -- Lorenzo

On 12/02/11 16:42, Lorenzo Caminiti wrote:
On Sat, Feb 12, 2011 at 5:50 AM, John Bytheway
// Member with function name for recursive calls. This cannot be // defined sooner because the function name is only available here. function_type factorial;
Amusingly I think this member could be static too, although it would be rather odd and I'm not claiming it's a good idea. I'm just wondering whether minimizing sizeof(functor_29) could help optimizers. I have no particular evidence, and indeed it could make matters worse to have static members.
It could be static in theory but unfortunately local classes cannot have static member variables in C++ :(
I didn't know that. Crazy limitations, but I guess it makes sense in retrospect. I wonder if this limitation is also removed in C++0x? However, on reflection I realised that it wouldn't work anyway (at least when there are bound variables) because the function that the contained the local function would not then be re-entrant. If it were called while the functor object was extant then another version of the same functor would be created and mess with this variable, after which the outer functor would behave incorrectly when performing a recursive call (it would e.g. have dangling references to the bound variables).
This is actually VERY unfortunate because if I can make the `factorial` member variable static then I can make the `body` function static so programmers cannot mistakenly use `this` instead of `this_` in the body code (yhe `body` needs to access the `factorial` member functor for recursive calls -- see LIMITATION in my code comments below).
A shame, yes, but I wouldn't go so far as to say VERY unfortunate :).
Yes, in C++0x local structs can be passed as template parameters. Obviously, in C++0x there are lambdas too, so you might think your library is useless, but I'd expect most compilers to support passing local structs as template parameters before they support lambdas, so there is some advantage in having this intermediate implementation. Also, your macros would allow writing code that worked in C++0x and C++03, with the virtual function business in only those compilers/modes where it is necessary.
OK, I understand. Yes, the code should be optimized for C++0x/C++03 (it should be easy to do). I'll work on these compiler-specific optimizations if the library gets accepted.
Well, at the rate reviews go lambdas might be in place in most compilers by the time you library is accepted :(. But let's hope it goes faster than that :). John

On Sat, Feb 12, 2011 at 1:57 PM, John Bytheway <jbytheway+boost@gmail.com> wrote:
On 12/02/11 16:42, Lorenzo Caminiti wrote: Well, at the rate reviews go lambdas might be in place in most compilers by the time you library is accepted :(. But let's hope it goes faster than that :).
Why C++0x lambdas don't support constant binding? Constant binding is instead supported by Boost.Local. I looked over N2550, N2529, etc but I could only see binding by value and reference and not by constant value and constant references?! I must be missing something... -- Lorenzo

[Lorenzo Caminiti]
Why C++0x lambdas don't support constant binding?
Constant binding is instead supported by Boost.Local. I looked over N2550, N2529, etc but I could only see binding by value and reference and not by constant value and constant references?! I must be missing something...
By default, lambdas' function call operators are const, so variables captured by copy can't be modified. Of course, this doesn't affect variables captured by reference. N3225 5.1.2 [expr.prim.lambda]/5: "This function call operator is declared const (9.3.1) if and only if the lambda-expression's parameter-declaration-clause is not followed by mutable." Stephan T. Lavavej Visual C++ Libraries Developer
participants (8)
-
Edward Diener
-
Gregory Crosswhite
-
Jeffrey Lee Hellrung, Jr.
-
John Bytheway
-
Lorenzo Caminiti
-
Stephan T. Lavavej
-
Steven Watanabe
-
Vicente Botet