Boost logo

Boost :

Subject: Re: [boost] Case study: Boost.Local versus Boost.Phoenix
From: Gregory Crosswhite (gcross_at_[hidden])
Date: 2011-02-04 16:47:58


On 2/4/11 12:39 PM, Phil Endecott wrote:
>
> The main complaint about that from the advocates of both Pheonix and
> Local seems to be that it's too far from the point of use.

True, but we're not saying that it's the end of the world for the
function to be so far away, just that we think in many situations that
the code is clearer when it is right next to the point of use.

Also, the other main complaint is that function objects require writing
extra boilerplate.

> Well, I have to ask how big your functions are, and if they're huge, why?

It doesn't matter whether the function is big or small; it still helps,
in my opinion, to have everything that the function needs contained
within the function and declared as close to the point of use as possible.

And this is not a new fancy foreign idea but one that we already use
with variables; that is, rather than writing code like this:

f(...) {
     int a, b, c;
     ...
     a = value;
     ...
     b = value;
     ...
     c = value;
}

the idiomatic style in C++ is to declare variables right at the point of
first use like this:

f(...) {
     ...
     int a = value;
     ...
     int b = value;
     ...
     int c = value;
}

It doesn't matter whether f() is big or small, it is still idiomatic to
put the declarations right next to where the variable is first used.
BOOST_LOCAL_FUNCTION is nothing more than an extension of this idea to
nested functions.

> Also do you dislike code like this:
>
> void f1(args) { ........ }
>
> void my_big_fn() {
> ....
> ....
> ....
> f1(a); // using a function only to avoid duplicating the
> f1(b); // same code for a and b.
> ....
> }
>
> because the definition of f1 is far from where it's used?

It depends on the situation. If the best solution really is to write a
function "f1" in this case and f1 were relatively small and not being
used outside of my_big_fn then I would prefer that it be declared right
where it is being used for the same reasons that I have said before ---
which again are the same reasons that we declare variables close to
their point of use --- even if my_big_fn is really my_small_fn.

Of course, if f1 is much bigger than my_fn then there might be times
when it makes sense to separate it out anyway because its presence
breaks up the logic of my_fn too much and so decreases readability. Or
if f1 were sufficiently non-trivial then I would be likely to separate
it out so that I could more easily run test cases against it.

There isn't a one-size-fits-all rule, but in general I would claim that
there are many cases where it is at least not unreasonable to want to
put the function right before it is used.

> Would you countenance using a macro instead:?
>
> #define f1(arg) ....
> f1(a);
> f1(b);
>

Again, it depends. If we're talking about just a couple of lines that I
want to refactor then I would be more likely to use a macro.

Keep in mind though that the use case for which I have mainly been using
this library is not the case where I wrote a function for the sake of
refactoring code I had copied and pasted but rather the case where I
wanted to pass a local function to another function.

> Perhaps it comes down to this: we're used to functions being
> relatively far from where they're used because it has always been like
> that, but we think of these lambda expressions as taking the place of
> the body of a loop, and we're not used to that being out-of-line.
>
Interesting point.

Along these lines, I will repeat my remark that there is some similarity
in this situation to how we like having BOOST_FOREACH available to us
even though we could theoretically accomplish the same thing using a
function object and boost::for_each or std::for_each.

> Anyway, I'm just going to wait for C++0x lambdas.
>

Well lucky for you, the Boost.Local manual actually has a clause in it
that says that you don't have to use it if you don't want to. :-)

But on a more serious note, nobody here is claiming that
BOOST_LOCAL_FUNCTION is the best tool to use in all situations or that
everyone has to use it. All that we are claiming (and again, I say this
not as a developer but as a user who was made very happy by this
library) is that it is a good general tool to have available and that
many people and situations would benefit from it.

Finally, it is worth mentioning that although you might be lucky enough
to be able to use C++0x lambdas in the near future, many of us won't be
able to rely on them being available on all of the platforms for which
we want to develop for a long time, just as we won't be able to rely on
rvalues being available for a long time. There is plenty of precedent
for Boost libraries (e.g. Boost.Move, which is *awesome* by-the-way!)
that allow us to use features similar to those in C++0x in C++03
environments.

Cheers,
Greg


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