Boost logo

Boost :

Subject: Re: [boost] [local] Simplifying the parenthesized syntax
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2011-02-07 16:52:23


On Mon, Feb 7, 2011 at 12:37 PM, Vicente Botet <vicente.botet_at_[hidden]> 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

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk