Boost logo

Boost :

Subject: Re: [boost] [local] Review
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2011-11-21 05:52:19


On Sun, Nov 20, 2011 at 8:36 PM, Thomas Heller
<thom.heller_at_[hidden]> wrote:
> Please let me clarify my vote again. Please also note, that the quality of
> the implementation and documentation is out of doubt.
>
> 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++. C++,
> IMHO, has better ways to structure code (namespaces and classes).
> Therefor, Boost.Local is not an alternative to C++-Lambdas, Boost.Bind,
> Boost.Lambda or Boost.Phoenix,

That is true for a very simple reason: Boost.Local functions cannot be
defined with an expression. Boost.Local don't define lambdas but they
define closures at local scope.

> but to regular C++ functions
> 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. 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

You can bind a local function to another local function thus composing
them together without needing to call the macros again:
https://svn.boost.org/svn/boost/sandbox/local/libs/local/doc/html/boost_local/Advanced_Topics.html#boost_local.Advanced_Topics.assigning_local_functions

int x = 10;

int BOOST_LOCAL_FUNCTION(int y, const bind x) {
    return x + y;
} BOOST_LOCAL_FUNCTION(g)

int BOOST_LOCAL_FUNCTION(int y, const bind g) {
    return g(y);
} BOOST_LOCAL_FUNCTION_END(f)

f(5);

This composition is "easy" (if by "easy" we mean "without calling the
macros again").

> another side effect that they are completely incompatible with the existing
> solutions (ok, you can bind them again).

Yes, you can compose them by "binding them again" as shown by the example above.

> 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". Additionally I can not see how local
> functions hide any information at all, the information is still visible

Local functions hide information in same sense as explained by N2511. Mainly:
1) Local functions are declared locally, next to the code where they
are directly needed (the std::for_each call, etc).
2) Local functions are only visible by the scope that needs to call
them (another part of the program can't call them by "mistake" because
they are not accessible outside the enclosing function).

If you open up the source file, you can of course read the local
function code as you can read any other implementation code. However,
both local function and implementation code is hidden because it is
not accessible from outer scopes within your program.

> (although hidden behind two enclosing, quite verbose, macro calls).

Nope, local functions are /not/ hidden by the wrapping macros at all
(they are declared by the wrapping macros). They are instead hidden by
the enclosing function scope which makes local functions not
accessible/visible from outside the enclosing function (even if they
are still readable as any non-obfuscated code is). Does this make
sense?

> 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.

On the contrary, there's no way to use macros at all without
introducing a DSEL by definition. Oops, this might be a controversial
point (and I don't want to speak for Paul) but it has been argued that
the moment you use a macro you are introducing a DSEL by #definition
;) That is because the pp is a code generator and it has nothing to do
with the underling language (C or C++) by definition. Even in simple
"function-like" (whatever that means) usage of macros:

#define M(x, y) (x-y) // (1)

You are introducing a DSEL because the following:

M( , 2) // expands to -2

Would not be legal if M was a C++ function but it is legal given that
M is a macro! That shows that even the super-simple (1) defines a DSEL
with respect to the underlining C++ language.

All of that said, I definitively think that you can draw different
degrees of complexity of the DSEL you /have to/ define with your
macros. You can say that the DSEL introduced by (1) is trivial and
acceptable but the DSEL introduced by Boost.Local is too complex and
not acceptable (which I think it is your point) [we'll leave out the
DSEL introduced by Boost.Contract because on this scale it would be
pure madness :) ]. However, they all are DSEL (and not C++) by
definition simply because they use macros.

> Again, Lorenzo's effort and ingenuity of creating this very library is out
> of question,

Thanks :)

> I solely believe that it is not the proper solution to this
> problem.

--Lorenzo


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