www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - anonymous delegates in objects. bug?

reply "Ilya Zaitseff" <sark7 mail333.com> writes:
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?
Mar 08 2005
parent reply xs0 <xs0 xs0.com> writes:
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
Mar 08 2005
parent reply "Ilya Zaitseff" <sark7 mail333.com> writes:
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?
Mar 08 2005
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
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; }
Mar 09 2005
parent "Ilya Zaitseff" <sark7 mail333.com> writes:
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.
Mar 10 2005