On 7 December 2013 20:30, H. S. Teoh <hst...@quickfur.ath.cx> wrote: > On Sat, Dec 07, 2013 at 07:32:46PM +0100, Johannes Pfau wrote: >> Am Sat, 7 Dec 2013 08:43:53 -0800 >> schrieb "H. S. Teoh" <hst...@quickfur.ath.cx>: >> >> > On Sat, Dec 07, 2013 at 10:08:25AM +0100, Johannes Pfau wrote: >> > [...] >> > > It looks like we actually generate a closure here which contains >> > > the this pointer instead of directly using the struct as a context >> > > pointer. That is probably an optimization bug in dmd, but it >> > > doesn't matter in this case as the problem would exist for >> > > closures and normal delegates. >> > >> > The problem is that delegates are never passed the this pointer from >> > the caller; it is assumed that it's part of their context. You never >> > write `myStruct.dg(args)`, but simply `dg(args)`. But by the time >> > the delegate is invoked, you can't guarantee that `this` is still >> > valid. Only the caller knows what copy of the struct it still >> > holds, but this isn't communicated to the delegate. (On second >> > thought, even if it *did* pass the updated `this` to the delegate, >> > it would still be wrong, because there could be multiple copies of >> > the struct by then, and who knows which copy the delegate was >> > supposed to be operating on?) >> >> True, but that's not what I meant ;-) >> I always get the terminology related to closures wrong so sorry if >> that didn't make sense. >> >> What I meant is this: In the first example I posted, >> http://dpaste.dzfl.pl/433c0a3d >> the delegate does not access _function variables_. It only accesses >> the this pointer. So there's no need for it to be a real closure and >> allocate memory, it could instead be a normal delegate with the >> context pointer simply set to the this pointer at the moment the >> delegate is created. > > The problem is that when `this` is closed over, it's one thing, but when > the delegate is invoked later, `this` may no longer be valid. For > example: > > struct S { > int x = 123; // canary > void delegate() getDelegate() { > // Closes over `this` > return () => x; > } > } > > void delegate() dg; > > S makeStruct() { > S s; > dg = s.getDelegate(); > return s; > } > > void main() { > auto s = makeStruct(); > dg(); // <-- NG > } >
I feel inclined to make that always make that sort of usage an error. :)