
On Fri, Feb 4, 2011 at 7:35 AM, Artyom <artyomtnk@yahoo.com> wrote:
From: Gregory Crosswhite <gcross@phys.washington.edu>
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... -- Lorenzo