www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Returning a delegate, strange behaviour: D limitation?

reply Deewiant <deewiant.doesnotlike.spam gmail.com> writes:
I don't think this is a bug, just a limitation due to D's lack of lexical
closures. However, I'm still confused as to why this happens. See comments in
example code:
--
class Foo {
	void delegate() dg() {
		return () {
			// just g(): asserts (like it should)
			// just h(1): asserts
			// just i(1,1): Access Violation
			
			// both g() and h(1): doesn't assert when called from f(), otherwise Access
Violation
			// both g() and i(1,1): doesn't assert when called from f(), otherwise Access
Violation
			// both h(1) and i(1,1): Access Violation
			
			// all three: doesn't assert when called from f(), otherwise Access Violation
			
			// am I getting random behaviour due to overstepping the bounds of where
delegates can reach?
			// the context pointer shouldn't matter, it should only be using the this
pointer, right?
			
			g();
			h(1);
			i(1,1);
		};
	}
	
	void f() { dg()(); }
	
	void g()             { assert (false); }
	void h(int x)        { assert (false); }
	void i(int x, int y) { assert (false); }
}

void main() {
	Foo foo = new Foo();
	foo.f();
	// foo.dg()();
}
--
If there's a clear and legitimate reason for this not working, is it worth
filing a bug about how DMD can't detect it at compile time?

Of course, what I'm most interested in is if there's any way to get something
like this to work <g>. This bit me when trying to make a function which would
take an array, and return a delegate usable as a foreach aggregate to loop over
that array.
Dec 02 2006
parent BCS <BCS pathlink.com> writes:
Deewiant wrote:
 I don't think this is a bug, just a limitation due to D's lack of lexical
 closures. However, I'm still confused as to why this happens. See comments in
 example code:
 --

 --
 If there's a clear and legitimate reason for this not working, is it worth
 filing a bug about how DMD can't detect it at compile time?
 
 Of course, what I'm most interested in is if there's any way to get something
 like this to work <g>. This bit me when trying to make a function which would
 take an array, and return a delegate usable as a foreach aggregate to loop over
 that array.

I'd have to dig around a bit more to be sure but I think it amounts to the delegate that is returned includes a pointer to the stack frame of the function in which it is declared. After that function returns, this is an invalid pointer, so things go wonky. The solution would be to do something like this: class Foo { void delegate() dg() { struct R{ Foo from; dg() { from.g(); from.h(1); from.i(1,1); } } auto ret = new R; ret.from = this; return &ret.dg; } } I have ended up needing to do this often enough to wish for something like this: class Foo { void delegate() dg() { return this.() { // use the provided pointer as context from.g(); from.h(1); from.i(1,1); } } } another version that just came to mind would use with class Foo { void delegate() dg() { return delegate() with(this){// use the provided pointer as context from.g(); from.h(1); from.i(1,1); } } }
Dec 04 2006