www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - easily convert any method/function to a delegate

reply Daniel Korsgaard <d__s__k hotmail.com> writes:
two simple function templates that together will enable you to 
mindlessly use delegates everywhere.

Whee first post on this NG :D
.. hope you like it..

-------------------

import std.stdio;

void main()
{
	void delegate() ptr;
	
	void dg()
	{
		writefln("DELEGATE");
	}
	
	ptr = to_delegate(&dg);
	ptr();
	
	ptr = to_delegate(&fp);
	ptr();
}

void fp()
{
	writefln("FUNCTION");
}

/// two functions that will convert any
R delegate(P) to_delegate(R, P...)(R delegate(P) dg)
{
	// insanely advanced operation!
	return dg;
}

/// ditto
R delegate(P) to_delegate(R, P...)(R function(P) fp)
{
	R delegate(P) dg;
	dg.funcptr = fp;
	dg.ptr = null;
	return dg;
}

/+

	Output:
		DELEGATE
		FUNCTION

+/
Jul 18 2007
next sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Thanks! I'm already using something similar, but this should really become a
language extension (FPs implicitly converted to delegates).

Daniel Korsgaard Wrote:

 two simple function templates that together will enable you to 
 mindlessly use delegates everywhere.
 
 Whee first post on this NG :D
 .. hope you like it..
 
 -------------------
 
 import std.stdio;
 
 void main()
 {
 	void delegate() ptr;
 	
 	void dg()
 	{
 		writefln("DELEGATE");
 	}
 	
 	ptr = to_delegate(&dg);
 	ptr();
 	
 	ptr = to_delegate(&fp);
 	ptr();
 }
 
 void fp()
 {
 	writefln("FUNCTION");
 }
 
 /// two functions that will convert any
 R delegate(P) to_delegate(R, P...)(R delegate(P) dg)
 {
 	// insanely advanced operation!
 	return dg;
 }
 
 /// ditto
 R delegate(P) to_delegate(R, P...)(R function(P) fp)
 {
 	R delegate(P) dg;
 	dg.funcptr = fp;
 	dg.ptr = null;
 	return dg;
 }
 
 /+
 
 	Output:
 		DELEGATE
 		FUNCTION
 
 +/

Jul 18 2007
prev sibling parent reply BCS <BCS pathlink.com> writes:
Daniel Korsgaard wrote:
 two simple function templates that together will enable you to 
 mindlessly use delegates everywhere.
 
 Whee first post on this NG :D
 .. hope you like it..
 
 -------------------

 /// two functions that will convert any
 R delegate(P) to_delegate(R, P...)(R delegate(P) dg)
 {
     // insanely advanced operation!
     return dg;
 }
 
 /// ditto
 R delegate(P) to_delegate(R, P...)(R function(P) fp)
 {
     R delegate(P) dg;
     dg.funcptr = fp;
     dg.ptr = null;
     return dg;
 }

IIRC that doesn't (quite) work because some functions pass an arg in the same place as methods pass "this" However IIRC you /can/ pass the function pointer as the delegate ptr and then have the delegate code convert it back to the correct type and call it. R delegate(P) to_delegate(R, P...)(R function(P) fp) { auto dg = delegate R(P p) {return (cast(R function(P))(cast(void*)this))(p);} dg.ptr = cast(void*)fp; return dg; }
Jul 18 2007
parent reply Daniel Korsgaard <d__s__k hotmail.com> writes:
BCS wrote:
 Daniel Korsgaard wrote:
 two simple function templates that together will enable you to 
 mindlessly use delegates everywhere.

 Whee first post on this NG :D
 .. hope you like it..

 -------------------

 /// two functions that will convert any
 R delegate(P) to_delegate(R, P...)(R delegate(P) dg)
 {
     // insanely advanced operation!
     return dg;
 }

 /// ditto
 R delegate(P) to_delegate(R, P...)(R function(P) fp)
 {
     R delegate(P) dg;
     dg.funcptr = fp;
     dg.ptr = null;
     return dg;
 }

IIRC that doesn't (quite) work because some functions pass an arg in the same place as methods pass "this"

Bummer :(
 
 However IIRC you /can/ pass the function pointer as the delegate ptr and 
 then have the delegate code convert it back to the correct type and call 
 it.

Aye ?!
 
 R delegate(P) to_delegate(R, P...)(R function(P) fp)
 {
     auto dg = delegate R(P p)
         {return (cast(R function(P))(cast(void*)this))(p);}
     dg.ptr = cast(void*)fp;
     return dg;
 }

Err.. where do you get that 'this' from? Anyways, my idea was to cut of the additional call. But if it really have to be there, this is a lot cleaner: R delegate(P) to_delegate(R, P...)(R function(P) fp) { return delegate R(P p) { return fp(p); }; } .. hope you like it..
Jul 18 2007
parent reply BCS <BCS pathlink.com> writes:
Daniel Korsgaard wrote:
 BCS wrote:
 R delegate(P) to_delegate(R, P...)(R function(P) fp)
 {
     auto dg = delegate R(P p)
         {return (cast(R function(P))(cast(void*)this))(p);}
     dg.ptr = cast(void*)fp;
     return dg;
 }

Err.. where do you get that 'this' from?

Aaahhh.... My Hat?? try this (totally bad form and all): R delegate(P) to_delegate(R, P...)(R function(P) fp) { struct S { R Go(P p) { return (cast(R function(P))(cast(void*)this))(p); } } return &(cast(S*)(cast(void*)fp)).Go; } void main() { auto dg = to_delegate(&hello); dg(5); } int hello(int i) { writef("hello world #%d\n", i); return 0; } (I actually tested this one)
 Anyways, my idea was to cut of the additional call. But if it really 
 have to be there, this is a lot cleaner:
 
 R delegate(P) to_delegate(R, P...)(R function(P) fp)
 {
     return delegate R(P p) { return fp(p); };
 }
 
 .. hope you like it..

And you walk right into the other gotcha of delegates[1], returning a delegate to a nested function or anon delegate is *really bad*. It carries a context pointer to stack space that, after the function returns, is unusable. Random results result. The same goes for keeping them around by any other means. [1] So many people miss it that there needs to be some size 24 blinking red bold notes next to a few sections of the spec about this.
Jul 18 2007
parent Daniel Korsgaard <d__s__k hotmail.com> writes:
BCS wrote:
 Daniel Korsgaard wrote:
 BCS wrote:
 R delegate(P) to_delegate(R, P...)(R function(P) fp)
 {
     auto dg = delegate R(P p)
         {return (cast(R function(P))(cast(void*)this))(p);}
     dg.ptr = cast(void*)fp;
     return dg;
 }

Err.. where do you get that 'this' from?

Aaahhh.... My Hat?? try this (totally bad form and all): R delegate(P) to_delegate(R, P...)(R function(P) fp) { struct S { R Go(P p) { return (cast(R function(P))(cast(void*)this))(p); } } return &(cast(S*)(cast(void*)fp)).Go; } void main() { auto dg = to_delegate(&hello); dg(5); } int hello(int i) { writef("hello world #%d\n", i); return 0; } (I actually tested this one)

Looks promising :)
 Anyways, my idea was to cut of the additional call. But if it really 
 have to be there, this is a lot cleaner:

 R delegate(P) to_delegate(R, P...)(R function(P) fp)
 {
     return delegate R(P p) { return fp(p); };
 }

 .. hope you like it..

And you walk right into the other gotcha of delegates[1], returning a delegate to a nested function or anon delegate is *really bad*. It carries a context pointer to stack space that, after the function returns, is unusable. Random results result. The same goes for keeping them around by any other means. [1] So many people miss it that there needs to be some size 24 blinking red bold notes next to a few sections of the spec about this.

you are soo right.. believe it or not, but i was actually on my way to correct it, as it just popped op that the delegate context could/would dissaper right after the return.. :'(
Jul 18 2007