
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