D - Thoughts on how to unify (and extend) functions and delegates
- Russ Lewis (69/69) Feb 27 2004 I am making heavy use of delegates in a D program I am currently
-
Ben Hinkle
(79/79)
Feb 28 2004
"Russ Lewis"
wrote in message - SpookyET (45/124) Mar 01 2004 Delegates and function pointers should be united in one way to point to ...
I am making heavy use of delegates in a D program I am currently writing. They are awesome! However, more than once I have found myself wishing that they could store more than just one argument. Why can't you have delegates of any size? Better yet (for the needs of my program) why can't you have delegates which have a VARIABLE number of implicit arguments? I think I know (roughly) how to do this. Stated roughly, a delegate is really just a struct. For example, this: int delegate(char a,Object b) foo; could be viewed as this struct: struct myDelegate { void *arg; int function(void*,char,Object) fptr; }; myDelegate foo; When you call the delegate foo('a',null); the compiler is basically doing this: foo.fptr(foo.arg, 'a',null); So a delegate is really just a function pointer with a single void* argment embedded into it. What if we decided to view this as a static-sized array instead? struct myDelegate { void*[1] arg; int function(void*,char,Object) fptr; }; This implies that you might have arrays of other sizes: struct myDelegate_2args { void*[2] args; int function(void*,void*,char,Object) fptr; }; In fact, a "normal" function pointer is just the trivial case, where the size of the array is 0: struct myDelegate_0args { void*[0] args; int function(char,Object) fptr; }; Finally, this conception suggests that we might be able to declare delegates with a dynamic number of arguments: struct myDelegate_dynArgs { void*[] args; int function(..., char,Object) fptr; }; In this last case, what the compiler would turn this call: myDelegate_dynArgs foo; foo('a',null); into something like this pseudocode: foreach(void *arg; foo.args) push(arg); push('a'); push(null); call(foo.fptr); So I propose the following syntaxes: <retType> function[<val>](<args...>) <retType> function[](<args...>) 'function[<val>]' would be a function with <val> stored arguments. 'function' would be syntax sugar for 'function[0]'. 'delegate' would be syntax sugar for 'function[1]'. 'function[]' declares a function pointer which has a dynamic number of stored arguments. You can implicitly cast any function[x] to function[] if the args and return values are the same. PROBLEMS: - What if one of the arguments you want to store is less than the size of a void pointer, like a char? Maybe the [] size should be in bytes rather than void pointers? - You should be able to turn a function[x] into a function[x+n] by supplying some additional stored arguments. I don't have a good, readable syntax for this yet. Any ideas?
Feb 27 2004
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:c1oiko$hs4$1 digitaldaemon.com... | I am making heavy use of delegates in a D program I am currently | writing. They are awesome! | | However, more than once I have found myself wishing that they could | store more than just one argument. Why can't you have delegates of any | size? Better yet (for the needs of my program) why can't you have | delegates which have a VARIABLE number of implicit arguments? Below is some template magic to do roughly the same thing. The calls in the user code could most likely be cleaned up but it works just fine. Another drawback compared to your proposal is that it allocates another wrapper object per implicit argument so it isn't as efficient as it could be. Also it needs to support delegates with return values. There seems to be a bug in dmd with opApply and template classes (the error message is that wrapper(8) expects a function and not WrapDG). Anyway, it's fun to play around with: // no explicit arg class WrapDG(DG,S) { S data; DG dg; this(DG dg, S data) { this.data = data; this.dg = dg; } void opApply() { dg(data); } } // one explicit arg class WrapDG(DG,S,A) { S data; DG dg; this(DG dg, S data) { this.data = data; this.dg = dg; } void opApply(A x) { dg(data,x); } } class Foo { int x; void the_callback(int p,int q) { printf("field x = %d\n",x); printf("param p = %d\n",p); printf("param q = %d\n\n",q); } } int main() { Foo t = new Foo(); t.x = 2; // wrap dg_t to get dg2_t alias void delegate(int,int) dg_t; alias void delegate(int) dg2_t; // make wrapper delegate resulting in dg alias WrapDG!(dg_t,int,int) wrapper_t; wrapper_t wrapper = new wrapper_t(&t.the_callback,4); dg2_t dg = &wrapper.opApply; // template opApply needs help // try applying it printf("calling delegate dg with arg 8\n"); dg(8); // another example: wrap the wrapper to add more implicit args WrapDG!(dg2_t,int) wrapper2 = new WrapDG!(dg2_t,int)(dg,16); void delegate() dg2 = &wrapper2.opApply; // try applying it printf("calling delegate dg2 with no args\n"); dg2(); return 0; }
Feb 28 2004
Delegates and function pointers should be united in one way to point to functions. The problem right now is that delegates can't call static methodes in a class. Also delegates can't point to more than one method and you have to use arrays. int (*pt2Function) (float, char, char); // C int (TMyClass::*pt2Member)(float, char, char); // C++ ---------------------------------------------------------------------------- import std.c.stdio; class Foobar { void printHello() { puts("Foobar.printHello(): Hello !"); } } class Foobar2 { void printHello() { puts("Foobar2.printHello(): Hello !"); } } void main ( char [] [] args ) { void delegate()[2] d; Foobar f = new Foobar(); Foobar2 f2 = new Foobar2(); d[0] = &f.printHello; d[1] = &f2.printHello; for (int i = 0; i < d.length; i++) { d[i](); } foreach (void delegate() x; d) { x(); } } On Sat, 28 Feb 2004 09:50:46 -0500, Ben Hinkle <bhinkle4 juno.com> wrote:"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message news:c1oiko$hs4$1 digitaldaemon.com... | I am making heavy use of delegates in a D program I am currently | writing. They are awesome! | | However, more than once I have found myself wishing that they could | store more than just one argument. Why can't you have delegates of any | size? Better yet (for the needs of my program) why can't you have | delegates which have a VARIABLE number of implicit arguments? Below is some template magic to do roughly the same thing. The calls in the user code could most likely be cleaned up but it works just fine. Another drawback compared to your proposal is that it allocates another wrapper object per implicit argument so it isn't as efficient as it could be. Also it needs to support delegates with return values. There seems to be a bug in dmd with opApply and template classes (the error message is that wrapper(8) expects a function and not WrapDG). Anyway, it's fun to play around with: // no explicit arg class WrapDG(DG,S) { S data; DG dg; this(DG dg, S data) { this.data = data; this.dg = dg; } void opApply() { dg(data); } } // one explicit arg class WrapDG(DG,S,A) { S data; DG dg; this(DG dg, S data) { this.data = data; this.dg = dg; } void opApply(A x) { dg(data,x); } } class Foo { int x; void the_callback(int p,int q) { printf("field x = %d\n",x); printf("param p = %d\n",p); printf("param q = %d\n\n",q); } } int main() { Foo t = new Foo(); t.x = 2; // wrap dg_t to get dg2_t alias void delegate(int,int) dg_t; alias void delegate(int) dg2_t; // make wrapper delegate resulting in dg alias WrapDG!(dg_t,int,int) wrapper_t; wrapper_t wrapper = new wrapper_t(&t.the_callback,4); dg2_t dg = &wrapper.opApply; // template opApply needs help // try applying it printf("calling delegate dg with arg 8\n"); dg(8); // another example: wrap the wrapper to add more implicit args WrapDG!(dg2_t,int) wrapper2 = new WrapDG!(dg2_t,int)(dg,16); void delegate() dg2 = &wrapper2.opApply; // try applying it printf("calling delegate dg2 with no args\n"); dg2(); return 0; }-- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Mar 01 2004