Boost logo

Boost :

Subject: Re: [boost] [local_function] any interest in a LocalFunction library?
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2010-09-15 13:55:15


On Wed, Sep 15, 2010 at 10:56 AM, Lorenzo Caminiti
<lorcaminiti_at_[hidden]> wrote:
> On Sun, Aug 22, 2010 at 11:09 AM, Lorenzo Caminiti
> <lorcaminiti_at_[hidden]> wrote:
>> Hello all,
>>
>> Is there interest in a library that implement local functions for C++?
>>
>>
>> Boost.LocalFunction (PROPOSAL DRAFT)
>
> Hello all,
>
> Based on our discussions so far (thanks a lot for all the input!) I am
> starting to make some actual design decisions. These decisions are not
> final and they are of course subject to continuous improvement and
> necessary changes that will be identified by Boosters during the
> formal review of the library. However, for the current development
> stage of the library I will make these decisions and move forward
> (otherwise I keep changing things forever).
>
> If you have a strong opinion on any of these topics, please voice your
> opinion _now_ so to minimize the amount of my re-work later :)
>
> CURRENT STATUS
>
> 1) I will name the library Boost.Local and this will include local
> functions (BOOST_LOCAL_FUNCTION/BOOST_LOCAL_FUNCTION_END/BOOST_LOCAL_FUNCTION_END_RENAME)
> as well as local constant blocks
> (BOOST_LOCAL_CONST/BOOST_LOCAL_CONST_END).
>
> 2) I will require users to use `this_` instead of `this` inside local
> functions when the enclosing object is bound. The local function is
> internally implement as a _static_ member of a local class so `this`
> will simply not be available and it cannot be used by mistake instead
> of `this_`.
>
> 3) I will use the `bind` preprocessor "keyword" for the parenthesized
> syntax as in `(bind)(...)` and `(const bind)(...)`. `bind` is more
> readable than `bound` or `closure` (plus I do not know English well
> enough to figure out if `bound` is more correct because it is used in
> declarative as supposed as imperative context... English native
> speakers: Help me!).
>
> 4) Local functions will use a trick that will allow them to be passed
> as template parameters (this is not possible for plain member
> functions of local classes). This will allow to pass local functions
> to algorithms like `std::for_each` which is a major use case of C++0x
> lambdas. (Still local functions will suffer the important limitations
> that they cannot be defined at expression level and they cannot have
> template parameters.)
>
> 5) When used within a template, the macros `BOOST_LOCAL_FUNCTION_TPL`,
> `BOOST_LOCAL_CONST_TPL`, etc will need to be used (otherwise you get a
> compiler error). This is necessary for the library to apply `typename`
> from within the template where the type determination is context
> depend (and given that C++ does not allow to use `typename` outside
> templates). The same convention is used by Boost.ScopeExit, etc.
>
> 6) Local functions will support recursion.
>
> 7) Local functions will support optional default values for non-bound
> parameters (as usual for C++ functions).
>
> 8) I will not provide the `BOOST_LOCAL_BLOCK` but only the
> `BOOST_LOCAL_CONST`. The only reason for `BOOST_LOCAL_BLOCK` would be
> to break to its exit using `return` and a local function executed
> immediately after it is defined can be used for that purpose.
>
> 9) I will not allow a local function to "inherit" from another local
> function. It seems there is no use case for such a feature (and I am
> not really sure how to define this behavior in the first place because
> inheritance makes sense between objects and not between functions...
> see related Boost email thread).
>
> 10) I will not merge Boost.Local with Boost.ScopeExit into a more
> generic Boost.Scope library. However, I will provide macros
> `BOOST_LOCAL_EXIT/BOOST_LOCAL_EXIT_END` which will work like
> Boost.ScopeExit plus they will allow to bind `this`. Boost.ScopeExit
> does not allow to bind `this` correct?
>
> OPEN ISSUES
>
> a) I am not sure if local functions can be nested into one another. In
> other words, I do not yet know if it will be possible to define a
> local function from within another local function.
>
> b) I am not sure if I will provide unnamed local functions (void or
> not) and if so what their syntax will look like. It seems if you need
> this you can just use the local functions macros to program it without
> a dedicated syntax (but still discussing...).
>
> c) I am not sure if I will provide local functions that execute
> immediately after they are defined. This might relate to b). Again, if
> you need this you can simply call the local function right after you
> define it without a dedicated syntax (but still discussing...).
>
> (I will eventually document all these points, and more, in the library
> documentation under the "Rational" section.)

As of right now, local function will be implemented more or less using
the following skeleton code (many thanks to John Bytheway for refining
my global base functors trick):

#include <iostream>
#include <algorithm>
#include <vector>

// Must be global type so lfn inheriting from this can be passed as tparam.
template<typename F> struct lfn_ftor_base {};
template<typename R, typename A1> struct lfn_ftor_base<R (A1)>
    // Abstract so never returns R (R could be void, have no default ctor, etc).
    { virtual R operator()(A1) = 0; };

// Wrap lfn functor ref in global type so it can be passed as tparm.
template<typename F> struct lfn_ftor_ref {};
template<typename R, typename A1> struct lfn_ftor_ref<R (A1)> {
    typedef R (f_type)(A1);
    explicit lfn_ftor_ref(lfn_ftor_base<f_type>& ftor): ftor_(ftor) {}
    inline R operator()(A1 a1) { return ftor_(a1); }
private:
    lfn_ftor_base<f_type>& ftor_;
};

int main () {
    double x = 5.6;

    // BOOST_LOCAL_FUNCTION(
    // (inline) (void) (lfn)( (int)(i) (const bound)((&x)) )
    // ) {
    // std::cout << " " << i + x;
    // if (i > 0) lfn(-i); // Recursive call.
    // } BOOST_LOCAL_FUNCTION_END(lfn)

    // Implementation of a local function named `lfn`.
    struct lfn_ftor: lfn_ftor_base<void (int)> {
        typedef void (f_type)(int);
        explicit lfn_ftor(double const& x): bound_x_(x) {}
        // Implement abstract base functor.
        inline void operator()(int i) { lfn(i); }
    private:
        // Bound params hold in a member variable (this example hides all
        // ScopeExit-like bound param type determination code).
        double const& bound_x_;
        // Member with local func name to allow recursion.
        inline void lfn(int i) { body(i, bound_x_); }
        // Body func cannot be static to allow recursive calls to `lfn`
        // (limitation: `this` available also when `this_` should be used).
        // Ultimately, bound params must be passed as func param because their
        // name is not know to preprocessor (it can prefixed by `&`).
        inline void body(int i, double const& x) {
            std::cout << " " << i + x;
            if (i > 0) lfn(-i); // Recursive call.
        }
    };
    lfn_ftor lfn_obj(x); // x is const& bound from scope.
    lfn_ftor_ref<lfn_ftor::f_type> lfn(lfn_obj);

    std::vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);

    std::cout << "v: ";
    std::for_each(v.begin(), v.end(), lfn);
    std::cout << std::endl;

    return 0;
}

-- 
Lorenzo

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