
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