(DMD) problem with closures/delegate literals and structs?
Iain Buclaw
ibuclaw at gdcproject.org
Sat Dec 7 16:17:02 PST 2013
On 7 December 2013 20:30, H. S. Teoh <hsteoh at 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" <hsteoh at 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. :)
More information about the D.gnu
mailing list