hi,
can you explain why in the following example the lambda for fun1 does not return the values as expected? is that behaviour intentional? is the workaround used with fun2 the best solution?
void main() { array fun1 = ({}); array fun2 = ({}); foreach(enumerate(2); int index; int value) { fun1 += ({ lambda() { return ({ index, value }); } }); fun2 += ({ lambda(int i, int v) { return lambda() { return ({ i,v }); }; }(index, value) }); } write("%O", fun1()); write("%O", fun2()); }
Well, it depends on what you expect. ;) I suspect you want index and value to be copied into a local store for each lambda when they are evaluated. But that would make them a lot less useful. For instance this example wouldn't work as I'd like:
int main() { int n = 0; function get_n = lambda() {return n;}; werror ("%O\n", get_n()); // Writes "0" n = 17; werror ("%O\n", get_n()); // Writes "17" }
And yes, that "workaround" is a decent way to make each generated lambda refer to its own set of variables.
But that would make them a lot less useful.
Useful? Maybe. However, consistency is more important IMHO. Saving references to stack frames that have gone out of scope is really confusing since unrelated variables from the same frame will be alive as well. Consider this for example:
Thread.Mutex mutex = Thread.Mutex();
function get_get_n() { Thread.MutexKey some_key = mutex->lock(); int n = 17; return lambda() { return n; }; }
int main() { function get_n = get_get_n(); Thread.MutexKey another_key = mutex->lock(); werror("%O\n", get_n()); }
Wohoo, recursive mutex locks! For even more fun, replace get_get_n() with the following to take advantage of another known Pike deficiency where the mutex key doesn't even have to be part of the same frame to begin with. Talk about minefield...
function get_get_n() { int n = 17; { Thread.MutexKey some_key = mutex->lock(); // ...protected stuff... } return lambda() { return n; }; }
That's a different issue. What you talk about is an implementation deficiency where unaccessed variables are kept in the heap allocated frames.
I'd say both your variants are instances of the same problem. You're welcome to fix it.
To me it sounds like at least the first problem was part of the original implementation and hence a design decision. I think such decisions are bad when the side-effects are just as big as the benefits. In hindsight the developer had several choices: solve the problem at the same time, don't introduce the problem in the first place, mark the construct as beta quality and only accessible with flags/pragmas/whatever, document the construct as potentially dangerous etc. Ignoring the issue seems like the worst choice.
I know my complains won't fix the problem, but perhaps they will avoid the same thing to be repeated next time.
To me it sounds like at least the first problem was part of the original implementation
Yes, and so was the second afaik.
and hence a design decision.
I don't understand how you arrive at that conclusion. What design purpose would it serve to keep unaccessible variables referenced? I believe it was plain oversight.
/.../ don't introduce the problem in the first place, /.../
I.e. not introduce statically scoped variables in nested functions at all.
One reason your pet peeve here hasn't been fixed is that it's more complex than what one might believe. A solution that works in the general case would require a refcounter for every variable that gets copied to the dynamic frame.
and hence a design decision.
I don't understand how you arrive at that conclusion. What design purpose would it serve to keep unaccessible variables referenced? I believe it was plain oversight.
By "design decision" I mean that the problem must have been known at the time the frame copying was put into the code. If that's not the case, well, too bad. :-)
I.e. not introduce statically scoped variables in nested functions at all.
Or don't copy the frame at all, and instead make it a run-time error to access scope variables once the frame is gone. Don't know if that's easy to detect, though.
One reason your pet peeve here hasn't been fixed is that it's more complex than what one might believe.
Don't know if it's my pet peeve; this discussion is the first time I talk about the frame copying issue as far as I can remember. And if it's that complex, are you sure you want me to fix it? :-)
Don't know if it's my pet peeve; this discussion is the first time I talk about the frame copying issue as far as I can remember.
Well, you obviously have a fairly strong opinion about it, so it looks like something you've been burnt badly by. And I believe we have discussed it in RL at least once.
And if it's that complex, are you sure you want me to fix it? :-)
Yes, as long as you _fix_ it. ;)
pike-devel@lists.lysator.liu.se