
Jaakko Jarvi <jajarvi@cs.indiana.edu> writes: | On Mar 8, 2004, at 11:40 AM, Gabriel Dos Reis wrote: | | > Jaakko Jarvi <jajarvi@cs.indiana.edu> writes: | > | > | On Sun, 8 Mar 2004, Gabriel Dos Reis wrote: | > | | > | > Jaakko Jarvi <jajarvi@cs.indiana.edu> writes: | > | > | > | | > | Right, variables with local storage cannot be used in local classes. | > | Now this rule would forbid the above (which is good), but it would | > also | > | rule out useful and safe lambdas: | > | > Those who are considered safe would have markers sayign they are safe | > to export, or they would have markers saying only their values are | > needed. | > | > | | > | auto foo(int x, int y) { | > | int i = x+y; // just some computation to motivate a local | > variable | > | vector<int> v; | > | ... | > | transform(v.begin(), v.end(), v.begin(), | > | auto(int x) { return x+i; }); | > | > Hmm, I do not see the difference between the "i" here and the "i" | > above. They are both automatic. | > | > But, if you want to tell the compiler that it is OK to use the value | > of a local variable then use lambda lifting, e.g. | > | > transform(v.begin(), v.vend(), v.begin() | > (auto x) ((int y) auto { return y + x; }) (i)); | > | | | Yes, but this is a quite complex and hard to read way to express | something simpler. Escaping variables are no simple :-) I doubt there is a simple criteria that says which ones are "good" and which ones are "bad", and those may depend on the context, thus let the user labels the good ones :-) It is possible to have a design that makes copy by default, but it handles only a very limited set (those for which functions/operations are expected to take values) at the cost of penalizing the reference semantics[1]. In a language like C++ where values/references look like the same syntactically but leak differently, that opens door for traps more often than needed. Yes, one can advance the argument that the situation already exists (see recent min/max thread); but do we need more ropes, especially when we want to talk people into using the feature? I believe that we should first optimize for the most simple common cases. Release the product, and extend later. Lambdas are handy and fun to program with; I'm less convinced that we would succeed in evangelizing C++ programmers into lambdas in the next 10-15 years, where traditional, well-developed, functional programming languages have failed for half a decade. Well, before this message provokes a deluge of mails, I would probably point out that I'm a big fan of lambdas; but realistically I don't see C++ brainwashing armies of programmers into lambdas. This lambda-conversion, if it were to happen, need not be done in a one single big-step. Just think about the perception of lambdas before the STL and after, say, 1998. If you optimize for the most common simple cases, then people will use it, get adicted and want more. That is essentially what STL did. But, I see we are in violent agreement on one fundamental point: lambdas in C++ should be bound to lexical scopes (e.g. implemented by local classes). That provides opportunities for efficiency and they can be effectively optimized (with the hope that compilers understand the semantics of scopes, which some of them do). If you let the possibility to escape by default, compilers would have more difficulty optimizing and would provide less effective support. This has been done before. The experience was not that conclusive[2]. | And it seems that in the inner lambda, x would be a variable from an | outer scope | with automatic storage, just like i is, and would therefore have to be | rejected | by the current local class rules. Hmm, I don't get that one. "x" in the inner lambda is the "x" bound by the outer (auto x). Therefore it is not rejected. Or am I being dense? Footnotes: [1] Simple constructs like struct foo { int bar() { return 666; } }; template<class T> int apply(foo* p, T f) { return (p->*f)(); } int main() { foo t[5]; for (int i = 0; i < 5; ++i) apply(t + i, &foo::bar); } are not effectively optimized by (common) compilers (especially, indirect calls through pointer to members or pointer to functions). Yes, in the abstract they can (and should) do better. But, in practice, few do correctly. [2] Lisp. -- Gaby