digitalmars.D - Delegate is left with a destroyed stack object
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (29/29) Oct 29 2013 Continuing the conversation from the following thread:
- Craig Dillabaugh (7/37) Oct 29 2013 According to the Book of Revelations, 666 is the number of the
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (3/5) Oct 29 2013 That's awesome! :)
- Jacob Carlborg (4/33) Oct 29 2013 Shouldn't "s" be moved to the heap and not destroyed.
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (4/5) Oct 29 2013 We are waiting for Walter to say the same thing and Kenji Hara to fix it...
- qznc (10/34) Oct 29 2013 Seems reasonable to me.
- Dicebot (1/4) Oct 29 2013
- Peter Alexander (9/11) Oct 29 2013 According to http://dlang.org/function.html
- David Nadlinger (16/21) Oct 29 2013 That's not how closures work in D – the local variables
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (8/13) Oct 29 2013 To add to that, Maxim Fomin notes in the D.learn forum that there are
- Lionello Lunesu (4/6) Oct 29 2013 So a copy should have been made of the live object, not the destructed
- David Nadlinger (5/7) Oct 29 2013 No. There should only be one struct instance, the one living
- Lionello Lunesu (9/15) Oct 30 2013 Why? It's a struct. It should be completely fine to create a copy [on
- David Nadlinger (19/21) Oct 30 2013 That's definitely not how D closures work, they always refer to
- Lionello Lunesu (5/16) Oct 30 2013 Well, that's a separate issue, whether to change the language or not.
- Max Samukha (4/19) Oct 30 2013 So D managed to mess up closures, too. And that's after years of
- Max Samukha (3/5) Oct 30 2013 And please no misguided arguments like
- deadalnix (9/15) Oct 30 2013 Quoting : "UPDATE: We are taking the breaking change. In C# 5,
- Marco Leise (8/15) Nov 05 2013 Without thinking much about it, why not call loop variables
- Timon Gehr (13/33) Oct 30 2013 No, the current behaviour is an implementation bug and the expected
- Peter Alexander (17/31) Oct 30 2013 That would be worse:
- Brian Rogoff (12/16) Oct 30 2013 I disagree. Closures work well in Scheme (more generally, Lisps)
- Jacob Carlborg (11/15) Oct 31 2013 I use Ruby all day with a lot of blocks (closures) and I never had any
- Jakob Ovrum (4/5) Oct 31 2013 I think `std.algorithm.copy` is generally a good replacement for
- Peter Alexander (4/20) Oct 31 2013 Those aren't closures, it captures none of the environment. Those
- Chris Nicholson-Sauls (34/52) Nov 02 2013 Maybe this would be a better Ruby example?
- David Nadlinger (6/12) Oct 29 2013 Closures follow the infinite lifetime model – the struct scope is
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (40/44) Oct 29 2013 Agreed but the implicit nature of things is troubling. Imagine that the
- Maxim Fomin (28/41) Oct 29 2013 It may be confusing but I agree that disabling dtor invocation at
- Jacob Carlborg (4/11) Oct 30 2013 Of course not. "s" is never referred to in the returned delegate.
- David Nadlinger (9/21) Oct 30 2013 Yes, only variables actually referenced by a nested fiction are
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (9/11) Oct 30 2013 Kenji Hara added there:
- Xiaoxi (5/17) Oct 30 2013 kenji is right. compilation error is the only safe approach, if
- Maxim Fomin (5/31) Oct 30 2013 This is wrong in a point that accessing object or not running
- Timon Gehr (6/23) Oct 31 2013 Destruction is implicit and it is possible to allocate structs on the
Continuing the conversation from the following thread: http://forum.dlang.org/post/l4mi8l$1r1$1 digitalmars.com (Note: The OP's example there behaves as expected on git head.) The programmer thinks that the following delegate returned by foo() will print S(1) because the delegate uses the local 's' which is supposed to live long enough: import std.stdio; struct S { int i; ~this() { i = 666; } } auto foo() { S s = S(1); return { writeln(s); } ; // <-- Uses local s } void main() { foo()(); } However, 's' gets destroyed upon leaving foo() and the delegate is left with a destroyed object; so the program prints S(666). Is that by design or a bug? Aside: Never mind that the destroyed object gets destroyed again, and again, and again. :) (Well, presumably after being copied to other object in its dead state, because the address of the object is not the same.) (Put a writeln() inside the destructor to see that in action.) Ali
Oct 29 2013
On Tuesday, 29 October 2013 at 17:55:45 UTC, Ali Çehreli wrote:Continuing the conversation from the following thread: http://forum.dlang.org/post/l4mi8l$1r1$1 digitalmars.com (Note: The OP's example there behaves as expected on git head.) The programmer thinks that the following delegate returned by foo() will print S(1) because the delegate uses the local 's' which is supposed to live long enough: import std.stdio; struct S { int i; ~this() { i = 666; } } auto foo() { S s = S(1); return { writeln(s); } ; // <-- Uses local s } void main() { foo()(); } However, 's' gets destroyed upon leaving foo() and the delegate is left with a destroyed object; so the program prints S(666). Is that by design or a bug? Aside: Never mind that the destroyed object gets destroyed again, and again, and again. :) (Well, presumably after being copied to other object in its dead state, because the address of the object is not the same.) (Put a writeln() inside the destructor to see that in action.) AliAccording to the Book of Revelations, 666 is the number of the Beast (Rev. 13:18), and later (Revelations 19:20) it is stated that the Beast will be thrown into a lake of fire and brimstone. That may explain the repeated destruction of s :o) Whether that is a bug or not, I am unsure. Craig
Oct 29 2013
On 10/29/2013 12:02 PM, Craig Dillabaugh wrote:the Beast will be thrown into a lake of fire and brimstone. That may explain the repeated destruction of s :o)That's awesome! :) Ali
Oct 29 2013
On 2013-10-29 18:55, Ali Çehreli wrote:Continuing the conversation from the following thread: http://forum.dlang.org/post/l4mi8l$1r1$1 digitalmars.com (Note: The OP's example there behaves as expected on git head.) The programmer thinks that the following delegate returned by foo() will print S(1) because the delegate uses the local 's' which is supposed to live long enough: import std.stdio; struct S { int i; ~this() { i = 666; } } auto foo() { S s = S(1); return { writeln(s); } ; // <-- Uses local s } void main() { foo()(); } However, 's' gets destroyed upon leaving foo() and the delegate is left with a destroyed object; so the program prints S(666). Is that by design or a bug? Aside: Never mind that the destroyed object gets destroyed again, and again, and again. :) (Well, presumably after being copied to other object in its dead state, because the address of the object is not the same.) (Put a writeln() inside the destructor to see that in action.) AliShouldn't "s" be moved to the heap and not destroyed. -- /Jacob Carlborg
Oct 29 2013
On 10/29/2013 01:23 PM, Jacob Carlborg wrote:Shouldn't "s" be moved to the heap and not destroyed.We are waiting for Walter to say the same thing and Kenji Hara to fix it last month. ;) Ali
Oct 29 2013
On Tuesday, 29 October 2013 at 17:55:45 UTC, Ali Çehreli wrote:Continuing the conversation from the following thread: http://forum.dlang.org/post/l4mi8l$1r1$1 digitalmars.com (Note: The OP's example there behaves as expected on git head.) The programmer thinks that the following delegate returned by foo() will print S(1) because the delegate uses the local 's' which is supposed to live long enough: import std.stdio; struct S { int i; ~this() { i = 666; } } auto foo() { S s = S(1); return { writeln(s); } ; // <-- Uses local s } void main() { foo()(); } However, 's' gets destroyed upon leaving foo() and the delegate is left with a destroyed object; so the program prints S(666). Is that by design or a bug?Seems reasonable to me. S s = S(1); // allocates on the stack, because value type, i is now 1 { writeln(s); } // creates closure with reference to stack memory "&s" return ... // returns and destroys local variable s, i is now 666 foo()() // calls closure with reference to invalid memory "&s" Returning closures with reference to stack memory is a bad idea. Maybe safe should prohibit this?
Oct 29 2013
http://dlang.org/function.htmlThe stack variables referenced by a nested function are still valid even after the function exits (this is different from D 1.0). This is called a closure.
Oct 29 2013
On Tuesday, 29 October 2013 at 21:14:39 UTC, qznc wrote:Returning closures with reference to stack memory is a bad idea. Maybe safe should prohibit this?According to http://dlang.org/function.html "The stack variables referenced by a nested function are still valid even after the function exits (this is different from D 1.0). This is called a closure." It it completely valid to reference that memory. It gets moved onto the heap when you create the closure. The problem is that the destructor still gets called, so the variable is no longer in a valid state post return.
Oct 29 2013
On Tuesday, 29 October 2013 at 21:14:39 UTC, qznc wrote:{ writeln(s); } // creates closure with reference to stack memory "&s" return ... // returns and destroys local variable s, i is now 666 foo()() // calls closure with reference to invalid memory "&s"That's not how closures work in D – the local variables referenced by nested functions/closures will be allocated inside the "nested context" for the function, which is placed on the GC heap if a reference to it can be escaped. Play around with the example some more if you want: Barring any further DMD bugs, you are not going to get the contents of i to be corrupted (i.e. set to another garbage value). The problem with the compiler behavior for the code in question is that it destructs a live object, and thus clearly breaks the type system. I think the only correct resolution is to not destruct the object at the end of foo() – which incidentally also means that the destructor will never be invoked, just as for any other GC-finalized memory. David
Oct 29 2013
On 10/29/2013 02:32 PM, David Nadlinger wrote:The problem with the compiler behavior for the code in question is that it destructs a live object, and thus clearly breaks the type system. I think the only correct resolution is to not destruct the object at the end of foo() – which incidentally also means that the destructor will never be invoked, just as for any other GC-finalized memory.To add to that, Maxim Fomin notes in the D.learn forum that there are the following conflicting requirements: 1) need to allocate struct into heap due to lambda 2) need to put dtor invocation in the end as usual. The first one is supported by the closure spec. The second one is the well-know struct destruction upon leaving a scope. Ali
Oct 29 2013
On 10/29/13, 22:37, Ali Çehreli wrote:To add to that, Maxim Fomin notes in the D.learn forum that there are the following conflicting requirements:So a copy should have been made of the live object, not the destructed one. Correct? Sounds like the destruction and the copy are happening in the wrong order.
Oct 29 2013
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
Oct 29 2013
On 10/29/13, 22:42, David Nadlinger wrote:On Tuesday, 29 October 2013 at 21:41:25 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. The way I see closure is that any referenced locals become hidden arguments. Imagine an implicit ", S s" in the closure's parameter list. Everybody would expect 's' (being a value type) to be a copy. If you want to ensure there's only one instance, you either need to use class instead of struct, or allocate 's' on the heap and use a pointer to S. L.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
Oct 30 2013
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 contextThat'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
Oct 30 2013
On 10/30/13, 10:56, David Nadlinger wrote:--- 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,Did NOT know that. Thanks for letting me know :)and tht's definitely too big a language change to consider at this stage.Well, that's a separate issue, whether to change the language or not. It's still valuable to discuss unexpected behavior when one runs into it. L.
Oct 30 2013
On Wednesday, 30 October 2013 at 09:56:08 UTC, David Nadlinger wrote: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. DavidSo D managed to mess up closures, too. And that's after years of countless complaints about the same issue in JS!
Oct 30 2013
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.
Oct 30 2013
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: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.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.
Oct 30 2013
Am Wed, 30 Oct 2013 13:28:12 +0100 schrieb "Max Samukha" <maxsamukha gmail.com>:On Wednesday, 30 October 2013 at 12:17:29 UTC, Max Samukha wrote:Without thinking much about it, why not call loop variables temporaries that you cannot close over. If you want a closure you'd have to declare the variable either inside or outside the loop. -- MarcoSo 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.
Nov 05 2013
On 10/30/2013 10:56 AM, David Nadlinger wrote:On Wednesday, 30 October 2013 at 09:20:40 UTC, Lionello Lunesu wrote: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 timesWhy? It's a struct. It should be completely fine to create a copy [on the heap] for the closure contextThat'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
Oct 30 2013
On Wednesday, 30 October 2013 at 09:20:40 UTC, Lionello Lunesu wrote:On 10/29/13, 22:42, David Nadlinger wrote: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).On Tuesday, 29 October 2013 at 21:41:25 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.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
Oct 30 2013
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.
Oct 30 2013
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
Oct 31 2013
On Thursday, 31 October 2013 at 07:41:30 UTC, Jacob Carlborg wrote:But in D one would of course use a foreach loop instead.I think `std.algorithm.copy` is generally a good replacement for foreach loops in functional D code.
Oct 31 2013
On Thursday, 31 October 2013 at 07:41:30 UTC, Jacob Carlborg wrote:On 2013-10-30 21:35, Peter Alexander wrote:Those aren't closures, it captures none of the environment. Those are just simple lambda functions.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.
Oct 31 2013
On Thursday, 31 October 2013 at 20:56:11 UTC, Peter Alexander wrote:On Thursday, 31 October 2013 at 07:41:30 UTC, Jacob Carlborg wrote:Maybe this would be a better Ruby example? module App def self.run register_callbacks Other.call_all end def self.register_callbacks foo = 10 Other.register { puts foo } Other.register { puts self } foo = 20 Other.register { puts foo } foo = 30 end end module Other callbacks = [] def self.register (&blk) callbacks << blk end def self.call_all callbacks.each {|cb| cb.call } end end App.run if __FILE__ == $0 Output is: 30 App 30 -- Chris NSI 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.Those aren't closures, it captures none of the environment. Those are just simple lambda functions.
Nov 02 2013
On Tuesday, 29 October 2013 at 21:37:43 UTC, Ali Çehreli wrote:To add to that, Maxim Fomin notes in the D.learn forum that there are the following conflicting requirements: 1) need to allocate struct into heap due to lambda 2) need to put dtor invocation in the end as usual. The first one is supported by the closure spec. The second one is the well-know struct destruction upon leaving a scope.Closures follow the infinite lifetime model – the struct scope is never left, if you want. This is not exactly a new scenario, destructors on new'd structs aren't called either (unless you manually destroy them). David
Oct 29 2013
On 10/29/2013 02:41 PM, David Nadlinger wrote:Closures follow the infinite lifetime model – the struct scope is never left, if you want.Agreed but the implicit nature of things is troubling. Imagine that the program depends on the destructor to be called: void foo() { auto s = S(1); // ... } Later, somebody creates a lambda that silently extends the lifetime of the stack frame (apparently, infinitely). That may be very surprising. Aside: Is it still a closure if the lambda does not refer to the stack frame? If so, it is even worse: import std.stdio; struct S { int i; ~this() { writeln("dtor"); } } void bar() {} auto foo() { S s = S(1); return &bar; // <-- all is well, this is not a closure } void main() { foo()(); } 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! :)This is not exactly a new scenario, destructors on new'd structs aren't called either (unless you manually destroy them).At least in the case of a new'ed structs I have a convenient way to destroy them through a pointer. I think in the case of a closure I must go through hoops to access or save that pointer. Ali
Oct 29 2013
On Tuesday, 29 October 2013 at 21:57:25 UTC, Ali Çehreli wrote:On 10/29/2013 02:41 PM, David Nadlinger wrote:It may be confusing but I agree that disabling dtor invocation at the end of function scope is a right decision. Technically scope is left, but lifetime continues.Closures follow the infinite lifetime model – the structscope is neverleft, if you want.Agreed but the implicit nature of things is troubling. Imagine that the program depends on the destructor to be called:This is not a big deal. Another but similar case: import std.stdio; struct S { int i; ~this() { writefln("dtor %X, %X", &this, i); } } auto foo() { S s = S(1); struct SS { void bar() { s = S(2); } } return SS(); } void main() { foo().bar(); } So, one need also to be aware of nested structs (or functions) touching local objects.This is not exactly a new scenario, destructors on new'dstructs aren'tcalled either (unless you manually destroy them).At least in the case of a new'ed structs I have a convenient way to destroy them through a pointer. I think in the case of a closure I must go through hoops to access or save that pointer. Ali
Oct 29 2013
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. -- /Jacob Carlborg
Oct 30 2013
On Wednesday, 30 October 2013 at 07:49:48 UTC, Jacob Carlborg wrote:On 2013-10-29 22:57, Ali Çehreli wrote: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. DavidImagine 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.
Oct 30 2013
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.comKenji 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
Oct 30 2013
On Wednesday, 30 October 2013 at 21:15:37 UTC, Ali Çehreli wrote:On 10/29/2013 10:55 AM, Ali Çehreli wrote: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.Continuing the conversation from the following thread: http://forum.dlang.org/post/l4mi8l$1r1$1 digitalmars.comKenji 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
Oct 30 2013
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: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.On 10/29/2013 10:55 AM, Ali Çehreli wrote: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.Continuing the conversation from the following thread: http://forum.dlang.org/post/l4mi8l$1r1$1 digitalmars.comKenji 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
Oct 30 2013
On 10/31/2013 01:46 AM, Xiaoxi wrote:I think nobody is 'right' here.===== 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 ===== Alikenji is right.compilation error is the only safe approach, if you do not wish scoped destruction, don’t request it in the first place!Destruction is implicit and it is possible to allocate structs on the heap anyway.dangerous operations like this should be explicit to avoid surprises, not hidden in complicared implicit special cases.If failing compilation is the way to go, avoiding special cases is not why. Erroring out here is a special case.
Oct 31 2013