[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2022-05-24 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

Walter Bright  changed:

   What|Removed |Added

 Status|REOPENED|RESOLVED
 Resolution|--- |MOVED

--- Comment #44 from Walter Bright  ---
Closed in favor of https://issues.dlang.org/show_bug.cgi?id=23136 which has an
accurate example.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2022-05-24 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

Walter Bright  changed:

   What|Removed |Added

   See Also||https://issues.dlang.org/sh
   ||ow_bug.cgi?id=23136

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2022-05-24 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

Tim  changed:

   What|Removed |Added

   See Also||https://issues.dlang.org/sh
   ||ow_bug.cgi?id=21929

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2022-05-24 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

Adam D. Ruppe  changed:

   What|Removed |Added

 CC||destructiona...@gmail.com

--- Comment #43 from Adam D. Ruppe  ---
> test.d(13): Error: reference to local variable `b` assigned to non-scope 
> parameter `_param_0`

This error is on the *writeln* line, not the actual capture line. It has
absolutely nothing to do with the actual bug.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2022-05-24 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #42 from Artem Borisovskiy  ---
(In reply to Walter Bright from comment #40)
> > dmd test.c -preview=dip1000

Is DIP1000 going to become the standard behaviour anytime soon? I left D, my
former favourite language, for good 4 years ago because of this ancient bug
(more like it has become the last straw that broke the camel's back). It turned
out easier to figure out how Rust lifetimes work, than to not shoot myself in
the foot in D, a GC-based language, that's supposed to be even safer w.r.t.
memory.

What's even the current state of DIP1000?

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2022-05-24 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

timon.g...@gmx.ch changed:

   What|Removed |Added

 Status|RESOLVED|REOPENED
 Resolution|WORKSFORME  |---

--- Comment #41 from timon.g...@gmx.ch ---
The correct behavior for a delegate literal that outlives a referenced variable
is to allocate a closure. This case is not an exception.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2022-05-23 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

Walter Bright  changed:

   What|Removed |Added

 Status|NEW |RESOLVED
 Resolution|--- |WORKSFORME

--- Comment #40 from Walter Bright  ---
Note that dgList exceeds the lifetime of b, and should fail to compile for that
reason.

Let's try it (adding import and @safe and updating the code to D2):

import std.stdio;

@safe:

void delegate()[] dgList;

void test() {

foreach(int i; [1, 2, 3]) {
int b = 2;
dgList ~= { writeln(b); };
writeln(&b); // b will be the *same* on each iteration
}
}


> dmd test.c -preview=dip1000
test.d(13): Error: reference to local variable `b` assigned to non-scope
parameter `_param_0`

This is correct behavior. There is no way D should allow references to
variables that went out of scope.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2021-01-22 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

Bolpat  changed:

   What|Removed |Added

 CC||qs.il.paperi...@gmail.com

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-16 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #39 from Artem Borisovskiy  ---
Sorry for off-topic, but this discussion brought back memories of the classic
song by Frank C Mantra:

It's a feature, not a bug,
No one really gives a *cough*,
So if you want it to be fixed,
Go on and fork it, badam badam pap-pa,
How hard can it be, badam badam pap-pa,
Trust me, it's worth it, badam badam pap-pa,
In 10 years you'll se!

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-06 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

greenify  changed:

   What|Removed |Added

 CC||greeen...@gmail.com

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-06 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #38 from timon.g...@gmx.ch ---
(In reply to Walter Bright from comment #37)
> (In reply to timon.gehr from comment #36)
> > (In reply to Walter Bright from comment #35)
> > As I said, just do it if the delegate does not escape.
> 
> Yes, I thought this was clear. This only applies if the delegate escapes.
> 
> > > 2. Doing a heap alloc/free for every loop iteration is expensive, and 
> > > since
> > > the cost is hidden it will come as a nasty surprise.
> > > ...
> > 
> > I don't get how this is different from other implicit heap closure
> > allocations. A function that does such an implicit allocation not within a
> > loop in its own body might well be called in a loop and cause a performance
> > bottleneck. Profile.
> 
> People have made it clear they don't particularly like hidden allocations in
> innocuous looking code.

Some people. Others just want obvious code to do the obvious thing.
Also, closures escaped from the loop body don't look innocuous.

> Hence the genesis of the @nogc attribute.

Exactly. I'm not proposing anything that would not be catched by @nogc.

> For this
> particular issue, it would be hard to look at a random loop and see if
> allocations are occurring

Not really. Annotate it with @nogc and you will see. This is really not a new
issue. This is about consistently applying an existing rule.

> - i.e. a nasty surprise if a small change suddenly
> made a big hit in performance. Profiling is not the answer, as very, very
> few people profile code.
> ...

A "big hit in performance" is noticeable.

> 
> > > 3. Doing a gc allocation will generate an unbounded set of allocations, 
> > > also
> > > coming as a nasty surprise.
> > > ...
> > This is true for all implicit heap allocations. They are also often
> > convenient and there are already ways to flag them.
> 
> I can hear the complaints about this already :-(
> ...

There will also be complaints about missing closure support.

> 
> > > 4. Doing my delegate rewrite will cause a "by value" which changes the
> > > semantics, so that won't work.
> > > ...
> > That's not true.
> 
> I believe it is:
> 
> int i = 0;
> auto dg = { ++i; }
> dg();
> print(i);  // zero or one?
> 
> By ref would make it one, with the rewrite it would be 0 because the ref
> would be to a copy of i, not the original.
> ...

No, the rewrite would wrap the loop body and nothing else. foreach loops have a
lowering similar to the following:

foreach(i; 0..n) delegates~=()=>i;

->

for(int __i=0;__ii;
}

Here, the rewrite would be:

for(int __i=0;__ii;
}()

This has the same semantics as before, and every closure gets its own copy of
i, as this is a different variable for each of them (because it is declared in
the loop body).

If you just had the for loop:

for(int i=0;ii;
}

Then the (unnecessary!) rewrite would be:

for(int i=0;ii;
}();

And all closures in the body get the same copy of i, as they all see the same
version. In this case, in the end, every closure would point to the same i and
the value of that i would be n. For this case, no additional implicit
allocations (gc or non-gc) would be necessary.

> > The delegate rewrite is a very hacky way
> > to implement it though, and probably not really the most convenient as you
> > need to thread through control flow and the generated code will not be as
> > good as it could be.
> 
> Things get very sticky if you've got closures from functions nested several
> levels deep. It turns out to be pretty hard to get all this stuff right.
> Doing the rewrite means I know it will be correct, as it leverages all that
> complex, debugged, working code.
> ...

You know that that part will be correct. Wrapping the loop body into a function
does not in general result in valid code though. (E.g. break, continue, early
returns, interactions with scope.) Therefore, there need to be additional
hacks.

> ...
> BTW, I belatedly realized that it wasn't just about loop variables.
> Capturing non-loop variables that get destructed when they go out of scope
> also cannot be done.

Yes, this is also an issue, though not related to the current one.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-05 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #37 from Walter Bright  ---
(In reply to timon.gehr from comment #36)
> (In reply to Walter Bright from comment #35)
> As I said, just do it if the delegate does not escape.

Yes, I thought this was clear. This only applies if the delegate escapes.

> > 2. Doing a heap alloc/free for every loop iteration is expensive, and since
> > the cost is hidden it will come as a nasty surprise.
> > ...
> 
> I don't get how this is different from other implicit heap closure
> allocations. A function that does such an implicit allocation not within a
> loop in its own body might well be called in a loop and cause a performance
> bottleneck. Profile.

People have made it clear they don't particularly like hidden allocations in
innocuous looking code. Hence the genesis of the @nogc attribute. For this
particular issue, it would be hard to look at a random loop and see if
allocations are occurring - i.e. a nasty surprise if a small change suddenly
made a big hit in performance. Profiling is not the answer, as very, very few
people profile code.


> > 3. Doing a gc allocation will generate an unbounded set of allocations, also
> > coming as a nasty surprise.
> > ...
> This is true for all implicit heap allocations. They are also often
> convenient and there are already ways to flag them.

I can hear the complaints about this already :-(


> > 4. Doing my delegate rewrite will cause a "by value" which changes the
> > semantics, so that won't work.
> > ...
> That's not true.

I believe it is:

int i = 0;
auto dg = { ++i; }
dg();
print(i);  // zero or one?

By ref would make it one, with the rewrite it would be 0 because the ref would
be to a copy of i, not the original.

> The delegate rewrite is a very hacky way
> to implement it though, and probably not really the most convenient as you
> need to thread through control flow and the generated code will not be as
> good as it could be.

Things get very sticky if you've got closures from functions nested several
levels deep. It turns out to be pretty hard to get all this stuff right. Doing
the rewrite means I know it will be correct, as it leverages all that complex,
debugged, working code.


> > I suspect the pragmatic solution is to disallow the capture of loop
> > variables by reference by escaping delegates. The user then will be notified
> > of the problem, and he can construct an efficient workaround that works for
> > his application.
> 
> This fixes the memory corruption issue without much work. Deprecation might
> be necessary even if we fix this the right way in the end, so this is a good
> first step.

At least we agree on that step :-), although I am far less sanguine about
adding hidden allocations inside loops being an acceptable option.

BTW, I belatedly realized that it wasn't just about loop variables. Capturing
non-loop variables that get destructed when they go out of scope also cannot be
done.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-05 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #36 from timon.g...@gmx.ch ---
(In reply to Walter Bright from comment #35)
> 1. alloca() won't work, because that won't survive the end of the function.
> ...

As I said, just do it if the delegate does not escape.

> 2. Doing a heap alloc/free for every loop iteration is expensive, and since
> the cost is hidden it will come as a nasty surprise.
> ...

I don't get how this is different from other implicit heap closure allocations.
A function that does such an implicit allocation not within a loop in its own
body might well be called in a loop and cause a performance bottleneck.
Profile.

> 3. Doing a gc allocation will generate an unbounded set of allocations, also
> coming as a nasty surprise.
> ...

This is true for all implicit heap allocations. They are also often convenient
and there are already ways to flag them.

> 4. Doing my delegate rewrite will cause a "by value" which changes the
> semantics, so that won't work.
> ...

That's not true. It just gets rid of the memory corruption. The capture is
still by reference, which you can easily verify by creating more than one
closure over the same instance of the variable. This is the standard semantics
for this kind of thing. The delegate rewrite is a very hacky way to implement
it though, and probably not really the most convenient as you need to thread
through control flow and the generated code will not be as good as it could be.

> I suspect the pragmatic solution is to disallow the capture of loop
> variables by reference by escaping delegates. The user then will be notified
> of the problem, and he can construct an efficient workaround that works for
> his application.

This fixes the memory corruption issue without much work. Deprecation might be
necessary even if we fix this the right way in the end, so this is a good first
step.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-05 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #35 from Walter Bright  ---
1. alloca() won't work, because that won't survive the end of the function.

2. Doing a heap alloc/free for every loop iteration is expensive, and since the
cost is hidden it will come as a nasty surprise.

3. Doing a gc allocation will generate an unbounded set of allocations, also
coming as a nasty surprise.

4. Doing my delegate rewrite will cause a "by value" which changes the
semantics, so that won't work.

I suspect the pragmatic solution is to disallow the capture of loop variables
by reference by escaping delegates. The user then will be notified of the
problem, and he can construct an efficient workaround that works for his
application.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-05 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #34 from timon.g...@gmx.ch ---
(In reply to timon.gehr from comment #33)
> ...
> In D, if the compiler can prove that closures don't escape, alloca might be
> an option.

(Or simply malloc/free, of course.)

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-05 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #33 from timon.g...@gmx.ch ---
(In reply to Walter Bright from comment #32)
> > Other programming languages, even those that always capture by reference, 
> > do not have this problem.
> 
> So, for a variable declared in a loop, where do they allocate storage for it?

For some, this is an implementation detail, others explicitly specify heap
allocation.

In D, if the compiler can prove that closures don't escape, alloca might be an
option.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-05 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #32 from Walter Bright  ---
> Other programming languages, even those that always capture by reference, do 
> not have this problem.

So, for a variable declared in a loop, where do they allocate storage for it?

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-05 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #31 from timon.g...@gmx.ch ---
(timon.gehr meant to write in comment #30)
> (In reply to Walter Bright from comment #28)
> > Added the `safe` keyword because of the immutable variable issue described
> > in the comments.
> 
> This is not a one-off issue. It is a symptom of the generally wrong
> behavior. DMD is sharing the same memory for different variables with
> *overlapping* lifetimes. This is plain memory corruption, whether or not
> immutable is involved.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-05 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #30 from timon.g...@gmx.ch ---
(In reply to Walter Bright from comment #28)
> Added the `safe` keyword because of the immutable variable issue described
> in the comments.

This is not a one-off issue. It is a symptom of the generally wrong behavior.
DMD is sharing the same memory for different variables with non-overlapping
lifetimes. This is plain memory corruption, whether or not immutable is
involved.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-05 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #29 from timon.g...@gmx.ch ---
(In reply to Walter Bright from comment #27)
> D closures are "by reference" rather than "by value". I make use of it being
> by reference all the time, as well as it being much more efficient. Changing
> it would likely break all sorts of code. So then the question is, what to do
> if you want it by value?
> ...

No, this is not about this distinction. Other programming languages, even those
that always capture by reference, do not have this problem. This form of memory
corruption cannot reasonably be defined away as a language feature.

> Now, the compiler could actually rewrite the delegate into the nested form
> above, but as I said, this changes the semantics of existing code, as well as
> being pretty inefficient. I doubt it would be acceptable.

All bug fixes change behavior of existing code. The current behavior is
unacceptable.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-04 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

Walter Bright  changed:

   What|Removed |Added

   Keywords||safe

--- Comment #28 from Walter Bright  ---
Added the `safe` keyword because of the immutable variable issue described in
the comments.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-04 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #27 from Walter Bright  ---
D closures are "by reference" rather than "by value". I make use of it being by
reference all the time, as well as it being much more efficient. Changing it
would likely break all sorts of code. So then the question is, what to do if
you want it by value?

One solution to creating such a delegate is to create it inside a nested
function:

  import core.stdc.stdio;
  int main()
  {
foreach (i; 0 .. 2)
{
void delegate(int) nested()
{
auto myi = i; // capture current value of i for use by del()
void del(int x)  // the real delegate
{
printf("&myi = %p\n", &myi);
}
return &del;
}
auto dg = nested();
dg(1);
}
return 0;
  }

Running it:
  &myi = 00261014
  &myi = 00261024

This works because `del` escapes its scope, and so the compiler allocates a
closure each time nested() is called, and `myi` is captured in that closure.

Now, the compiler could actually rewrite the delegate into the nested form
above, but as I said, this changes the semantics of existing code, as well as
being pretty inefficient. I doubt it would be acceptable.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-04-03 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #26 from Artem Borisovskiy  ---
Buckle up for celebration of 10 year anniversary and don't forget flowers for
Walter.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2018-01-06 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

ag0ae...@gmail.com changed:

   What|Removed |Added

 CC||alexandru.razva...@gmail.co
   ||m

--- Comment #25 from ag0ae...@gmail.com ---
*** Issue 18201 has been marked as a duplicate of this issue. ***

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2017-10-05 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

calex  changed:

   What|Removed |Added

 CC||calex+bugzilla-mail@aristow
   ||eb.net

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2016-04-09 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

ZombineDev  changed:

   What|Removed |Added

 CC||petar.p.ki...@gmail.com

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2016-04-08 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

Edwin van Leeuwen  changed:

   What|Removed |Added

 CC||ed...@tkwsping.nl

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2015-05-02 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #24 from timon.g...@gmx.ch ---
(In reply to Walter Bright from comment #21)
> The most practical solution is to simply disallow referencing variables from
> a dynamic closure that end sooner than the closing } of the function.
> 

Why? Lexical scoping exists for a reason.

> This leaves it up to the user to decide how to handle it, such as passing
> the variable explicitly as an argument, declaring the variable at function
> scope, or copying the variable to another declared at function scope.

It's up to the user anyway. Mandating the workaround may be the easiest to
implement, but it certainly isn't the right thing to do.

Of course, your suggestion might be implemented (*only for local scopes inside
loops, please*) as a temporary fix for type system unsoundness, but don't
assume that this will fix this issue.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2015-05-02 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #23 from Artem Borisovskiy  ---
(In reply to Walter Bright from comment #21)
> The most practical solution is to simply disallow referencing variables from
> a dynamic closure that end sooner than the closing } of the function.
> 
> This leaves it up to the user to decide how to handle it, such as passing
> the variable explicitly as an argument, declaring the variable at function
> scope, or copying the variable to another declared at function scope.

Well, if you think it's the most practical solution, then would you kindly
provide us with a couple of examples showing the solution from different
angles? It isn't clear how it solves the problem.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2015-05-01 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #22 from Ketmar Dark  ---
i.e. forbid closures at all. i wonder how should i pass additional parameter to
std.alporithm.map predicate though.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2015-05-01 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

Walter Bright  changed:

   What|Removed |Added

   Hardware|x86 |All
 OS|Windows |All

--- Comment #21 from Walter Bright  ---
The most practical solution is to simply disallow referencing variables from a
dynamic closure that end sooner than the closing } of the function.

This leaves it up to the user to decide how to handle it, such as passing the
variable explicitly as an argument, declaring the variable at function scope,
or copying the variable to another declared at function scope.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2014-10-03 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #20 from Gabor Mezo  ---
I agree. This is a bug definitely and shuld be addressed as soon as possible.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2014-10-03 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #19 from Artem Borisovskiy  ---
> If the loop index is mutable, then I think
> it's OK to make it shared across loop iterations.
Ridiculous.

--
void delegate()[] dgList;
const count = 10;

// 1
for (int i = 0; i < count; ++i)
  dgList ~= { writeln(i); }

// 2
foreach (immutable i; iota(count))
  dgList ~= { writeln(i); }
--

Why should 1 and 2 behave differently? Lambdas should capture outer variables
in a consistent way - by copying them to their activation record, just as all
other languages do. If you really want to capture the counter itself, you
should use a pointer, although it doesn't make sense either, because you'll get
an address of a stack-allocated variable.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2014-10-02 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #18 from hst...@quickfur.ath.cx ---
If the loop index is mutable, then I think it's OK to make it shared across
loop iterations. Creating a new instance of a loop variable per iteration is
only necessary if (1) the loop index is immutable, and (2) it is being closed
over.

(I also think modifying the loop counter of a foreach loop is a very bad idea
-- you should be using a good ole for(...) loop or while loop instead -- but
that's beside the point.)

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2014-10-02 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

Ketmar Dark  changed:

   What|Removed |Added

 CC||ket...@ketmar.no-ip.org

--- Comment #17 from Ketmar Dark  ---
(In reply to entheh from comment #16)
i believe that modifying `i` should be allowed here. but without 'ref' `i` is a
copy of internal counter, so your sample correctly iterates 10 times, updating
`i` to correct value on each iteration. but this works (and it's correct too):

  foreach (ref i; 0..10) {
++i; // skip one
writeln(i);
  }

this outputs 1, 3, 5, 7, 9.

> If 'i' became a new variable for each iteration, then the modify-assign
> would not have the effect intended.
it works this way now. ;-)

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2014-10-02 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #16 from ent...@cantab.net ---
Unfortunately I have a feeling there will be people relying on being able to do
this kind of thing (though I'm not 100% sure if it currently works):

foreach (i; 0..10) {
  ...
  if (somethingStrangeHappens) {
//Try again with the same 'i'
i--;
continue;
  }
}

If 'i' became a new variable for each iteration, then the modify-assign would
not have the effect intended. Do we need to make 'i' implicitly final to
protect against this?

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2014-10-02 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #15 from hst...@quickfur.ath.cx ---
P.S., printing out the addresses of local variables outside the loop as well as
the loop counter, reveals that if we comment out the line that initializes the
delegates closing over the loop counter, then the loop counter is allocated on
the stack, but with the closures, the compiler actually allocates the loop
counter on the heap. However, it fails to recognize that multiple iterations of
the loop will reuse the same heap variable.

So it looks like the compiler is already halfway there; it's already detecting
the closure and putting the loop counter on the heap instead of the stack. Now
the only thing that remains, is for it to detect that it needs a new instance
of the loop counter per iteration, as opposed to just a single instance.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2014-10-02 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

--- Comment #14 from hst...@quickfur.ath.cx ---
Note that the same thing applies if you make the loop counter immutable, which
the compiler also readily accepts. But the delegates will all capture the same
address which is reused over and over.

So, basically, the logical scope of the loop counter i should be restricted to
a *single* iteration (otherwise we must reject immutable loop counters!), but
currently, its actual scope is the loop body *across* all iterations. The
delegates exacerbate this problem by extending this scope even further, outside
the loop body. Ideally, the compiler should allocate each new loop counter
value on the heap, unless it can prove that there are no escaping references to
it at the end of the iteration, in which case it is then safe to put it on the
stack (and reuse the same memory for subsequent iterations).

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2014-10-02 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

hst...@quickfur.ath.cx changed:

   What|Removed |Added

 CC||hst...@quickfur.ath.cx

--- Comment #13 from hst...@quickfur.ath.cx ---
Note that this bug breaks immutability:

-
import std.stdio;

void main() {
void delegate()[] a;
foreach (i; 1 .. 10) {
immutable j = i;
writeln(j);
a ~= { writeln(j); };
}
writeln("---");
foreach (f; a) {
f();
}
}
-

Output:
-
1
2
3
4
5
6
7
8
9
---
9
9
9
9
9
9
9
9
9
-

Notice that in each iteration of the loop, we are closing on the immutable
value j, which is set to the loop counter. However, the output shows that the
value of j has changed since the delegates were initialized. In fact, it
changes at every iteration. This violates the guarantee of immutable.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly: should have multiple instances but only have one.

2014-10-02 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

ent...@cantab.net changed:

   What|Removed |Added

 CC||ent...@cantab.net
Summary|Closure outer variables in  |Closure outer variables in
   |nested blocks are not   |nested blocks are not
   |allocated/instantiated  |allocated/instantiated
   |correctly.  |correctly: should have
   ||multiple instances but only
   ||have one.

--- Comment #12 from ent...@cantab.net ---
Expanded summaries a little on this bug and on 8621 to prevent further
confusion - they are not duplicates.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly.

2014-10-01 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

Kenji Hara  changed:

   What|Removed |Added

 CC||and...@erdani.com

--- Comment #11 from Kenji Hara  ---
*** Issue 8621 has been marked as a duplicate of this issue. ***

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly.

2014-10-01 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

Gabor Mezo  changed:

   What|Removed |Added

 CC||gabor.m...@outlook.com

--- Comment #10 from Gabor Mezo  ---
Actually, I find this style of workaround mutch more readable than we seen
before:

foreach (idx; 1 .. data.length)
{
 (idx)
 {
   // Do stuff
 }(idx);
}

It not looks too ugly if you have some JS background. :)

Please fix this bug ASAP. I really like this language but this POS always makes
me sad if I take a look at my code.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly.

2014-07-15 Thread via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=2043

Artem Borisovskiy  changed:

   What|Removed |Added

 CC||kolo...@bk.ru
   Severity|normal  |major

--- Comment #9 from Artem Borisovskiy  ---
I write a simple app that reads a binary log file, decrypts the messages in
parrallel and prints them when all the decrypting threads are finished. Here's
a piece of my code:

--
auto workers = new ThreadGroup;
int i;
foreach (group; logEntries.chunks(averageChunkSize)) () {
auto data = group;
auto ii = i;
auto workerThread = new Thread(
{
writefln("[%s] %s", ii, data.length);
});
workers.add(workerThread);
workerThread.start;
++i;
}();
workers.joinAll;
--

As you can see, I tried to use hack from the code above, but it didn't help
until I created "data" and "ii" variables. Just using "i" and "group" gives
wrong results, just as described by Bruno. The same code works perfectly in
Java, and it should in D, because it's the way closures work.

Please, fix this bug, it's real PITA and it's 6 years old after all.

--


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly.

2013-01-05 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=2043


Russ Lewis  changed:

   What|Removed |Added

 CC||webmaster@villagersonline.c
   ||om


--- Comment #8 from Russ Lewis  2013-01-05 
23:52:25 PST ---
Comment 7's workaround is a little brilliant, though terribly hard to read. 
Basically, it's declaring a delegate with the
() {
   
}
syntax, and calling it (with a trailing () ), all inline in each pass of the
for() loop.

This works around the problem because, as far as I can tell, the DMD compiler
will make only 1 heap copy of any given variable *per instance of a function
call*, even if the variable is a loop-local variable.  So, if you run 10
iterations of a for() loop, and create a delegate in each one, then all 10
iterations of the loop share the same heap space for their variables, even the
loop-local ones (which ought to have 10 different copies).  But, if you instead
call the same function 10 times in a row (as comment 7 effectively does), then
you get 10 different copies of the variable on the heap.

I can understand why this is a hard problem to solve on the compiler
side...but, IMHO, it's a fairly important one to solve.  This bug causes some
rather hard-to-understand bugs in what would otherwise look like
straightforward code.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly.

2012-06-19 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=2043


timon.g...@gmx.ch changed:

   What|Removed |Added

 CC||timon.g...@gmx.ch


--- Comment #7 from timon.g...@gmx.ch 2012-06-19 09:27:41 PDT ---
(In reply to comment #6)
> ...
> Simplified case, which returns array of delegates each printing next integer.
> 
>   import std.stdio;
>   alias void delegate() D;
>   /* do not work, */
>   auto f(int n) {
> auto tab = new D[n];
> for (int i = 0; i < n; i++) {
> // invariant ii = i; // will not help
> // struct S { int i_; }; S x = new S; x.i_ = i;
> // will also not help, as x is on stack
> tab[i] = delegate void() { writefln("i=%d", i); };
> // also using nested function, and taking address do not work
> }
> return tab;
>   }
> 
>   void main() {
> auto tab = f(10);
> foreach (k, ref x; tab) {
> writef("%d : ", k);
> x();
> }
>   }
> 
> It currently will print in all cases:
> 
>   0 : i=10
>   1 : i=10
>   2 : i=10
>   3 : i=10
>   4 : i=10
>   5 : i=10
>   6 : i=10
>   7 : i=10
>   8 : i=10
>   9 : i=10
> 
> 
> My current workaround involves looping using recursion (and be sure that
> compiler do not make it tail-recursive probably):
> [snip.]

There is a much simpler workaround:

  import std.stdio;
  alias void delegate() D;

  auto f(int n) {
auto tab = new D[n];
for (int i = 0; i < n; i++) (){ int i = i;
tab[i] = delegate void() { writefln("i=%d", i); };
}();
return tab;
  }

  void main() {
auto tab = f(10);
foreach (k, ref x; tab) {
writef("%d : ", k);
x();
}
  }

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly.

2011-01-01 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=2043


Witold Baryluk  changed:

   What|Removed |Added

 CC||bary...@smp.if.uj.edu.pl


--- Comment #6 from Witold Baryluk  2011-01-01 
18:20:46 PST ---
I today hit this bug. It really isn't obvious how to workaround this problem.
It is not possible to easly just allocate variable or struct with variable's
value manually, as it still will just by single identifier, and it will at the
end still point to single entity.

Simplified case, which returns array of delegates each printing next integer.

  import std.stdio;
  alias void delegate() D;
  /* do not work, */
  auto f(int n) {
auto tab = new D[n];
for (int i = 0; i < n; i++) {
// invariant ii = i; // will not help
// struct S { int i_; }; S x = new S; x.i_ = i;
// will also not help, as x is on stack
tab[i] = delegate void() { writefln("i=%d", i); };
// also using nested function, and taking address do not work
}
return tab;
  }

  void main() {
auto tab = f(10);
foreach (k, ref x; tab) {
writef("%d : ", k);
x();
}
  }

It currently will print in all cases:

  0 : i=10
  1 : i=10
  2 : i=10
  3 : i=10
  4 : i=10
  5 : i=10
  6 : i=10
  7 : i=10
  8 : i=10
  9 : i=10


My current workaround involves looping using recursion (and be sure that
compiler do not make it tail-recursive probably):

/* recursive loop version will work */
auto f2(int n) {
auto tab = new D[n];
void f2r(int i) {
tab[i] = delegate void() { writefln("i=%d", i); };
if (i < n-1) {
f2r(i+1); /* recursion */
}
}
f2r(0); /* enter recursion */
return tab;
}

Which will make our constructed delegates work as desired:

  0 : i=0
  1 : i=1
  2 : i=2
  3 : i=3
  4 : i=4
  5 : i=5
  6 : i=6
  7 : i=7
  8 : i=8
  9 : i=9

(I tested if this is not just a a coincidence, but overwriting stack by random
values, and it works still correctly. BTW. switch for compiler which will show
what local variables are/will automatically allocated on heap will be usefull).

As of definitive solution, i think "invariant" which is referenced by escaping
delegate should be allocated on heap, and its addresses should be remembered
immediately in constructed delegate. Other possibility is separate syntax, like
"new delegate void() ... ", which will make all variables referenced by
delegate a copies of current values of variables with the same names
(considering scoping rules).


Hope this will be helpful for somebody.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 2043] Closure outer variables in nested blocks are not allocated/instantiated correctly.

2010-11-19 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=2043


Bruno Medeiros  changed:

   What|Removed |Added

 CC||nfx...@gmail.com


--- Comment #5 from Bruno Medeiros  2010-11-19 
08:59:46 PST ---
*** Issue 4966 has been marked as a duplicate of this issue. ***

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---