Subject: Re: [boost] [local] Review
From: Gregory Crosswhite (gcrosswhite_at_[hidden])
Date: 2011-11-20 22:27:40
On Nov 21, 2011, at 11:36 AM, Thomas Heller wrote:
> I vote to not include Boost.Local into Boost for the following reason.
> I obviously can not appreciate the value of local functions in C++.
I similarly have trouble seeing the value of the higher-order functional programming constructs provided by Phoenix. Personally when I want to program in a functional programming style I write my code in a language Haskell rather than shoehorning functional programming into C++ constructs that were never designed for such a purpose. When I translate my Haskell code into C++ (as I have done for a numerical code I once wrote), I would never think of using Phoenix, but instead I would change the idioms that I was using to match C++'s stateful, imperative nature.
However, despite my criticisms I am in no way against the inclusion of Phoenix in Boost! I personally believe that programmers should have a toolbox with a broad selection of high-quality tools so that when a particular tool fits their problem, they can just grab it and make their lives easier. For this reason, although I do not use Phoenix myself or see myself using it in the foreseeable future to solve any of the problems that I face, I am happy to have it exist since clearly it is very useful for people who have need for such things as it provides --- and heck, maybe one day even I will stumble into a problem where it provides the best solution and be glad it is around. :-)
> C++, IMHO, has better ways to structure code (namespaces and classes).
Although you don't see any reason to use Boost.Local when we already have classes and namespaces, similarly Linus doesn't see any reason to use C++ when C has structs and function pointers. :-) That is to say, Boost.Local doesn't let you do something you couldn't do without it --- just like the functional programming libraries don't. However, it can make life easier when you are facing a problem where the most natural fit is a local function defined at the point where it is used.
> Therefor, Boost.Local is not an alternative to C++-Lambdas, Boost.Bind, Boost.Lambda or Boost.Phoenix, but to regular C++ functions
I am perfectly happy to give you an admission that Boost.Local is not a complete alternative to C++-Lambdas, Boost.Bind, Boost.Lambda or Boost.Phoenix and hence should not be directly compared with them --- as long as you are no longer claiming that Boost.Local is made redundant by these other options. :-)
> That being said, I don't see Boost.Local as a complement to the other already existing functional programming style libraries. I see it as a complement to regular functions. It is true that this implementation of local functions leads to function objects that can be used as callbacks where something callable is expected.
Yes, and the way that I see it that is Boost.Locals' major point of existing --- to make callbacks easier to write for those of us who want compatibility with C++03. And that is good enough for me. :-)
> However, that does not mean that they are higher order functions, which in turn means that they are not easily composable (that means, there is no way to compose two local functions to form another local function other than calling the macros again). Which has another side effect that they are completely incompatible with the existing solutions (ok, you can bind them again).
Fair enough, but that is true of plain C++ functions and methods and we don't consider them made redundant by the functional programming libraries. :-)
Nonetheless, I really do have to concede that until this discussion I never really thought of Phoenix as a functional programming library that just *happened* to also be useful for callbacks. While I still don't see a use for Phoenix myself in the foreseeable future, I am really glad that we have had this discussion because it has given me more insight as to what Phoenix is all about, and made it more likely that I would consider it in the future now that my understanding of its purpose has been clarified.
> Also, i think the verbosity of the macros defeat their initial purpose of "avoiding cluttering other parts of the program with functions, variables, etc unrelated to those parts".
I think that you must misunderstand what is meant by "avoiding cluttering other parts of the program with functions, variables, etc unrelated to those parts". The point is that the function is declared at the point of use rather than elsewhere; the "verbosity of the macros" does not change this and hence could not defeat this purpose.
> Additionally I can not see how local functions hide any information at all, the information is still visible (although hidden behind two enclosing, quite verbose, macro calls).
Local functions hide information in two senses.
First, they hide information in the same way that private members of classes do: although they are plainly visible in the code (and in particular the *public*-facing headers) you still can't easily get to them. (Of course, someone can technically mangle names to get access to the local functions and so they are not completely inaccessible, but likewise someone can use pointer tricks to get access to private variables and so in this sense local functions are not *less* hidden then private members.)
Second, they keep the implementation details of a function "hidden" inside the function, so as not to provide noise *outside* the function to people who just want to treat the function as a black box. An additional advantage of this approach is that if a function needs to be copied or moved, you can just copy/move the body of the function as it its implementation is entirely self-contained.
> I admit the fact, that we as C++ Programmers need Macros to avoid repeating ourselves (aka boilerplate code). A lot of libraries do exactly this, and it is considered good practice. My main point of critique was that the Boost.Local seem to implement a quite complex logic and, basically, their own language. I would not consider the preprocessor the proper place to implement a DSEL.
As I have said before, I find it somewhat difficult to believe that an author of *Phoenix* would find the Boost.Local DSL complicated. ;-) In my opinion, the Boost.Local DSL really isn't that all that complicated to use, though I will readily concede that at some point this becomes a matter of taste --- and as Lorenzo has said, taste is certainly a fair criteria to use in these reviews since we want all of the Boost libraries to be in good taste!
As for the philosophical object to the heavy use of macros, I note that comparing Local which uses macros to Phoenix which uses template metaprogramming demonstrates a clear advantage of the macro approach: it provides error messages that can be understood by mere mortals. This is a feature that really can't be overstated, and if macros make it easier to provide this then I don't see the disadvantage of using them.
> Again, Lorenzo's effort and ingenuity of creating this very library is out of question, I solely believe that it is not the proper solution to this problem.
We all appreciate your willingness to acknowledge this despite your personal distaste for the approach taken by Boost.Local. :-D
Also, as I write earlier in this e-mail, while I strongly disagree with your arguments, the part of this discussion involving comparing Boost.Local to Boost.Phoenix has enlightened me as to what Boost.Phoenix is really about, for which I am greatly appreciative.