Boost logo

Boost :

Subject: Re: [boost] Case study: Boost.Local versus Boost.Phoenix
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2011-02-05 19:22:03


On Sat, Feb 5, 2011 at 3:52 PM, Lorenzo Caminiti <lorcaminiti_at_[hidden]> wrote:
> On Fri, Feb 4, 2011 at 7:35 AM, Artyom <artyomtnk_at_[hidden]> wrote:
>>
>>
>>> From: Gregory Crosswhite <gcross_at_[hidden]>
>>>
>>> Hey everyone,
>>>
>>> This e-mail is going to be a case study of my personal  experience in
>>>converting code
>>> using Boost.Local to use Boost.Phoenix instead in  order to get insight into
>>>the
>>> similarities and differences in what the libraries  have to offer.
>>>
>>> [snip]
>>>
>>>
>>>          BOOST_LOCAL_FUNCTION(
>>>              (void) (checkSolution)(
>>>                  (const StandardFormParameters&)(parameters)
>>>                  (const  OperatorSpace&)(space)
>>>              )
>>>         ) {
>>>              checkRegion(Z,space.getOMatrix().slice(
>>>                   parameters.z_bit_diagonal_size
>>>                  ,space.number_of_qubits
>>>                  ,0u
>>>                  ,space.number_of_operators
>>>              ));
>>>         }  BOOST_LOCAL_FUNCTION_END(checkSolution)
>>>          forEachStandardFormSolution(
>>>               number_of_qubits
>>>              ,number_of_operators
>>>              ,list_of(EveryColumnHasZ)
>>>              ,checkSolution
>>>         );
>>>
>>
>>
>> I'm sorry is it only me or it would be much more readable
>> and maintainable to write:
>>
>> namespace {
>>   struct my_lambda  {
>>       foo_type &foo;
>>       bar_type &bar
>>       my_lambda(foo_type &local_foo,bar_type &local_bar) :
>>           foo(local_foo),
>>           bar(local_bar)
>>       {
>>       }
>>
>>       void operator()(a_type a) const
>>       {
>>             /// Your body goes there
>>       }
>>
>>   };
>> }
>>
>> void my_function()
>> {
>>    foo_type foo;
>>    bar_type bar;
>>
>>    my_lambda lambda(foo,bar);
>>    for_each(as.begin(),as.end(),lambda);
>>    // or something else
>> }
>
> 1) No, it's not only you. From Stroustrup's Glossary
> http://www2.research.att.com/~bs/glossary.html :
>
> local function - function defined within a function. Not supported by
> C++. Most often, the use of a local function is a sign that a function
> is too large.
>
> So the creator of C++ would probably argue that you should pull out
> the code into a separate functor (exactly as you did above) and make
> your enclosing function `my_function` smaller. What you propose is
> DEFINITELY one approach.* (I tried to make this point in the library
> docs.)
>
> (*) Note that one (small?) issue with your code if that you have to
> repeat the bound types `foo_type` and `bar_type` in different places.
> That might complicate maintainability (if you change the types within
> the enclosing function `my_function` you need to change them in the
> `my_lambda` function as well but syntactically they are not linked and
> they could be defined in two completely different places in the code
> -- you could have a global typedef, but that's even less "local" than
> your code... then what if everyone else starts using the same
> typedef...). Semantically instead these types must always be the same
> and it would be nice if you could capture such information.
> Boost.Local uses typeof so you don't have to worry about this (maybe
> you could rework your example to also use typeof if this was really
> important but then you have even more noise code...). (I tried to make
> this point in the library docs.)
>
> 2) However, local functions really are a form of *information hiding*
> (http://en.wikipedia.org/wiki/Nested_function#Purpose). This is not
> achieved at all by your example because the information about
> `my_lambda` declaration and definition is not hidden within the scope
> of its user `my_function`. If you don't need this form of information
> hiding, it's fine, you really don't have to use it. I found it useful
> myself (other Pascal and Ada programmers _might_ argue the same given
> that they are accustomed to using local functions as they have
> language support for it; I personally used them when I programmed in
> Turbo Pascal back in the days ;) ).
>
> 3) I also needed local functions because I needed a macro to expand locally:
>
>   void f(int& zero) {
>       BLOCK_INVARIANT( (const (zero) (zero == 0)) ) // Compiler error
> if programmers mistake `==` with `=`.
>       ...
>   }
>
> I can do this with Boost.Local:
>
>   void f(int& zero) {
>       BOOST_LOCAL_BLOCK( (const bind)((&zero)) ) {
>           assert(zero == 0);
>       } BOOST_LOCAL_BLOCK_END
>       ...
>   }
>
> There's no way I can program `BLOCK_INVARIANT` to expand to code
> outside `f` (like in the code you proposed) because macros are always
> expanded right where they are invoked. So for this one use case, your
> code just doesn't do the trick...

2a) Also I forgot to reference N2511
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2511.html)
for a discussion on why named lambdas / local functions are useful and
should be added to standard. (Again, this is mentioned in Boost.Local
docs.)

-- 
Lorenzo

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