October 30, 2013 Re: Delegate is left with a destroyed stack object | ||||
---|---|---|---|---|
| ||||
Posted in reply to Max Samukha | On Wednesday, 30 October 2013 at 12:17:29 UTC, Max Samukha wrote: > So D managed to mess up closures, too. And that's after years of countless complaints about the same issue in JS! And please no misguided arguments like http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx. |
October 30, 2013 Re: Delegate is left with a destroyed stack object | ||||
---|---|---|---|---|
| ||||
Posted in reply to Max Samukha | On Wednesday, 30 October 2013 at 12:28:13 UTC, Max Samukha wrote:
> On Wednesday, 30 October 2013 at 12:17:29 UTC, Max Samukha wrote:
>
>> So D managed to mess up closures, too. And that's after years of countless complaints about the same issue in JS!
>
> And please no misguided arguments like http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx.
Quoting : "UPDATE: We are taking the breaking change. In C# 5, the loop variable of a foreach will be logically inside the loop, and therefore closures will close over a fresh copy of the variable each time. The "for" loop will not be changed. We return you now to our original article."
Javascript is introducing the let keyword to create properly scoped variables. It seems everybody agrees on what should have been done.
|
October 30, 2013 Re: Delegate is left with a destroyed stack object | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Wednesday, 30 October 2013 at 07:49:48 UTC, Jacob Carlborg wrote:
> On 2013-10-29 22:57, Ali Çehreli wrote:
>
>> Imagine someone decides to return a lambda from foo() instead:
>>
>> auto foo()
>> {
>> S s = S(1);
>> return {}; // <-- Should 's' be immortal now?
>> }
>>
>> Too subtle for my taste! :)
>
> Of course not. "s" is never referred to in the returned delegate.
Yes, only variables actually referenced by a nested fiction are placed in the nested context.
I agree that the fact that an object's destructor is not run at the end of the parent function should ideally be more easily visible, but given the inherently implicit nature of D's closures, I'm not sure we can do much about that.
David
|
October 30, 2013 Re: Delegate is left with a destroyed stack object | ||||
---|---|---|---|---|
| ||||
Posted in reply to Lionello Lunesu | On Wednesday, 30 October 2013 at 09:20:40 UTC, Lionello Lunesu wrote:
> On 10/29/13, 22:42, David Nadlinger wrote:
>> On Tuesday, 29 October 2013 at 21:41:25 UTC, Lionello Lunesu wrote:
>>> So a copy should have been made of the live object, not the destructed
>>> one. Correct?
>>
>> No. There should only be one struct instance, the one living (forever)
>> in the closure context.
>>
>> David
>
> Why? It's a struct. It should be completely fine to create a copy [on the heap] for the closure context.
That would be worse:
void increment(ref int x) { ++x; }
void run(void delegate() f) { f(); }
void main()
{
int x = 0;
run( { increment(x); } );
writeln(x);
}
If the closure took a copy of x then this would write 0. Certainly not what I would expect.
I think not running the destructor is the best option (although to be honest, I'm not a huge fan of closures to begin with, for exactly these sorts of reasons -- they only really work well in a pure functional setting).
|
October 30, 2013 Re: Delegate is left with a destroyed stack object | ||||
---|---|---|---|---|
| ||||
Posted in reply to David Nadlinger | On 10/30/2013 10:56 AM, David Nadlinger wrote: > On Wednesday, 30 October 2013 at 09:20:40 UTC, Lionello Lunesu wrote: >> Why? It's a struct. It should be completely fine to create a copy [on >> the heap] for the closure context > > That's definitely not how D closures work, they always refer to local > variables "by reference". > > One other place where this tends to crop is for code involving loop > variables, but while the behavior might be unexpected to some, > discussion has made clear that the code works as intended: > > --- > void main() { > import std.stdio; > > void delegate()[] dgs; > foreach (i; 0 .. 5) dgs ~= { writeln(i); }; > > foreach (dg; dgs) dg(); > } > --- > > If structs behaved like you want them to, the snippet would (have to) > print 0, 1, 2, 3, 4 as well, and tht's definitely too big a language > change to consider at this stage. > > David No, the current behaviour is an implementation bug and the expected behaviour is indeed to print the numbers from zero to four. The foreach iteration variable is stored in loop iteration scope since 2.063. The frontend never allocates closures in such a scope even though it is required for basic type safety. Bug report: http://d.puremagic.com/issues/show_bug.cgi?id=2043 Past discussion: http://forum.dlang.org/thread/felqszcrbvtrepjtfpul@forum.dlang.org Your example can be changed to use a for loop, and then it indeed illustrates your point. for(int i=0;i<5;i++) dgs ~= { writeln(i); }; foreach (dg; dgs) dg(); // prints 5 five times |
October 30, 2013 Re: Delegate is left with a destroyed stack object | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On 10/29/2013 10:55 AM, Ali Çehreli wrote: > Continuing the conversation from the following thread: > > http://forum.dlang.org/post/l4mi8l$1r1$1@digitalmars.com Kenji Hara added there: ===== The combination of closure variables + scoped destruction should be rejected, but currently it isn't. It's a compiler bug. http://d.puremagic.com/issues/show_bug.cgi?id=11382 Kenji Hara ===== Ali |
October 31, 2013 Re: Delegate is left with a destroyed stack object | ||||
---|---|---|---|---|
| ||||
Posted in reply to Peter Alexander | On Wednesday, 30 October 2013 at 20:35:14 UTC, Peter Alexander wrote:
> I think not running the destructor is the best option (although to be honest, I'm not a huge fan of closures to begin with, for exactly these sorts of reasons -- they only really work well in a pure functional setting).
I disagree. Closures work well in Scheme (more generally, Lisps) and ML, which are not purely functional languages. In SICP *, the combination of closures and mutable state is used to model OO. I used closures more than I used OO in OCaml.
Things are trickier in D for a trickier of reasons. You may be right about not running the destructor; I'm still thinking about it.
-- Brian
* The Structure and Interpretation of Computer Programs by Abelson and Sussman, for those who don't know.
|
October 31, 2013 Re: Delegate is left with a destroyed stack object | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Wednesday, 30 October 2013 at 21:15:37 UTC, Ali Çehreli wrote:
> On 10/29/2013 10:55 AM, Ali Çehreli wrote:
>
> > Continuing the conversation from the following thread:
> >
> > http://forum.dlang.org/post/l4mi8l$1r1$1@digitalmars.com
>
> Kenji Hara added there:
>
> =====
> The combination of closure variables + scoped destruction should
> be rejected, but currently it isn't. It's a compiler bug.
>
> http://d.puremagic.com/issues/show_bug.cgi?id=11382
>
> Kenji Hara
> =====
>
> Ali
kenji is right. compilation error is the only safe approach, if you do not wish scoped destruction, don’t request it in the first place! dangerous operations like this should be explicit to avoid surprises, not hidden in complicared implicit special cases.
|
October 31, 2013 Re: Delegate is left with a destroyed stack object | ||||
---|---|---|---|---|
| ||||
Posted in reply to Xiaoxi | On Thursday, 31 October 2013 at 00:46:05 UTC, Xiaoxi wrote:
> On Wednesday, 30 October 2013 at 21:15:37 UTC, Ali Çehreli wrote:
>> On 10/29/2013 10:55 AM, Ali Çehreli wrote:
>>
>> > Continuing the conversation from the following thread:
>> >
>> > http://forum.dlang.org/post/l4mi8l$1r1$1@digitalmars.com
>>
>> Kenji Hara added there:
>>
>> =====
>> The combination of closure variables + scoped destruction should
>> be rejected, but currently it isn't. It's a compiler bug.
>>
>> http://d.puremagic.com/issues/show_bug.cgi?id=11382
>>
>> Kenji Hara
>> =====
>>
>> Ali
>
> kenji is right. compilation error is the only safe approach, if you do not wish scoped destruction, don’t request it in the first place! dangerous operations like this should be explicit to avoid surprises, not hidden in complicared implicit special cases.
This is wrong in a point that accessing object or not running destructor is not safe: closures can touch any object, not only structs, making them allocated in heap, and there are many cases when struct destructors are not called.
|
October 31, 2013 Re: Delegate is left with a destroyed stack object | ||||
---|---|---|---|---|
| ||||
Posted in reply to Peter Alexander | On 2013-10-30 21:35, Peter Alexander wrote: > I think not running the destructor is the best option (although to be > honest, I'm not a huge fan of closures to begin with, for exactly these > sorts of reasons -- they only really work well in a pure functional > setting). I use Ruby all day with a lot of blocks (closures) and I never had any problem. In Ruby everything is an object and passed around by reference. I guess that's help. BTW, the default iteration pattern in Ruby is to use blocks: [1, 2, 3].each { |e| puts e } Closest translation in D: [1, 2, 3].each!(e => writeln(e)); But in D one would of course use a foreach loop instead. -- /Jacob Carlborg |
Copyright © 1999-2021 by the D Language Foundation