
Fernando Cacciola wrote:
Here's my review of the lambda sublibrary:
FCPP Lamba is "explicit" as opposed to "implicit" as in BLL. That is, I don't create a lambda expression on the fly by merely putting a placeholder somewhere in the expression; rather, I have to use brackets (% for infix notation).
I really like this part of the design.... I was myself caught at the "early evaluation" problems of implicit lambda until trained to put BLL's "protect()" on the right place.
When you work with complex lambdas it's hard to get it right (that is, avoid all possible early evaluations) implicitly, yet explicitly (the way FC++ works), it's straight forward (even if it requires a more adorned syntax).
OTOH, I don't agree with the arguments against overloaded operators. Since FC++ lambda expressions are explicit I can't see any overload resolution problems. Given that C++ allows you to overload operators is hard to understand why would I have to write [X %plus% 1] instead of [X+1]
The problem with operator overloading, LL/Phoenix style, can be alleviated by simply by disallowing automatic conversions. This is what I am advocating now, given the experience with Phoenix, possibly through a #define DISALLOW_AUTO_CONVERSION which defaults to ON. Let me explain... The folling snippet is your typical complaint: for_each(f, l, cout << "hello, " << arg1); << arg1 in Phoenix is _1 in LL >> The problem is that the expression cout << "hello, " is immediate, hence, cout << "hello, " << arg1 is immediate + deferred. Yet, the compiler does not catch this because the library allows overloading of the LHS and RHS where the RHS and LHS are curryable epxressions such as arg1 (or _1). This may be hard to get right. It took me lots of explaining about overloading rules in phoenix to make this point clear. See: http://www.boost.org/libs/spirit/doc/phoenix.html A simple solution is to simply disallow automatic conversions. Thus, if you want deferred evaluation, state it explicitly using var and val: for_each(f, l, var(cout) << val("hello, ") << arg1); In my opinion, this syntax is still clear while being safe from incorrect usage. Expressions such as: for_each(f, l, cout << "hello, " << arg1); will simply not compile. That said, I should point out that even FC++'s scheme can be prone to improper use too. No-one can prevent users from writing incorrect code with mixed operators such as: x * y %plus% 1 where x + y is immediately evaluated. Worse, the % precedence might be another cause of confusion. Consider: x + y %plus% 1 where the precedence of + is lower than %. The first will compile, (x * y is immediately evaluated) but the second might not (you probably can't add (y %plus% 1) to x. I fear that there might be still more confusion if you add ^ to the mix: x ^f^ y // ok x & y ^f^ y // x & y is immediate x | y ^f^ y // probably compile error << Having said all these, I have no problems with either LL/Phoenix or FC++'s syntax. IMO, it's just a matter of properly explaning the issues. >> Regards, -- Joel de Guzman http://www.boost-consulting.com http://spirit.sf.net