Trouble with anon delegates.

Frits van Bommel fvbommel at REMwOVExCAPSs.nl
Tue Jan 16 14:12:24 PST 2007


Pragma wrote:
> All,
>   I ran into a small problem regarding the use of anon delegates, and 
> what their context (.ptr) is set to.  If anyone can share any insight as 
> to if this is a bug or not, I would appreciate it.
> 
> In short: I'm attempting to create delegates on the fly and use them 
> elsewhere.  After many strange errors, I narrowed it down to the 
> following case.  Note the assertions at the end:
> 
> abstract class Foobar{
>     Fn getFn();
> }
> alias void delegate() Fn;
> 
> auto foo = new class Foobar{
>     int x;
>     Fn getFn(){
>     return { x = x };
>     }
> };

That class has a member function returning a delegate. That returned 
delegate has the stack frame of said member function as its context 
pointer and should thus not be called after it returns.
Basically, the return value is useless as it can't safely be called.

> auto fn = foo.getFn();

'fn' now contains said delegate, with the context pointer set to an 
invalidated stackframe.

> assert((&foo.getFn).ptr is foo); // passes

(&foo.getFn) is a delegate with context foo and function pointer Foo.getFn.

> assert(fn.ptr is foo); // fails (ptr does *not* point to the object)

fn.ptr is the invalid stack frame of the call to foo.getFn(), not foo 
itself.

> So by this, anon delegates are not the same as actual object delegates.  
> Is this a bug, or is this intentional?

Intentional.

> "When comparing with nested functions, the function form is analogous to 
> static or non-nested functions, and the delegate form is analogous to 
> non-static nested functions. In other words, a delegate literal can 
> access stack variables in its enclosing function, a function literal 
> cannot."
> 
> As you can see, the docs are as clear as mud.  I suppose a "non-static 
> nested function" wouldn't know about the 'this' pointer, nor care - but 
> then why encumber it with the 'delegate' keyword?

It *does* know about 'this'. However, its context pointer is a stack 
frame (that happens to store 'this' in your case), not 'this' itself.


There are simply several 'types' of delegates. One is a delegate that 
has a class or struct (or perhaps even a union) instance as its context 
pointer. These are created by (&instance.memberFunction).

Another 'type' has a stack frame as its context pointer. These are 
created by (&nestedFunction) or { foo(); }. They should not be called 
after the function call (of the function directly containing their 
definition) in which they were created returns.


Spec reference: http://www.digitalmars.com/d/function.html#closures


More information about the Digitalmars-d-learn mailing list