Boost logo

Boost :

Subject: Re: [boost] New libraries implementing C++11 features in C++03
From: Dean Michael Berris (mikhailberis_at_[hidden])
Date: 2011-11-24 05:57:14


On Thu, Nov 24, 2011 at 8:16 PM, Lorenzo Caminiti <lorcaminiti_at_[hidden]> wrote:
> On Wed, Nov 23, 2011 at 8:11 PM, Joel de Guzman
> <joel_at_[hidden]> wrote:
>>
>> If you've read the Spirit docs, you will know what that means.
>>
>> Now having said that, and before I leave this thread, let me remind
>> everyone that **you can also have statement syntax in Phoenix** if you
>> have a complex statement and you fear writing complex phoenix lambda
>> expressions. It's called phoenix::functions.
>>
>> In fact here's what I advocate:
>>
>> 1) For simple 1-2-3 liners, use a phoenix lambda expression. It's hard
>>   to get them wrong. For example, you'll have to be absurdly dumb to
>>   get this wrong:
>>
>>     auto plus = _1 + _2;
>>
>> 2) For more complex expressions, especially those involving statements,
>>   use a phoenix function plus a simple lambda expression that forwards
>>   to the phoenix function. Example:
>>
>>     for_each(f, l, call_complex_function(_1));
>
> IF (this is a big IF) I understand it correctly, Phoenix functions are
> non-local functors:
> http://www.boost.org/doc/libs/1_48_0/libs/phoenix/doc/html/phoenix/starter_kit/lazy_functions.html
>
> // non-local scope
> struct is_odd_impl
> {
>    typedef bool result_type;
>
>    template <typename Arg>
>    bool operator()(Arg arg1) const
>    {
>        return arg1 % 2 == 1;
>    }
> };
>
> // local scope
> function<is_odd_impl> is_odd;
>
> A couple of people have argued that for complex task it is OK to push
> the code to non-local scope. That is their point of view but of course
> it goes fundamentally against local functions principles (e.g., N2511)
> and the fact that even local functions can be long in some programming
> style (as expressed by others commenting before).
>

Lorenzo, I think you've done a good job of implementing the currently
proposed library for inclusion. I do not doubt that your solution
works and in your eyes it's as close to perfect as you can make it.

BUT (and this is a big BUT), even after reading your documentation,
I'm still unconvinced that local functions are an elegant solution to
the problem they're purportedly meant to solve.

C++ (and if I know my C correctly, even C) has gone fine without local
functions. What C++11 already has right now is much more powerful than
just local functions in lambdas.

The only difference between a local function and a non-local function
is where it's located. If the function is named appropriately and is
located in a convenient location (i.e. logically outside any given
function) I and the hundreds and thousands of other C++ programmers
don't see what the problem is with non-location functions. One thing I
do see that is a problem with local functions the way you implement it
are:

1. They're not real functions. That means I cannot refer to it inside
a function pointer. Which means the myriad libraries that take
function pointers out there won't be able to leverage whatever local
function objects made with your library.

2. They clutter up my current function's scope. Instead of being
defined in-line like C++11 lambdas, Boost.Phoenix lambda's,
Boost.Lambda lambda's, and Boost.Bind lambda's, they're being defined
outside the point of usage. The difference between the function being
defined in-line (as in C++11 lambdas) and not in-line is *HUGE*
(difference between 0 and at least one) while the difference between a
function defined in a function's scope and outside the function's
scope is marginal at best.

3. I cannot, no matter how I look at your examples and the "logic"
behind the concept of local functions, comprehend why this is a good
way to organize code. Aren't we all past the phase yet of functions
that have more than 10 lines of code?

The advantages of having a function (a logical piece of code that's
meant to be used as a unit *anyway*) at namespace scope or class scope
is that re-usability is something you get for free. On the other hand,
defining a local function with Boost.Local that I'd want to define as
an external function at some point (because oh I don't know I want to
use the same function somewhere else all of a sudden) will be too much
work with all the macro voodoo that I have to wade through.

I (and maybe others as well who follow the same logic I follow) don't
see a large enough gap between C++11 lambdas and
Boost.Phoenix/Lambda/Bind function objects that merits being addressed
by local functions. Until you can convince us that local functions are
"absolutely necessary" and that C++ should have it because it makes
certain programming paradigms/techniques possible, I'm afraid what you
have is a solution that's looking for a problem.

> IMO, our library users should be felt the opportunity to program as
> they see more fit to themselves and their problem domain (long/short
> local functions, long/short global Phoenix functions, long/short
> Phoenix lambdas ( yes, even long Phoenix lambdas if the users want to)
> ).

I agree 100%. I still don't think though for your library to succeed
that it has to be in Boost.

Cheers

-- 
Dean Michael Berris
http://goo.gl/CKCJX

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