On 15.06.19 18:29, Rémy Mouëza wrote:
On Saturday, 15 June 2019 at 01:21:46 UTC, Emmanuelle wrote:
On Saturday, 15 June 2019 at 00:30:43 UTC, Adam D. Ruppe wrote:
On Saturday, 15 June 2019 at 00:24:52 UTC, Emmanuelle wrote:
Is it a compiler bug?
Yup, a very longstanding bug.
You can work around it by wrapping it all in another layer of
function which you immediately call (which is fairly common in
javascript):
funcs ~= ((x) => (int i) { nums[x] ~= i; })(x);
Or maybe less confusingly written long form:
funcs ~= (delegate(x) {
return (int i) { nums[x] ~= i; };
})(x);
You write a function that returns your actual function, and
immediately calls it with the loop variable, which will explicitly
make a copy of it.
Oh, I see. Unfortunate that it's a longstanding compiler bug, but at
least the rather awkward workaround will do. Thank you!
I don't know if we can tell this is a compiler bug.
It's a bug. It's memory corruption. Different objects with overlapping
lifetimes use the same memory location.
The same behavior happens in Python.
No, it's not the same. Python has no sensible notion of variable scope.
>>> for i in range(3): pass
...
>>> print(i)
2
Yuck.
The logic being variable `x` is captured by the
closure. That closure's context will contain a pointer/reference to x.
Whenever x is updated outside of the closure, the context still points
to the modified x. Hence the seemingly strange behavior.
...
It's not the same instance of the variable. Foreach loop variables are
local to the loop body. They may both be called `x`, but they are not
the same. It's most obvious with `immutable` variables.
Adam's workaround ensures that the closure captures a temporary `x`
variable on the stack: a copy will be made instead of taking a
reference, since a pointer to `x` would be dangling once the
`delegate(x){...}` returns.
Most of the time, we want a pointer/reference to the enclosed variables
in our closures. Note that C++ 17 allows one to select the capture mode:
the following link lists 8 of them:
https://en.cppreference.com/w/cpp/language/lambda#Lambda_capture.
...
No, this is not an issue of by value vs by reference. All captures in D
are by reference, yet the behavior is wrong.
D offers a convenient default that works most of the time. The trade-off
is having to deal with the creation of several closures referencing a
variable being modified in a single scope, like the incremented `x` of
the for loop.
...
By reference capturing may be a convenient default, but even capturing
by reference the behavior is wrong.