[Phoenix] Some questions and notes...

Hi all, I'm writing a review of phoenix, but first I have a some questions and notes. * First of all, it is not clear to me how 'lambda' works. I would have thought that it just introduced a new scope, but it seems that it does something more: 1: int i = 10; 2: cout << arg1(i) <<endl; 3: cout << lambda[ arg1 ](i) <<endl; // doesn't compile 4: cout << lambda[ arg1 ]()(i) The use of lambda at line 3 is completely superfluous, nevertheless, I prefer that syntax because it makes it clear that I'm using a lambda expression (always using lambda will also allow some other tricks I'll discuss later). Surprisingly, line 3 doesn't compile. lambda::operator[] actually returns a nullary stub that must be evaluated to actually get our unary function. Is this really necessary? can it be fixed? * non-standard result<> protocol. IMHO for Phoenix to become a first class boost library, it should support result_of out of the box. I understand that this is not done for backward compatibility, but I think that there are three solutions: 1) old users will still be able to use the Phoenix inside spirit if they have a large codebase that uses the old protocol. 2) phoenix could provide a wrapper that converts from the old to the new protocol and viceversa. This would require some changes in the client code. 3) phoenix could detect the protocol used by the user function and switch between the old and new 'result'. This is hard to do in a robust way, but breaks no user code. I would prefer the first option. * Perfect forwarding. I'm used to the perfect forwarding in boost lambda (which, contrary to what the documentation states, perfectly forwards up to 3 args). Personally have little use for lambdas that take their arguments by non const reference as I strive for referential transparency. I know that implementing this feature has an high compile time cost, but there should at least be an option to enable it. I would vote for two additional 'lambda' syntaxes: clambda and plambda (better names are wellcome). The first one would work like boost lambda const_arguments and should have no compile time cost, while the second will do perfect forwarding up to some parameter number. This would require the lambda[] syntax to actually return the wrapped function object, not a stub (as per first question). * operator->*. I sometimes use this operator with boost lambda, as a short hand for binding member functions, but, as in phoenix, it requires it lhs to be a pointer. Would it possible to extend it to any functions? for example: struct foo { int bar; }; std::vector<foo> in =...; std::vector<int> out; std::transform(in.begin(), in.end(), std::back_inserter(out), (&arg1)->*&foo::bar); The parenthesis, and ampersand are ugly, it would be great if this worked: std::transform(in.begin(), in.end(), std::back_inserter(out), arg1->*&foo::bar); I think this would interfere with foo implementing its own operator->*. Which brings the question... * ... how do I implement type deduction for the my own overloaded operators? I.e. what is the phoenix equivalent of http://tinyurl.com/4botne ? By reading of the documentation I couldn't figure out an easy way to do it. Well, that's all for now, those questions are mostly to get the discussion rolling, more to come. -- gpd

Giovanni Piero Deretta wrote:
Hi all,
I'm writing a review of phoenix, but first I have a some questions and notes.
* First of all, it is not clear to me how 'lambda' works. I would have thought that it just introduced a new scope, but it seems that it does something more:
1: int i = 10; 2: cout << arg1(i) <<endl; 3: cout << lambda[ arg1 ](i) <<endl; // doesn't compile 4: cout << lambda[ arg1 ]()(i)
The use of lambda at line 3 is completely superfluous, nevertheless, I prefer that syntax because it makes it clear that I'm using a lambda expression (always using lambda will also allow some other tricks I'll discuss later). Surprisingly, line 3 doesn't compile. lambda::operator[] actually returns a nullary stub that must be evaluated to actually get our unary function. Is this really necessary?
Yes.
can it be fixed?
It's not broken. As Doug noted in his review, phoenix lambda is like lambda protect (http://tinyurl.com/3sx7bo). lambda[...] returns another lambda functor, hence for each lambda, there's one function application. Some samples from the tests: 1) int x = 1; int y = lambda[_1]()(x); BOOST_TEST(x == y); 2) int x = 1, y = 10; BOOST_TEST( (_1 + lambda[_1 + 2])(x)(y) == 1+10+2 ); 3) int x = 1; long x2 = 2; short x3 = 3; char const* y = "hello"; zzz z; BOOST_TEST(lambda[_1](x)(y) == y); BOOST_TEST(lambda(_a = _1)[_a](x)(y) == x); BOOST_TEST(lambda(_a = _1)[lambda[_a]](x)(y)(z) == x); BOOST_TEST(lambda(_a = _1)[lambda[_a + _1]](x)(y)(x) == 2); BOOST_TEST(lambda(_a = _1)[lambda(_b = _1)[_a + _b + _1]](x)(x2)(x3) == 6); So, walking through the first example (which resembles yours): lambda[_1]()(x); The first call (empty) does no substitution and results to: _1 The second call with x then substitutes x for _1. Let's take another example (2): (_1 + lambda[_1 + 2])(x)(y) The first call (with x) results in another lambda functor after substituting the outer _1 for x and exposing the expression inside the lambda without substitution: (x + _1 + 2) The second call (with y) then does the final invocation: (x + y + 2) The difference with lambda's protect is that phoenix' lambda has true local variables and with the mechanism, inner lambda scopes can actually get arguments and other information from outer lambda scopes. This is important. For instance, the example in the doc: write a lambda expression that accepts: 1. a 2-dimensional container (e.g. vector<vector<int> >) 2. a container element (e.g. int) and pushes-back the element to each of the vector<int>. cannot be done with protect alone.
* non-standard result<> protocol. IMHO for Phoenix to become a first class boost library, it should support result_of out of the box. I understand that this is not done for backward compatibility, but I think that there are three solutions:
1) old users will still be able to use the Phoenix inside spirit if they have a large codebase that uses the old protocol. 2) phoenix could provide a wrapper that converts from the old to the new protocol and viceversa. This would require some changes in the client code. 3) phoenix could detect the protocol used by the user function and switch between the old and new 'result'. This is hard to do in a robust way, but breaks no user code.
I would prefer the first option.
What's the first solution? It's not clear.
* Perfect forwarding. I'm used to the perfect forwarding in boost lambda (which, contrary to what the documentation states, perfectly forwards up to 3 args). Personally have little use for lambdas that take their arguments by non const reference as I strive for referential transparency.
We will have perfect forwarding controlled by a macro. The proto version has it. It's turned off by default because even at a low expansion number, Eric notes that it explodes.
I know that implementing this feature has an high compile time cost, but there should at least be an option to enable it. I would vote for two additional 'lambda' syntaxes: clambda and plambda (better names are wellcome). The first one would work like boost lambda
That's a very good idea. Trivia: Phoenix started out pure. No side-effects, only consts. It was good for me but people just can't get over the scheme. It's not C++, they say. Yes, I'd love to bring back some purity. Let me think about it some more, ok?
const_arguments and should have no compile time cost, while the second will do perfect forwarding up to some parameter number. This would require the lambda[] syntax to actually return the wrapped function object, not a stub (as per first question).
Good points. I'm adding these ideas in my notebook.
* operator->*. I sometimes use this operator with boost lambda, as a short hand for binding member functions, but, as in phoenix, it requires it lhs to be a pointer. Would it possible to extend it to any functions? for example:
struct foo { int bar; };
std::vector<foo> in =...; std::vector<int> out;
std::transform(in.begin(), in.end(), std::back_inserter(out), (&arg1)->*&foo::bar);
The parenthesis, and ampersand are ugly, it would be great if this worked:
std::transform(in.begin(), in.end(), std::back_inserter(out), arg1->*&foo::bar);
arg1->*&foo::bar is perfectly allowed! Why do you think it's not? see /test/operator/member.cpp for examples on this. Some examples: Test test = {1}; const Test* cptr = &test; Test* ptr = &test; BOOST_TEST((val(ptr)->*&Test::value)() == 1); BOOST_TEST((val(cptr)->*&Test::value)() == 1); BOOST_TEST((arg1->*&Test::value)(cptr) == 1); ((val(ptr)->*&Test::value) = 2)(); BOOST_TEST(test.value == 2); BOOST_TEST((val(ptr)->*&Test::func)(3)() == 3); BOOST_TEST((val(cptr)->*&Test::func)(4)() == 4); BOOST_TEST((val(ptr)->*&Test::dunc)()() == 10); BOOST_TEST((arg1->*&Test::func)(5)(ptr) == 5); shared_ptr<Test> sptr(new Test(test)); BOOST_TEST((arg1->*&Test::value)(sptr) == 2); BOOST_TEST((arg1->*&Test::func)(6)(sptr) == 6);
I think this would interfere with foo implementing its own operator->*. Which brings the question...
* ... how do I implement type deduction for the my own overloaded operators? I.e. what is the phoenix equivalent of http://tinyurl.com/4botne ? By reading of the documentation I couldn't figure out an easy way to do it.
With V2, you can't (**). Phoenix V3 OTOH uses Boost Typeof. So it just works on most compilers out of the box. If not, then Boost Typeof has its own protocols for extending type deduction. (**) Actually there is a way, but it's undocumented. I intentionally didn't put more effort into this because I was certain to use Boost.Typeof soon.
Well, that's all for now, those questions are mostly to get the discussion rolling, more to come.
Thanks! Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On Thu, Sep 25, 2008 at 2:43 PM, Joel de Guzman <joel@boost-consulting.com> wrote:
Giovanni Piero Deretta wrote:
Hi all,
I'm writing a review of phoenix, but first I have a some questions and notes.
* First of all, it is not clear to me how 'lambda' works. I would have thought that it just introduced a new scope, but it seems that it does something more:
1: int i = 10; 2: cout << arg1(i) <<endl; 3: cout << lambda[ arg1 ](i) <<endl; // doesn't compile 4: cout << lambda[ arg1 ]()(i)
The use of lambda at line 3 is completely superfluous, nevertheless, I prefer that syntax because it makes it clear that I'm using a lambda expression (always using lambda will also allow some other tricks I'll discuss later). Surprisingly, line 3 doesn't compile. lambda::operator[] actually returns a nullary stub that must be evaluated to actually get our unary function. Is this really necessary?
Yes.
can it be fixed?
It's not broken. As Doug noted in his review, phoenix lambda is like lambda protect (http://tinyurl.com/3sx7bo).
I would be perfectly fine if it lambda[f] worked as protect(f), but it actually is subtly different What I do not like is the extra '()' you have to use to actually get the protected lambda: int i = 0; std::cout << protect(arg1)(i) ; // print 0 std::cout << lambda[arg1](i) ; // compile error std::cout << lambda[arg1]()(i) ; // ok, prints 1
lambda[...] returns another lambda functor, hence for each lambda, there's one function application. Some samples from the tests:
<snipped examples>
So, walking through the first example (which resembles yours):
lambda[_1]()(x);
The first call (empty) does no substitution and results to:
_1
The second call with x then substitutes x for _1.
Let's take another example (2):
(_1 + lambda[_1 + 2])(x)(y)
The first call (with x) results in another lambda functor after substituting the outer _1 for x and exposing the expression inside the lambda without substitution:
(x + _1 + 2)
The second call (with y) then does the final invocation:
(x + y + 2)
The difference with lambda's protect is that phoenix' lambda has true local variables and with the mechanism, inner lambda scopes can actually get arguments and other information from outer lambda scopes. This is important. For instance, the example in the doc:
I now understand why you need another evaluation round, and I see the need for local variables in lambdas (I've missed them in boost.lambda, and it was one of the reasons I was eagerly waiting for phoenix to be reviewed). My only objection is that a lambda[f] which doesn't have any local variables should just return 'f' and not a nullary. In fact I think this should be a global propery of lambda expressions: Let 'add' be an binary lazy function: 'add(arg1, 0)' should return an unary function (as it is currently the case). OTOH: 'add(1, 2)' should immediately be evaluated and not return a nullary function. In practice, 'add' would be 'optionally lazy'. This is in fact not that surprising: let's substitute add with its corresponding operator: 'arg1 + 0' returns an unary funciton, but '1 + 2' is immediately evaluated. I know this is a bit controversial and would probably require large code changes, but probably a review is the best place to comment on design aspects. Anyways, I can live with the current design, 'optional lazyness' could be built on top of phoenix lazy functions. My only compliant is that the 'lambda[]' syntax is already taken. BTW, FC++ had both 'optionally lazy' functions (which it called generalized currying) and required a top level 'lambda[]' around all lambdas.
* non-standard result<> protocol. IMHO for Phoenix to become a first class boost library, it should support result_of out of the box. I understand that this is not done for backward compatibility, but I think that there are three solutions:
1) old users will still be able to use the Phoenix inside spirit if they have a large codebase that uses the old protocol. 2) phoenix could provide a wrapper that converts from the old to the new protocol and viceversa. This would require some changes in the client code. 3) phoenix could detect the protocol used by the user function and switch between the old and new 'result'. This is hard to do in a robust way, but breaks no user code.
I would prefer the first option.
What's the first solution? It's not clear.
Completely ditch the old protocol and adopt the result_of one. Users that need backward compatibility can still use the phoenix inside spirit.
* Perfect forwarding. I'm used to the perfect forwarding in boost lambda (which, contrary to what the documentation states, perfectly forwards up to 3 args). Personally have little use for lambdas that take their arguments by non const reference as I strive for referential transparency.
We will have perfect forwarding controlled by a macro.
Great! <snip>
* operator->*. I sometimes use this operator with boost lambda, as a short hand for binding member functions, but, as in phoenix, it requires it lhs to be a pointer. Would it possible to extend it to any functions? for example:
struct foo { int bar; };
std::vector<foo> in =...; std::vector<int> out;
std::transform(in.begin(), in.end(), std::back_inserter(out), (&arg1)->*&foo::bar);
The parenthesis, and ampersand are ugly, it would be great if this worked:
std::transform(in.begin(), in.end(), std::back_inserter(out), arg1->*&foo::bar);
arg1->*&foo::bar is perfectly allowed! Why do you think it's not?
Sure it does, but the placeholder must be substituted with a pointer...
see /test/operator/member.cpp for examples on this. Some examples:
Test test = {1}; const Test* cptr = &test; Test* ptr = &test;
BOOST_TEST((val(ptr)->*&Test::value)() == 1);
This doesn't compile BOOST_TEST((arg1->*&Test::value)(test) == 1); because 'test' is not a pointer. OTOH boost::bind(&Test::value, arg1)(x) compiles for both x of type "Test&" and "Test*". BTW, what if the member function is not nullary? struct foo { void bar(int){} }; foo * x =...; int y = 0; ((arg1->*&foo::bar)(arg2))(x, y); The above (or any simple variation I could think of) doesn't compile. There is a way to make something like this to work without using bind? Not that it is very compelling, I'm just curious.
Well, that's all for now, those questions are mostly to get the discussion rolling, more to come.
An additional question: is it possible to make lambdas always assignable? ATM, if you close around a reference (something which I think is very common), the lambda expression is only CopyConstructible. This means that an iterator that holds a lambda expression by value internally (think about filter_iterator or transform iterator) technically does no longer conform to the Iterator concept. A simple fix, I think, is internally converting all references to reference wrappers which are assignable. -- gpd

Giovanni Piero Deretta wrote:
It's not broken. As Doug noted in his review, phoenix lambda is like lambda protect (http://tinyurl.com/3sx7bo).
I would be perfectly fine if it lambda[f] worked as protect(f), but it actually is subtly different What I do not like is the extra '()' you have to use to actually get the protected lambda:
int i = 0; std::cout << protect(arg1)(i) ; // print 0
Have you tried it? I did and I get compiler error. The result of protect(arg1)(i) is a lambda functor as expected (and that's in line with the lambda docs). #include <boost/lambda/lambda.hpp> #include <iostream> int main() { using namespace boost::lambda; int i = 0; std::cout << protect(_1)(i) << std::endl; return 0; } This: int xxx = protect(_1)(i); gives me: 'initializing' : cannot convert from 'boost::lambda::lambda_functor<T>' to 'int'
std::cout << lambda[arg1](i) ; // compile error std::cout << lambda[arg1]()(i) ; // ok, prints 1
Sure, and the correct lambda code is: std::cout << protect(_1)()(i) << std::endl; Which prints 0.
I now understand why you need another evaluation round, and I see the need for local variables in lambdas (I've missed them in boost.lambda, and it was one of the reasons I was eagerly waiting for phoenix to be reviewed).
My only objection is that a lambda[f] which doesn't have any local variables should just return 'f' and not a nullary. In fact I think this should be a global propery of lambda expressions:
Let 'add' be an binary lazy function:
'add(arg1, 0)'
should return an unary function (as it is currently the case). OTOH:
'add(1, 2)'
should immediately be evaluated and not return a nullary function. In practice, 'add' would be 'optionally lazy'. This is in fact not that surprising: let's substitute add with its corresponding operator:
'arg1 + 0'
returns an unary funciton, but
'1 + 2'
is immediately evaluated. I know this is a bit controversial and would probably require large code changes, but probably a review is the best place to comment on design aspects.
IMO, it's not controversial. I've considered this approach a long time ago. It's actually doable: evaluate immediately when there are no placeholders in an expression. I'm not sure about the full effect of this behavior, OTOH. Such things should be taken very carefully. Mind you, the very impact of immediate evaluation on expressions like above already confuses people. Sometimes, the effect is subtle and is not quite obvious when you are dealing with complex lambda expressions. I know, from experiences with ETs (prime example is Spirit), that people get confused when an expression is immediate or not. The classic example: for_each(f, l, std::cout << 123 << _1) Oops! std::cout << 123 is immediate. But that's just for starters. With some heavy generic code, you can't tell by just looking at the code which expresions are being evaluated immediately or lazily.
Anyways, I can live with the current design, 'optional lazyness' could be built on top of phoenix lazy functions. My only compliant is that the 'lambda[]' syntax is already taken.
I'd like to get convinced. Can you give me a nice use case for this 'optional lazyness' thing that cannot be done with the curent interface?
BTW, FC++ had both 'optionally lazy' functions (which it called generalized currying) and required a top level 'lambda[]' around all lambdas.
* non-standard result<> protocol. IMHO for Phoenix to become a first class boost library, it should support result_of out of the box. I understand that this is not done for backward compatibility, but I think that there are three solutions:
1) old users will still be able to use the Phoenix inside spirit if they have a large codebase that uses the old protocol. 2) phoenix could provide a wrapper that converts from the old to the new protocol and viceversa. This would require some changes in the client code. 3) phoenix could detect the protocol used by the user function and switch between the old and new 'result'. This is hard to do in a robust way, but breaks no user code.
I would prefer the first option. What's the first solution? It's not clear.
Completely ditch the old protocol and adopt the result_of one. Users that need backward compatibility can still use the phoenix inside spirit.
Hmmm.. That's a good suggestion.
* operator->*. I sometimes use this operator with boost lambda, as a short hand for binding member functions, but, as in phoenix, it requires it lhs to be a pointer. Would it possible to extend it to any functions? for example:
struct foo { int bar; };
std::vector<foo> in =...; std::vector<int> out;
std::transform(in.begin(), in.end(), std::back_inserter(out), (&arg1)->*&foo::bar);
The parenthesis, and ampersand are ugly, it would be great if this worked:
std::transform(in.begin(), in.end(), std::back_inserter(out), arg1->*&foo::bar); arg1->*&foo::bar is perfectly allowed! Why do you think it's not?
Sure it does, but the placeholder must be substituted with a pointer...
see /test/operator/member.cpp for examples on this. Some examples:
Test test = {1}; const Test* cptr = &test; Test* ptr = &test;
BOOST_TEST((val(ptr)->*&Test::value)() == 1);
This doesn't compile BOOST_TEST((arg1->*&Test::value)(test) == 1);
because 'test' is not a pointer. OTOH boost::bind(&Test::value, arg1)(x) compiles for both x of type "Test&" and "Test*".
Ah! Good point. But, hey, doesn't -> imply "pointer"? bind OTOH does not imply pointer. But sure I get your point and it's easy enough to implement. Is this a killer feature for you?
BTW, what if the member function is not nullary?
struct foo { void bar(int){} };
foo * x =...; int y = 0; ((arg1->*&foo::bar)(arg2))(x, y);
The above (or any simple variation I could think of) doesn't compile. There is a way to make something like this to work without using bind? Not that it is very compelling, I'm just curious.
The examples show how. I don't know why your example does not compile. Again, see /test/operator/member.cpp for examples on this. Here's one that's not nullary: struct Test { int func(int n) const { return n; } }; ... BOOST_TEST((val(ptr)->*&Test::func)(3)() == 3); and I just added this test for you: int i = 33; BOOST_TEST((arg1->*&Test::func)(arg2)(cptr, i) == i); Compiles fine.
Well, that's all for now, those questions are mostly to get the discussion rolling, more to come.
An additional question: is it possible to make lambdas always assignable? ATM, if you close around a reference (something which I think is very common), the lambda expression is only
Not sure what you mean by "close around a reference".
CopyConstructible. This means that an iterator that holds a lambda expression by value internally (think about filter_iterator or transform iterator) technically does no longer conform to the Iterator concept.
Good point.
A simple fix, I think, is internally converting all references to reference wrappers which are assignable.
I wish it was that simple. Anyway, gimme some time to ponder on the impact of this on the implementation. Perhaps an easier way is to do as ref does: store references by pointer. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

Speaking of operator->*, does anyone have any ideas about this question that i previously posted on the Spirit list? : http://thread.gmane.org/gmane.comp.parsers.spirit.general/13478 Thanks, Richard Webb

Richard Webb wrote:
Speaking of operator->*, does anyone have any ideas about this question that i previously posted on the Spirit list? : http://thread.gmane.org/gmane.comp.parsers.spirit.general/13478
It is a bug and your fix is correct. Sorry I missed your post in the Spirit list. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On Fri, Sep 26, 2008 at 3:06 AM, Joel de Guzman <joel@boost-consulting.com> wrote:
Giovanni Piero Deretta wrote:
It's not broken. As Doug noted in his review, phoenix lambda is like lambda protect (http://tinyurl.com/3sx7bo).
I would be perfectly fine if it lambda[f] worked as protect(f), but it actually is subtly different What I do not like is the extra '()' you have to use to actually get the protected lambda:
int i = 0; std::cout << protect(arg1)(i) ; // print 0
Have you tried it? I did and I get compiler error.
Yes I did. But I just found out that I had mixed lambda placeholders with phoenix ones (In my own code I use the argN placeholers with lambda too for compatiblity with boost.bind). It is interesting that when using the arg1 phoenix placeholder with lambda.protect everything compiles and gives me what I expected... werid. Anyways, as I said in another email, I always confuse protect with unlambda. I initially expected lambda[] to behave as unlambda.
I now understand why you need another evaluation round, and I see the need for local variables in lambdas (I've missed them in boost.lambda, and it was one of the reasons I was eagerly waiting for phoenix to be reviewed).
My only objection is that a lambda[f] which doesn't have any local variables should just return 'f' and not a nullary. In fact I think this should be a global propery of lambda expressions:
Let 'add' be an binary lazy function:
'add(arg1, 0)'
should return an unary function (as it is currently the case). OTOH:
'add(1, 2)'
should immediately be evaluated and not return a nullary function. In practice, 'add' would be 'optionally lazy'. This is in fact not that surprising: let's substitute add with its corresponding operator:
'arg1 + 0'
returns an unary funciton, but
'1 + 2'
is immediately evaluated. I know this is a bit controversial and would probably require large code changes, but probably a review is the best place to comment on design aspects.
IMO, it's not controversial. I've considered this approach a long time ago. It's actually doable: evaluate immediately when there are no placeholders in an expression. I'm not sure about the full effect of this behavior, OTOH. Such things should be taken very carefully. Mind you, the very impact of immediate evaluation on expressions like above already confuses people. Sometimes, the effect is subtle and is not quite obvious when you are dealing with complex lambda expressions. I know, from experiences with ETs (prime example is Spirit), that people get confused when an expression is immediate or not. The classic example:
for_each(f, l, std::cout << 123 << _1)
Oops! std::cout << 123 is immediate. But that's just for starters. With some heavy generic code, you can't tell by just looking at the code which expresions are being evaluated immediately or lazily.
Ok, I'll start by saying that for me this is not just "it would be great if...". I routinely use an extension to boost.lambda that allows one to define lazy functions a-la phoenix, except that they lazy only if one or more of their parameter is a lambda expression. I usually assume that an expression is not lazy unless I see a placeholder in the right position. I do not think that generic code makes thing worse: I carefully wrap all function parameters with the equivalent unlambda [1] *before* I pass them to higher order functions. In fact I always have to because in general I do not know if a certain function is optionally lazy or not. The additional advantages of always using lambda[] are that: - a lambda[] stands out in the code better than a placeholder, so it is clearer what is going on (if you think about it, pretty much every other language that support a lambda abstraction has a lambda introducer). - the rule to determine the scope of a placeholder is simpler: it doesn't cross a lambda[] barrier. The biggest problem with optional lazyness is in fact not in generic code, but in simple top level imperative code: most of my lazy function objects are pure functions, with the most common exception the 'for_each' wrapper. Sometimes I forget to protect the function argument with lambda[], which makes the whole function call a lambda expression. You always use the result of a pure function, so the compiler will loudly complain if it gets a lambda expression instead of the expected type, but it is not usually the case with for_each. So the code will compile, but will be silently a nop. [1] I have rolled my own lambda[] syntax for this (which in addition makes a a boost.lambda expression result_of compatible), and this is why the behavior of phoenix::lambda surprised me.
Anyways, I can live with the current design, 'optional lazyness' could be built on top of phoenix lazy functions. My only compliant is that the 'lambda[]' syntax is already taken.
I'd like to get convinced. Can you give me a nice use case for this 'optional lazyness' thing that cannot be done with the curent interface?
I find it very convenient to define functions that I use very often (for example tuple accessors, generic algorithms, etc...) as polymorphic function objects. I put a named instance in an header file and I use them as normal functions. Except that I can pass them to higher order functions without monomorphizing them. In addition I can use the exact same name in a lambda expression without having to pull in additional headers or namespaces. After a while it just feel natural and you wish that all functions provided the same capabilities. The following snippet is taken from production code: map( ents.to_tokens(entities, tok), lambda[ tuple( ll::bind(to_utf8, arg1) , newsid, quote_id, is_about ) ] ) | copy(_, out) ; Some explainations: * 'a | f' is equivalent to 'f(a)'. In practice I often use it to chain range algorithm, but can be used for anything. * '_' is similar to 'arg1', except that it can only used as a parameter to a lazy lambda function and the resulting unary function is no longer a lambda expression (so the 'lambdiness' doesn't propagate). map returns a pair of transform iterators, copy is the range equivalent of std::copy and tuple is equivalent to make_tuple. All three functions can be used both inside and outside of lambdas. So, it is not really a question of power, just of convenience. You can always have to functions one lazy and one not, but I like to have everything packaged in a single place. Compile times are of course not pretty and requires lots of code to roll this syntax on top of boost.lambda. I think that a port to Phoenix will be much simpler and probably lighter at compile time.
BOOST_TEST((val(ptr)->*&Test::value)() == 1);
This doesn't compile BOOST_TEST((arg1->*&Test::value)(test) == 1);
because 'test' is not a pointer. OTOH boost::bind(&Test::value, arg1)(x) compiles for both x of type "Test&" and "Test*".
Ah! Good point. But, hey, doesn't -> imply "pointer"? bind OTOH does not imply pointer. But sure I get your point and it's easy enough to implement. Is this a killer feature for you?
No, not really, in fact I can see many would consider it needless obfuscation. I just thought that was a nicer notation than bind. Anyways, -> doesn't necessarily imply pointer. See optional. In fact I think that -> is, in general, a good substitute for the lack of an overloadable 'operator.', sometimes I wish that reference_wrapper did provide it.
BTW, what if the member function is not nullary?
struct foo { void bar(int){} };
foo * x =...; int y = 0; ((arg1->*&foo::bar)(arg2))(x, y);
The above (or any simple variation I could think of) doesn't compile. There is a way to make something like this to work without using bind? Not that it is very compelling, I'm just curious.
The examples show how. I don't know why your example does not compile. Again, see /test/operator/member.cpp for examples on this. Here's one that's not nullary:
struct Test { int func(int n) const { return n; } };
...
BOOST_TEST((val(ptr)->*&Test::func)(3)() == 3);
and I just added this test for you:
int i = 33; BOOST_TEST((arg1->*&Test::func)(arg2)(cptr, i) == i);
Compiles fine.
Yes, it compiles fine... I think I was trying to stream out the result of a void function, sorry for the noise ;). Thanks.
Well, that's all for now, those questions are mostly to get the discussion rolling, more to come.
An additional question: is it possible to make lambdas always assignable? ATM, if you close around a reference (something which I think is very common), the lambda expression is only
Not sure what you mean by "close around a reference".
Hum, "the lambda expression closure captures a reference to a local object" int i = 2; auto plus_i = arg1 + ll::ref(i); //closes around i by reference decltype(plus_i) y; // error, not default constructible plus_i = plus_i; //error plus_i not assignable
CopyConstructible. This means that an iterator that holds a lambda expression by value internally (think about filter_iterator or transform iterator) technically does no longer conform to the Iterator concept.
Good point.
In fact I think the problem is not limited to iterators. AFAIK standard algorithms require that their funcitonal parameters be assignable.
A simple fix, I think, is internally converting all references to reference wrappers which are assignable.
I wish it was that simple. Anyway, gimme some time to ponder on the impact of this on the implementation. Perhaps an easier way is to do as ref does: store references by pointer.
Sure. BTW, boost.lambda has the same problem; I use a wrapper that hides the lambda in an optional (another service provided by my lambda[]). With in_place construction you can implement assignment as an copy construction. But it adds overhead. -- gpd

Giovanni Piero Deretta wrote:
IMO, it's not controversial. I've considered this approach a long time ago. It's actually doable: evaluate immediately when there are no placeholders in an expression. I'm not sure about the full effect of this behavior, OTOH. Such things should be taken very carefully. Mind you, the very impact of immediate evaluation on expressions like above already confuses people. Sometimes, the effect is subtle and is not quite obvious when you are dealing with complex lambda expressions. I know, from experiences with ETs (prime example is Spirit), that people get confused when an expression is immediate or not. The classic example:
for_each(f, l, std::cout << 123 << _1)
Oops! std::cout << 123 is immediate. But that's just for starters. With some heavy generic code, you can't tell by just looking at the code which expresions are being evaluated immediately or lazily.
Ok, I'll start by saying that for me this is not just "it would be great if...". I routinely use an extension to boost.lambda that allows one to define lazy functions a-la phoenix, except that they lazy only if one or more of their parameter is a lambda expression.
Are you suggesting that you want phoenix functions to be "optionaly lazy" too? Currently, they are not. That can be done, but I need more convincing.
I usually assume that an expression is not lazy unless I see a placeholder in the right position. I do not think that generic code makes thing worse: I carefully wrap all function parameters with the equivalent unlambda [1] *before* I pass them to higher order functions. In fact I always have to because in general I do not know if a certain function is optionally lazy or not.
This is exactly the problem I see with generic code.
The additional advantages of always using lambda[] are that:
- a lambda[] stands out in the code better than a placeholder, so it is clearer what is going on (if you think about it, pretty much every other language that support a lambda abstraction has a lambda introducer).
Yes.
- the rule to determine the scope of a placeholder is simpler: it doesn't cross a lambda[] barrier.
Good point.
The biggest problem with optional lazyness is in fact not in generic code, but in simple top level imperative code: most of my lazy function objects are pure functions, with the most common exception the 'for_each' wrapper. Sometimes I forget to protect the function argument with lambda[], which makes the whole function call a lambda expression. You always use the result of a pure function, so the compiler will loudly complain if it gets a lambda expression instead of the expected type, but it is not usually the case with for_each. So the code will compile, but will be silently a nop.
I'm not sure I understand this part. Can you explain this with simple examples?
[1] I have rolled my own lambda[] syntax for this (which in addition makes a a boost.lambda expression result_of compatible), and this is why the behavior of phoenix::lambda surprised me.
Anyways, I can live with the current design, 'optional lazyness' could be built on top of phoenix lazy functions. My only compliant is that the 'lambda[]' syntax is already taken. I'd like to get convinced. Can you give me a nice use case for this 'optional lazyness' thing that cannot be done with the curent interface?
I find it very convenient to define functions that I use very often (for example tuple accessors, generic algorithms, etc...) as polymorphic function objects. I put a named instance in an header file and I use them as normal functions. Except that I can pass them to higher order functions without monomorphizing them. In addition I can use the exact same name in a lambda expression without having to pull in additional headers or namespaces. After a while it just feel natural and you wish that all functions provided the same capabilities.
The following snippet is taken from production code:
map( ents.to_tokens(entities, tok), lambda[ tuple( ll::bind(to_utf8, arg1) , newsid, quote_id, is_about ) ] ) | copy(_, out) ;
Some explainations: * 'a | f' is equivalent to 'f(a)'. In practice I often use it to chain range algorithm, but can be used for anything. * '_' is similar to 'arg1', except that it can only used as a parameter to a lazy lambda function and the resulting unary function is no longer a lambda expression (so the 'lambdiness' doesn't propagate).
map returns a pair of transform iterators, copy is the range equivalent of std::copy and tuple is equivalent to make_tuple. All three functions can be used both inside and outside of lambdas.
So, it is not really a question of power, just of convenience. You can always have to functions one lazy and one not, but I like to have everything packaged in a single place.
Compile times are of course not pretty and requires lots of code to roll this syntax on top of boost.lambda. I think that a port to Phoenix will be much simpler and probably lighter at compile time.
Those are pretty cool code. I'm still not sure of the implications of all these though. I know for sure that people less smarter than you are tend to get bitten by expressions that are intended to be lazy but are actually immediate. Perhaps we can be arrange for an "optionaly-lazy" layer on top of phoenix: it can be done, phoenix is modular enough to have that layer. In general though, I tend to avoid special cases. This "optional laziness" is based on special casing depending on some qualities of a lambda function. This may be outside our subject, but this same special casing is the reason why I rejected lambda's design to have optional-reference-capture on the LHS. For example, this is allowed in lambda: int i = 0; i += _1; But in Phoenix, it would have to be: int i = 0; ref(i) += _1; All variables are captured by value, always. I know that's off the subject, but I'm sure you see what I mean.
BOOST_TEST((val(ptr)->*&Test::value)() == 1); This doesn't compile BOOST_TEST((arg1->*&Test::value)(test) == 1);
because 'test' is not a pointer. OTOH boost::bind(&Test::value, arg1)(x) compiles for both x of type "Test&" and "Test*". Ah! Good point. But, hey, doesn't -> imply "pointer"? bind OTOH does not imply pointer. But sure I get your point and it's easy enough to implement. Is this a killer feature for you?
No, not really, in fact I can see many would consider it needless obfuscation. I just thought that was a nicer notation than bind. Anyways, -> doesn't necessarily imply pointer. See optional.
Hah, I don't want to get in that optional pointer semantics argument again :P Least I can say is that I never liked it. OptionalPointee (http://tinyurl.com/3fwlp9) does imply pointer.
Well, that's all for now, those questions are mostly to get the discussion rolling, more to come. An additional question: is it possible to make lambdas always assignable? ATM, if you close around a reference (something which I think is very common), the lambda expression is only Not sure what you mean by "close around a reference".
Hum, "the lambda expression closure captures a reference to a local object"
int i = 2; auto plus_i = arg1 + ll::ref(i); //closes around i by reference
decltype(plus_i) y; // error, not default constructible plus_i = plus_i; //error plus_i not assignable
CopyConstructible. This means that an iterator that holds a lambda expression by value internally (think about filter_iterator or transform iterator) technically does no longer conform to the Iterator concept. Good point.
In fact I think the problem is not limited to iterators. AFAIK standard algorithms require that their funcitonal parameters be assignable.
A simple fix, I think, is internally converting all references to reference wrappers which are assignable. I wish it was that simple. Anyway, gimme some time to ponder on the impact of this on the implementation. Perhaps an easier way is to do as ref does: store references by pointer.
Sure.
Understood. I'll see what I can do in that regard. I agree with you. That's good observation and thanks for pointing it out. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On Fri, Sep 26, 2008 at 4:44 PM, Joel de Guzman <joel@boost-consulting.com> wrote:
Giovanni Piero Deretta wrote:
IMO, it's not controversial. I've considered this approach a long time ago. It's actually doable: evaluate immediately when there are no placeholders in an expression. I'm not sure about the full effect of this behavior, OTOH. Such things should be taken very carefully. Mind you, the very impact of immediate evaluation on expressions like above already confuses people. Sometimes, the effect is subtle and is not quite obvious when you are dealing with complex lambda expressions. I know, from experiences with ETs (prime example is Spirit), that people get confused when an expression is immediate or not. The classic example:
for_each(f, l, std::cout << 123 << _1)
Oops! std::cout << 123 is immediate. But that's just for starters. With some heavy generic code, you can't tell by just looking at the code which expresions are being evaluated immediately or lazily.
Ok, I'll start by saying that for me this is not just "it would be great if...". I routinely use an extension to boost.lambda that allows one to define lazy functions a-la phoenix, except that they lazy only if one or more of their parameter is a lambda expression.
Are you suggesting that you want phoenix functions to be "optionaly lazy" too? Currently, they are not. That can be done, but I need more convincing.
I would love if they were. But I can live with a layer on top of that. About the convincing part... hum I guess the only way is to try them and see if one find them convenient. For me it started as an experiment that worked.
I usually assume that an expression is not lazy unless I see a placeholder in the right position. I do not think that generic code makes thing worse: I carefully wrap all function parameters with the equivalent unlambda [1] *before* I pass them to higher order functions. In fact I always have to because in general I do not know if a certain function is optionally lazy or not.
This is exactly the problem I see with generic code.
In general the compiler will loudly tell you if you get something wrong (even if the errors might be unintelligible). Except of course for something like the example below...
The biggest problem with optional lazyness is in fact not in generic code, but in simple top level imperative code: most of my lazy function objects are pure functions, with the most common exception the 'for_each' wrapper. Sometimes I forget to protect the function argument with lambda[], which makes the whole function call a lambda expression. You always use the result of a pure function, so the compiler will loudly complain if it gets a lambda expression instead of the expected type, but it is not usually the case with for_each. So the code will compile, but will be silently a nop.
I'm not sure I understand this part. Can you explain this with simple examples?
Ok, let's assume for_each is optionally lazy: for_each(range, lambda[cout << arg1]); will print all the elements. What if I forget the lambda? for_each(range, cout << arg1); D'oh, now everything is a big unary lambda expression. It compiles, but as the lambda is never evaluated, it is a nop. At least gcc doesn't warn that the code doesn't do anything. If your lazy functions are pure functions, you will always use the value (to pass it to another function or store it in a variable or whatever: int i = map(range_of_ints, lambda[ arg1 * 2]).front(); If you forget the lambda, it will complain that the the result of map doesn't have a front() parameter. C++0x auto will make thing a bit trickier though: auto r2 = map(range_of_ints, arg1 * 2); The user wanted r2 to be a range, but, as he forgot lambda[], it is actually a lambda expression. The compiler will probably complain when he tries to use r2, but the error will be more incompressible than usual.
Anyways, I can live with the current design, 'optional lazyness' could be built on top of phoenix lazy functions. My only compliant is that the 'lambda[]' syntax is already taken.
I'd like to get convinced. Can you give me a nice use case for this 'optional lazyness' thing that cannot be done with the curent interface?
I find it very convenient to define functions that I use very often (for example tuple accessors, generic algorithms, etc...) as polymorphic function objects. I put a named instance in an header file and I use them as normal functions. Except that I can pass them to higher order functions without monomorphizing them. In addition I can use the exact same name in a lambda expression without having to pull in additional headers or namespaces. After a while it just feel natural and you wish that all functions provided the same capabilities.
The following snippet is taken from production code:
map( ents.to_tokens(entities, tok), lambda[ tuple( ll::bind(to_utf8, arg1) , newsid, quote_id, is_about ) ] ) | copy(_, out) ;
Some explainations: * 'a | f' is equivalent to 'f(a)'. In practice I often use it to chain range algorithm, but can be used for anything. * '_' is similar to 'arg1', except that it can only used as a parameter to a lazy lambda function and the resulting unary function is no longer a lambda expression (so the 'lambdiness' doesn't propagate).
map returns a pair of transform iterators, copy is the range equivalent of std::copy and tuple is equivalent to make_tuple. All three functions can be used both inside and outside of lambdas.
So, it is not really a question of power, just of convenience. You can always have to functions one lazy and one not, but I like to have everything packaged in a single place.
Compile times are of course not pretty and requires lots of code to roll this syntax on top of boost.lambda. I think that a port to Phoenix will be much simpler and probably lighter at compile time.
Those are pretty cool code. I'm still not sure of the implications of all these though. I know for sure that people less smarter than you are tend to get bitten by expressions that are intended to be lazy but are actually immediate. Perhaps we can be arrange for an "optionaly-lazy" layer on top of phoenix: it can be done, phoenix is modular enough to have that layer.
It would be great.
In general though, I tend to avoid special cases. This "optional laziness" is based on special casing depending on some qualities of a lambda function.
Well, I guess that is a point of view.. as I see it, functions are usually evaluated, unless some of the arguments are suspended: it is not eager evaluation that is special, but lazyness (or partial application or whatever you want to call it).
This may be outside our subject, but this same special casing is the reason why I rejected lambda's design to have optional-reference-capture on the LHS. For example, this is allowed in lambda:
int i = 0; i += _1;
But in Phoenix, it would have to be:
int i = 0; ref(i) += _1;
All variables are captured by value, always. I know that's off the subject, but I'm sure you see what I mean.
I didn't even know that lambda captured by reference in this case (if it is documented, I missed it)! I always use ref(i)... which begs another question: could you add a shorthand syntax to tell that a specific variable must be captured by reference? Lambda has it, but is a bit cumbersome: int i =0; var_type<int> r_i = var(i); (_1 + r_i)(0); //capture by ref something like this is desirable (and in fact can be done easily, but IMHO should be part of the library): byref<int> i = 0; (_1 + i)(0); // capture by ref BTW, yet another reason for always requiring lambda[] or something equivalent: the library could delay the decision of capturing by reference or by value by default up to the lambda introducer (I think I already mentioned something like this in the past): int i = 0; lambda[ i+= arg1]; //default capture by value lambda_r[ i += arg1]; //default capture by reference It would make Phoenix similar to C++0x lambdas. Without requiring lambda[] [1] I do not see how this could be implemented (expecially if you want the default capture behavior to be by value). [1] or a different set of placeholders... messy!
BOOST_TEST((val(ptr)->*&Test::value)() == 1);
This doesn't compile BOOST_TEST((arg1->*&Test::value)(test) == 1);
because 'test' is not a pointer. OTOH boost::bind(&Test::value, arg1)(x) compiles for both x of type "Test&" and "Test*".
Ah! Good point. But, hey, doesn't -> imply "pointer"? bind OTOH does not imply pointer. But sure I get your point and it's easy enough to implement. Is this a killer feature for you?
No, not really, in fact I can see many would consider it needless obfuscation. I just thought that was a nicer notation than bind. Anyways, -> doesn't necessarily imply pointer. See optional.
Hah, I don't want to get in that optional pointer semantics argument again :P Least I can say is that I never liked it. OptionalPointee (http://tinyurl.com/3fwlp9) does imply pointer.
Ok, as I said, it is not a killer feature :) I want to comment about switch_, but I'll do it by replying to another thread. After that, time to write a review :) -- gpd

Giovanni Piero Deretta wrote:
Are you suggesting that you want phoenix functions to be "optionaly lazy" too? Currently, they are not. That can be done, but I need more convincing.
I would love if they were. But I can live with a layer on top of that. About the convincing part... hum I guess the only way is to try them and see if one find them convenient. For me it started as an experiment that worked.
Don't stop! Don't backout now that I'm starting to get convinced ;) I know the value of your suggestion. I've actually pondered on this a long time ago.
I usually assume that an expression is not lazy unless I see a placeholder in the right position. I do not think that generic code makes thing worse: I carefully wrap all function parameters with the equivalent unlambda [1] *before* I pass them to higher order functions. In fact I always have to because in general I do not know if a certain function is optionally lazy or not. This is exactly the problem I see with generic code.
In general the compiler will loudly tell you if you get something wrong (even if the errors might be unintelligible). Except of course for something like the example below...
Imperative code. Right. [snip more on "optional-laziness"]
Anyways, I can live with the current design, 'optional lazyness' could be built on top of phoenix lazy functions. My only compliant is that the 'lambda[]' syntax is already taken.
If we are to break the interface, I want to do it right. Your feedback here is invaluable. The lambda[] behavior is not set in stone, so to speak. I just want to be sure I'm making the right decisions when changing the interface. I cannot affort a failed experiment.
Those are pretty cool code. I'm still not sure of the implications of all these though. I know for sure that people less smarter than you are tend to get bitten by expressions that are intended to be lazy but are actually immediate. Perhaps we can be arrange for an "optionaly-lazy" layer on top of phoenix: it can be done, phoenix is modular enough to have that layer.
It would be great.
In general though, I tend to avoid special cases. This "optional laziness" is based on special casing depending on some qualities of a lambda function.
Well, I guess that is a point of view.. as I see it, functions are usually evaluated, unless some of the arguments are suspended: it is not eager evaluation that is special, but lazyness (or partial application or whatever you want to call it).
And it is a valid point of view. Recall in the brief introduction that "The focus is more on usefulness and practicality than purity, elegance and strict adherence to FP principles.". I do admire people like you who embrace FP and pure functions. I try to do as much FP as I can. But in the real world, it's C++ we are dealing with with the side-effects, with the imperative code, etc. This is not the first time things like this are brought into light though. As I said, I already pondered on this a long time ago. I'm definitely interested with your approach. And, as someone who already made progress in that route, I would love to collaborate with you on having a facility like this built on top of phoenix.
specific variable must be captured by reference? Lambda has it, but is a bit cumbersome:
int i =0; var_type<int> r_i = var(i); (_1 + r_i)(0); //capture by ref
something like this is desirable (and in fact can be done easily, but IMHO should be part of the library):
byref<int> i = 0; (_1 + i)(0); // capture by ref
Phoenix has it but is not as terse. I think your suggestion is good.
BTW, yet another reason for always requiring lambda[] or something equivalent: the library could delay the decision of capturing by reference or by value by default up to the lambda introducer (I think I already mentioned something like this in the past):
Yes.
int i = 0;
lambda[ i+= arg1]; //default capture by value lambda_r[ i += arg1]; //default capture by reference
It would make Phoenix similar to C++0x lambdas. Without requiring lambda[] [1] I do not see how this could be implemented (expecially if you want the default capture behavior to be by value).
I'm not sure about this one. What makes this better than just having ref(i) ? Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On Sat, Sep 27, 2008 at 6:16 AM, Joel de Guzman <joel@boost-consulting.com> wrote:
Giovanni Piero Deretta wrote:
Are you suggesting that you want phoenix functions to be "optionaly lazy" too? Currently, they are not. That can be done, but I need more convincing.
I would love if they were. But I can live with a layer on top of that. About the convincing part... hum I guess the only way is to try them and see if one find them convenient. For me it started as an experiment that worked.
Don't stop! Don't backout now that I'm starting to get convinced ;) I know the value of your suggestion. I've actually pondered on this a long time ago.
I really would like to bring other arguments, but it really seems something one has to get used to.
Anyways, I can live with the current design, 'optional lazyness' could be built on top of phoenix lazy functions. My only compliant is that the 'lambda[]' syntax is already taken.
If we are to break the interface, I want to do it right. Your feedback here is invaluable. The lambda[] behavior is not set in stone, so to speak. I just want to be sure I'm making the right decisions when changing the interface. I cannot affort a failed experiment.
IMHO always requiring lambda[] (and changing a bit the current lambda[] behavior) is more future proof than the other solution. The 'lambda' keyword provides a simple place to hook extra solutions.
In general though, I tend to avoid special cases. This "optional laziness" is based on special casing depending on some qualities of a lambda function.
Well, I guess that is a point of view.. as I see it, functions are usually evaluated, unless some of the arguments are suspended: it is not eager evaluation that is special, but lazyness (or partial application or whatever you want to call it).
And it is a valid point of view. Recall in the brief introduction that "The focus is more on usefulness and practicality than purity, elegance and strict adherence to FP principles.". I do admire people like you who embrace FP and pure functions. I try to do as much FP as I can. But in the real world, it's C++ we are dealing with with the side-effects, with the imperative code, etc.
I'm an engineer so for me practicality is everything :) I try to practice a functional approach to programming simply because ditching as much mutable state as possible let me reason about a system more easily. The catch is, as usual, in the 'as much as possible'.
This is not the first time things like this are brought into light though. As I said, I already pondered on this a long time ago. I'm definitely interested with your approach. And, as someone who already made progress in that route, I would love to collaborate with you on having a facility like this built on top of phoenix.
Ok, I do not think it will be hard! I'll start to look to the current phoenix V3.
int i = 0;
lambda[ i+= arg1]; //default capture by value lambda_r[ i += arg1]; //default capture by reference
It would make Phoenix similar to C++0x lambdas. Without requiring lambda[] [1] I do not see how this could be implemented (expecially if you want the default capture behavior to be by value).
I'm not sure about this one. What makes this better than just having ref(i) ?
With just a single captured variable, it is more or less the same, but with complex lambda expressions were you need to capture many variables by reference (because you need to mutate or simply they are expensive to copy), it makes a difference. C++0x lambdas do the same. In general, I find that the most of my lambdas have a shorter lifetime than the variables they capture, so capture by (const) reference as default would work for me. OTOH having an simple syntax to switch from one mode to the other without requiring to explicitly mark every variable is a good thing. -- gpd
participants (3)
-
Giovanni Piero Deretta
-
Joel de Guzman
-
Richard Webb