Thread overview
anonymous delegates in objects. bug?
Mar 08, 2005
Ilya Zaitseff
Mar 08, 2005
xs0
Mar 08, 2005
Ilya Zaitseff
Mar 09, 2005
Russ Lewis
Mar 10, 2005
Ilya Zaitseff
March 08, 2005
This code works:

<code>
import std.stdio;

void delegate () dg;

class A
{
	this() { dg = delegate void () { foo(); }; }
	void foo() { writefln("foo"); }
}

void main()
{
	B b = new B();
	A a = new A();

	dg(); // prints "foo"
}
</code>

But this code throws AV:

<code>
import std.stdio;

class B { void delegate () dg; }

B b;

class A
{
	this() { b.dg = delegate void () { foo(); }; }
	void foo() { writefln("foo"); }
}

void main()
{
	B b = new B();
	A a = new A();

	b.dg(); // AV here
}
</code>

Whats the difference? Is it a bug or specific D behaviour?
March 08, 2005
Ilya Zaitseff wrote:
> This code works:
> 
> <code>
> import std.stdio;
> 
> void delegate () dg;
> 
> class A
> {
>     this() { dg = delegate void () { foo(); }; }
>     void foo() { writefln("foo"); }
> }
> 
> void main()
> {
>     B b = new B();
>     A a = new A();
> 
>     dg(); // prints "foo"
> }
> </code>
> 
> But this code throws AV:
> 
> <code>
> import std.stdio;
> 
> class B { void delegate () dg; }
> 
> B b;
> 
> class A
> {
>     this() { b.dg = delegate void () { foo(); }; }
>     void foo() { writefln("foo"); }
> }
> 
> void main()
> {
>     B b = new B();
>     A a = new A();
> 
>     b.dg(); // AV here
> }
> </code>
> 
> Whats the difference? Is it a bug or specific D behaviour?

You made a mistake - A.this() sets the global b, while "B b=new B()" creates the local b.. When you execute b.dg(), it's not the global b, so it doesn't have the delegate set, hence AV.. In fact, I'd say that it's A.this() that produces AV, because the global b is null...


xs0
March 08, 2005
On Tue, 08 Mar 2005 18:07:00 +0100, xs0 <xs0@xs0.com> wrote:

> Ilya Zaitseff wrote:
>>  Whats the difference? Is it a bug or specific D behaviour?
>
> You made a mistake - A.this() sets the global b, while "B b=new B()" creates the local b.. When you execute b.dg(), it's not the global b, so it doesn't have the delegate set, hence AV.. In fact, I'd say that it's A.this() that produces AV, because the global b is null...
>
> xs0

Oops, just a stupid typo :)

Actually second code snippet is:

<code>
import std.stdio;

class B
{
  void delegate () dg;
  void run() { dg(); }
}

B b;

class A
{
  this() { b.dg = delegate void () { foo(); }; }
  void foo() { writefln("foo"); }
}

void main()
{
  b = new B();
  A a = new A();
  b.dg(); // prints "foo"
  b.run(); // AV here
}
</code>

bug, isn't it?
March 09, 2005
Ilya Zaitseff wrote:
> <code>
> import std.stdio;
> 
> class B
> {
>   void delegate () dg;
>   void run() { dg(); }
> }
> 
> B b;
> 
> class A
> {
>   this() { b.dg = delegate void () { foo(); }; }
>   void foo() { writefln("foo"); }
> }
> 
> void main()
> {
>   b = new B();
>   A a = new A();
>   b.dg(); // prints "foo"
>   b.run(); // AV here
> }
> </code>
> 
> bug, isn't it?

My guess is that the problem is that the delegate you're creating is a stack delegate, and the stack frame is no longer valid.  Remembery that the line
	foo();
in the delegate literal is really
	this.foo();
and that, since this is a stack delegate, the compiler is gettting 'this' from a function argument which was on the stack; thus, the statement really becomes
	stack_frame.this.foo();
where stack_frame is the pointer which is saved in the delegate.  This pointer is created when the delegate literal is created, and is invalid from the moment that the stack frame (the constructor) exits.

This code should work fine if you change A's constructor to this:
	this() { b.dg = &this.foo; }
March 10, 2005
On Wed, 09 Mar 2005 11:09:01 -0700, Russ Lewis <spamhole-2001-07-16@deming-os.org> wrote:

> Ilya Zaitseff wrote:
>> <code>
>> import std.stdio;
>>  class B
>> {
>>   void delegate () dg;
>>   void run() { dg(); }
>> }
>>  B b;
>>  class A
>> {
>>   this() { b.dg = delegate void () { foo(); }; }
>>   void foo() { writefln("foo"); }
>> }
>>  void main()
>> {
>>   b = new B();
>>   A a = new A();
>>   b.dg(); // prints "foo"
>>   b.run(); // AV here
>> }
>> </code>
>>  bug, isn't it?
>
> My guess is that the problem is that the delegate you're creating is a stack delegate, and the stack frame is no longer valid.  Remembery that the line
> 	foo();
> in the delegate literal is really
> 	this.foo();
> and that, since this is a stack delegate, the compiler is gettting 'this' from a function argument which was on the stack; thus, the statement really becomes
> 	stack_frame.this.foo();
> where stack_frame is the pointer which is saved in the delegate.  This pointer is created when the delegate literal is created, and is invalid from the moment that the stack frame (the constructor) exits.
>
> This code should work fine if you change A's constructor to this:
> 	this() { b.dg = &this.foo; }

I got it. Thanks.