
On Thu, Nov 24, 2011 at 5:57 AM, Dean Michael Berris <mikhailberis@gmail.com> wrote:
On Thu, Nov 24, 2011 at 8:16 PM, Lorenzo Caminiti <lorcaminiti@gmail.com> wrote:
On Wed, Nov 23, 2011 at 8:11 PM, Joel de Guzman <joel@boost-consulting.com> 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_k...
// 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.
1) I don't think I have to convince anyone. Following Boost process, I have first asked for interest in the library about ~1year ago plus all the reviewers have answered the question:
- What is your evaluation of the potential usefulness of the library? With that information I am confident that the review manager will be able to assess the library usefulness taking into consideration the opinion of /all/ the people that reviewed the library.
2) As for local functions, namespace, or global structs see N2511. If you disagree with N2511 arguments, it's truly OK because IMO everyone is free to use whatever idiom they see fit for themselves and their problem domain. I am sure the library reviewers had namespaces and global structs in mind when they assessed the "potential usefulness of the library" (also because these are mentioned in the library docs). So also in this case /all/ submitted reviews should allow the review manager to come to a conclusion on this issue. 3) [MOST IMPORTANT OF ALL] This thread is about "should new libraries implementing C++11 features in C++03" be considered for admission in Boost or not. It's not about the usefulness of Local, namespace, struct, Phoenix, etc. Let's all try to provide the review manager with this piece of information about C++11, C++03, and Boost. HTH, --Lorenzo