digitalmars.D - Functors
- Craig Black (51/51) Jun 28 2007 I just realized that a Functor class is much much easier to express in D...
- BCS (10/13) Jun 28 2007 if all you want to do is convert fn ptrs to delegates this works:
- Craig Black (3/12) Jun 28 2007 I didn't know this was possible. Are you sure this works? I thought the...
- BCS (8/23) Jun 28 2007 What goes on there is that the context pointer (which is supposed to be ...
- Craig Black (3/27) Jun 28 2007 Very useful hack. Thanks!
-
BCS
(28/58)
Jun 28 2007
It gets better
that 32 bits of the pointer can be used for... - Craig Black (3/62) Jun 28 2007 I'll keep that in mind evil genius.
- Kirk McDonald (7/71) Jun 28 2007 Instead of calling it "invoke", why not overload opCall?
- Craig Black (1/2) Jun 28 2007 Yes opCall would be better. Thanks.
- Nathan Allan (10/62) Jun 29 2007 Isn't the "words" part of the union assuming 32bit pointers? How about
I just realized that a Functor class is much much easier to express in D than in C++. Functors are more flexible than delegates because they can be associated with static/global functions as well as functions local to a class or struct. In essense they can be either a function or a delegate. The implementation is also pretty efficient. The implementation below does not support functions/delegates with return values, but that would be easy to accommodate. Anyway, thought it might be useful to someone. struct Functor(A...) { private: union { void function(A) fun; void delegate(A) del; int[2] words; } public: void clear() { words[0] = 0; words[1] = 0; } void opAssign(void function(A) arg) { fun = arg; words[1] = 0; } void opAssign(void delegate(A) arg) { del = arg; } void invoke(A args) { if(words[0] == 0) return; if(words[1] == 0) fun(args); else del(args); } } int main(char[][] args) { // A functor that takes no parameters Functor!() functor; static void fun() { printf("In static function.\n"); } functor = &fun; functor.invoke; struct A { public void fun() { printf("In local function.\n"); } } A a; functor = &a.fun; functor.invoke; return 0; }
Jun 28 2007
Reply to Craig,Functors are more flexible than delegates because they can be associated with static/global functions as well as functions local to a class or struct.if all you want to do is convert fn ptrs to delegates this works: |T delegate(A) Fn2Dg(T, A...)(T function(A) f) |{ | struct tmp | { | T ret(A args){ return (cast(T function(A))this)(args); } | }; | return &(cast(tmp*)f).ret; |}
Jun 28 2007
if all you want to do is convert fn ptrs to delegates this works: |T delegate(A) Fn2Dg(T, A...)(T function(A) f) |{ | struct tmp | { | T ret(A args){ return (cast(T function(A))this)(args); } | }; | return &(cast(tmp*)f).ret; |}I didn't know this was possible. Are you sure this works? I thought there were some issues with calling conventions. -Craig
Jun 28 2007
Reply to Craig,What goes on there is that the context pointer (which is supposed to be a object, struct or stack frame) is in fact a function pointer. The calling convention for delegates never actually de references the context pointer so what is is doesn't matter. In this case I convert it back to a function pointer, and then call it with the arguments I was given. All of the values in the arguments get copied and arranged correctly for the function call and everything is fine and dandy.if all you want to do is convert fn ptrs to delegates this works: |T delegate(A) Fn2Dg(T, A...)(T function(A) f) |{ | struct tmp | { | T ret(A args){ return (cast(T function(A))this)(args); } | }; | return &(cast(tmp*)f).ret; |}I didn't know this was possible. Are you sure this works? I thought there were some issues with calling conventions. -Craig
Jun 28 2007
Very useful hack. Thanks! "BCS" <ao pathlink.com> wrote in message news:ce0a3343b7368c987a5d27c1f2e news.digitalmars.com...Reply to Craig,What goes on there is that the context pointer (which is supposed to be a object, struct or stack frame) is in fact a function pointer. The calling convention for delegates never actually de references the context pointer so what is is doesn't matter. In this case I convert it back to a function pointer, and then call it with the arguments I was given. All of the values in the arguments get copied and arranged correctly for the function call and everything is fine and dandy.if all you want to do is convert fn ptrs to delegates this works: |T delegate(A) Fn2Dg(T, A...)(T function(A) f) |{ | struct tmp | { | T ret(A args){ return (cast(T function(A))this)(args); } | }; | return &(cast(tmp*)f).ret; |}I didn't know this was possible. Are you sure this works? I thought there were some issues with calling conventions. -Craig
Jun 28 2007
Reply to Craig,Very useful hack. Thanks! "BCS" <ao pathlink.com> wrote in message news:ce0a3343b7368c987a5d27c1f2e news.digitalmars.com...It gets better <g type=evil> that 32 bits of the pointer can be used for anything as long as it isn't set to null struct S { union U { S* ptr; struct { short s; byte b; char c; } } void delegate() build(short s, byte b, char c) { U u; u.s=s; u.b=b; u.c=c; return &s.ptr.go; } void go() { U u; U.ptr = this; writef("%s, %s, %s\n", u.s, u.b, u.c); } }Reply to Craig,What goes on there is that the context pointer (which is supposed to be a object, struct or stack frame) is in fact a function pointer. The calling convention for delegates never actually de references the context pointer so what is is doesn't matter. In this case I convert it back to a function pointer, and then call it with the arguments I was given. All of the values in the arguments get copied and arranged correctly for the function call and everything is fine and dandy.if all you want to do is convert fn ptrs to delegates this works: |T delegate(A) Fn2Dg(T, A...)(T function(A) f) |{ | struct tmp | { | T ret(A args){ return (cast(T function(A))this)(args); } | }; | return &(cast(tmp*)f).ret; |}I didn't know this was possible. Are you sure this works? I thought there were some issues with calling conventions. -Craig
Jun 28 2007
I'll keep that in mind evil genius. "BCS" <ao pathlink.com> wrote in message news:ce0a3343b7398c987a7d80a1836 news.digitalmars.com...Reply to Craig,Very useful hack. Thanks! "BCS" <ao pathlink.com> wrote in message news:ce0a3343b7368c987a5d27c1f2e news.digitalmars.com...It gets better <g type=evil> that 32 bits of the pointer can be used for anything as long as it isn't set to null struct S { union U { S* ptr; struct { short s; byte b; char c; } } void delegate() build(short s, byte b, char c) { U u; u.s=s; u.b=b; u.c=c; return &s.ptr.go; } void go() { U u; U.ptr = this; writef("%s, %s, %s\n", u.s, u.b, u.c); } }Reply to Craig,What goes on there is that the context pointer (which is supposed to be a object, struct or stack frame) is in fact a function pointer. The calling convention for delegates never actually de references the context pointer so what is is doesn't matter. In this case I convert it back to a function pointer, and then call it with the arguments I was given. All of the values in the arguments get copied and arranged correctly for the function call and everything is fine and dandy.if all you want to do is convert fn ptrs to delegates this works: |T delegate(A) Fn2Dg(T, A...)(T function(A) f) |{ | struct tmp | { | T ret(A args){ return (cast(T function(A))this)(args); } | }; | return &(cast(tmp*)f).ret; |}I didn't know this was possible. Are you sure this works? I thought there were some issues with calling conventions. -Craig
Jun 28 2007
Craig Black wrote:I just realized that a Functor class is much much easier to express in D than in C++. Functors are more flexible than delegates because they can be associated with static/global functions as well as functions local to a class or struct. In essense they can be either a function or a delegate. The implementation is also pretty efficient. The implementation below does not support functions/delegates with return values, but that would be easy to accommodate. Anyway, thought it might be useful to someone. struct Functor(A...) { private: union { void function(A) fun; void delegate(A) del; int[2] words; } public: void clear() { words[0] = 0; words[1] = 0; } void opAssign(void function(A) arg) { fun = arg; words[1] = 0; } void opAssign(void delegate(A) arg) { del = arg; } void invoke(A args) { if(words[0] == 0) return; if(words[1] == 0) fun(args); else del(args); } } int main(char[][] args) { // A functor that takes no parameters Functor!() functor; static void fun() { printf("In static function.\n"); } functor = &fun; functor.invoke; struct A { public void fun() { printf("In local function.\n"); } } A a; functor = &a.fun; functor.invoke; return 0; }Instead of calling it "invoke", why not overload opCall? -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org
Jun 28 2007
Instead of calling it "invoke", why not overload opCall?Yes opCall would be better. Thanks.
Jun 28 2007
Isn't the "words" part of the union assuming 32bit pointers? How about using an array of void pointers, or better yet assign both members to null before setting either of them. This is more defensive as it allows future versions of D to change the internal representations of delegates and function pointers. Best, -- Nathan Allan "Craig Black" <craigblack2 cox.net> wrote in message news:f60vdo$2fb8$1 digitalmars.com...I just realized that a Functor class is much much easier to express in D than in C++. Functors are more flexible than delegates because they can be associated with static/global functions as well as functions local to a class or struct. In essense they can be either a function or a delegate. The implementation is also pretty efficient. The implementation below does not support functions/delegates with return values, but that would be easy to accommodate. Anyway, thought it might be useful to someone. struct Functor(A...) { private: union { void function(A) fun; void delegate(A) del; int[2] words; } public: void clear() { words[0] = 0; words[1] = 0; } void opAssign(void function(A) arg) { fun = arg; words[1] = 0; } void opAssign(void delegate(A) arg) { del = arg; } void invoke(A args) { if(words[0] == 0) return; if(words[1] == 0) fun(args); else del(args); } } int main(char[][] args) { // A functor that takes no parameters Functor!() functor; static void fun() { printf("In static function.\n"); } functor = &fun; functor.invoke; struct A { public void fun() { printf("In local function.\n"); } } A a; functor = &a.fun; functor.invoke; return 0; }
Jun 29 2007