Subject: Re: [boost] [local] Review
From: Gregory Crosswhite (gcrosswhite_at_[hidden])
Date: 2011-11-21 00:27:01
On Nov 21, 2011, at 2:16 PM, Thomas Heller wrote:
> You should definitely take a look at spirit. Try to use Local in semantic actions.
Noted for future reference. :-)
> ... the proposed solution aren't real local functions, because you explicitly need to capture variables in scope and ...
If that is what you mean by "real local functions" then fair enough, Boost.Local does not provide "real local functions" --- and I do appreciate you clarifying what you meant by this. Nonetheless, I don't see why it should matter if the local functions are or are not "real local functions" by this definition because they are still enough like "local functions" to be more useful then not having local functions.
> ... I tried to distance myself from comparing Boost.Local to Bind, Lambda and Phoenix, because the comparison just isn't fair. I try to see them as an alternative to regular functions. And, TBH, it just doesn't cut it. Mainly because of the macro overhead introduced.
Yes, but the macro overhead buys you the ability to put the code where it is being used, and to avoid writing what is effectively the same code multiple times. To see one example of why this is an advantage, suppose that you need to bind another variable in your callback. With plain functions, you would need to scroll outside of your function to where you defined the callback function, add a parameter to that function, and then jump back to where it was being bound using Boost.Bind and then add the variable to the proper position. By contrast, with Boost.Local you don't have to jump around your code and you don't have to write multiple lines of code that essentially say the same thing, you can just add a single line to the callback macro --- which, again, is conveniently located *right* where it is being used so that you don't need to go far --- and you are done. Also, since the type is detected by Boost.Local automatically, if you change the type of the bound variable you don't have to do anything at all, whereas with a plain function callback you would have to scroll up and update the type manually.
> Right. TBH, I considered writing macros to reduce the boilerplate of creating such construct for Phoenix. I decided to stop investigating that because at the end of the day, the macros grew in complexity and actually writing the boilerplate yourself turned out to be clearer, shorter and more flexible.
Clearly at this point you should have hired Lorenzo, since he is the macro master. ;-)
It is a shame, though, because the existence of such might have made it more likely that I would have considered using Phoenix.
> Ok, i can live with that argument. However, i continue in claiming that the whole noise hiding and locality argument is defeated by the verbosity of the macros.
Fair enough, though obviously I disagree. :-)
> Sorry, I wasn't entirely clear. I am all for DSELs, I just think that the PP is the wrong place. Admittingly, the complexity of functions is in the body, not the arguments, so arcane errors with the proposed library are more unlikely, but they do exist! I of course agree that the errors that come out of any ET based code are horrible. But they show exactly what went wrong, which is not so much the case when you do something wrong in the calls to the macro.
I understand your point that technically macro error messages have a disadvantage over template error messages in that they don't show you exactly what went wrong since the code is implicitly generated and often not shown. However, in practice this advantage really doesn't matter, because when an error message is pages long and gives you no insight at all as to what *you* did wrong, then the fact that at least it is showing you exactly what went wrong in all the layers of code that were touched is cold comfort. :-)
So in short, I don't see how using PP is necessarily at a disadvantage *in practice* when implementing DSELs, given that the error messages for complex template-metaprogramming libraries are hardly any better.
> To use one of Lorenzo's argument: "In my experience, this quickly becomes a non-issue after the 1st week that you start using the library." Which is true for all sorts of libraries.
Yes, but this library has a shallower learning curve than many. I would say that the syntax became a non-issue for me after more like an hour using it.
>> 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.
> That is one of my points that i somehow can't convey:
> You don't need macros for that. Just code up a regular off-line function/function-object. Just try it, and you'll probably realize that the boilerplate you need is negligible compared to the boilerplate code you need to set up a local function.
Sheesh, do you really think that ever since starting to use Boost.Local I have never even once written a regular off-line function/function-object and compared the experience I had to using Boost.Local? ;-)
First, boilerplate is not just about the number of characters typed, it is about the amount of redundant information you have to specify. Boost.Local allows me to declare the variables being bound at exactly one point in the code (which, again, is right next to where it is being used) and I don't even have to specify the types.
Second, using Boost.Local allows me to locate the function body right where the callback is being passed in, which is often the most natural location for such information. The way I figure it, there is no point in making someone reading my code jump around to figure out exactly what the callback I just passed into another function is doing when I can provide that information exactly where and when they need it.
Finally, as I said before Boost.Local allows me to "hide" a callback inside the function which uses it, which plain functions/function objects don't in the same way.
All three of these features together are worth it in my mind, even if the actual typing were slightly more.
So in short, no, Boost.Local is not really about just saving a little typing; I could understand, though, how you would be perplexed if that is what you thought it was primarily meant to do. :-)
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk