digitalmars.D - Function to delegate conversion
- Kirk McDonald (37/37) Jun 24 2006 Some of the functionality of C++-style pointers to member functions is
- Kirk McDonald (11/13) Jun 25 2006 Okay, that IS a bit of hyperbole. I can easily do it with wrappers:
- Kirk McDonald (30/44) Jun 26 2006 The following dirty, dirty hack /appears/ to work, at least in this
- BCS (8/38) Jun 26 2006 - void delegate() real_dg;
- Kirk McDonald (38/79) Jun 26 2006 I think you mean:
- BCS (13/41) Jun 26 2006 Actually I did mean what I said, but what I meant (and said) was wrong.
- Kirk McDonald (8/21) Jun 27 2006 Ah! Now that is appealing as it cuts the union out of the thing entirely...
Some of the functionality of C++-style pointers to member functions is lost with D's delegates. (In exchange for many advantages, don't get me wrong!) For instance, I am currently looking at how to wrap D classes and present them to Python. Parts of this look suprisingly easy. (Conversion between the Python type and the D class, for instance, is going to be much easier than I had previously feared.) But exposing a class's member functions is tricky without C++-style pointers to member functions. (Boost.Python utilizes them for this purpose.) For instance: class A { void foo() { } } void main() { A a = new A; void function() fn = &A.foo; } Without the ability to convert fn into a delegate to a.foo, implementing this class-wrapping functionality is all but impossible. The way I'd do it if I had the ability to make this conversion is something not totally unlike this: // T is the wrapped class // Fn is the member function we're wrapping template method_wrap(T, alias Fn) { extern(C) PyObject* func(PyObject* self, PyObject* args) { // Some concern needs to be had with respect to the GC, but // nevermind that. T t = *cast(T*)PyCObject_AsVoidPtr(self); // Something like this, only with a billion static ifs and more // template hooha. auto dg = delegate(t, &Fn); // Convert to a delegate dg(); return something; } } -Kirk McDonald
Jun 24 2006
Kirk McDonald wrote:Without the ability to convert fn into a delegate to a.foo, implementing this class-wrapping functionality is all but impossible.Okay, that IS a bit of hyperbole. I can easily do it with wrappers: class A { void foo() { } } void A_foo(A a) { a.foo(); } // Then wrap A_foo and pass the object as the first arg... But this imposes a bit of a burden on the user. -Kirk McDonald
Jun 25 2006
Kirk McDonald wrote:For instance: class A { void foo() { } } void main() { A a = new A; void function() fn = &A.foo; } Without the ability to convert fn into a delegate to a.foo, implementing this class-wrapping functionality is all but impossible.The following dirty, dirty hack /appears/ to work, at least in this trivial case: import std.stdio; struct DG { Object instance; void function() fn; } union U { DG fake_dg; void delegate() real_dg; } class A { void foo() { writefln("A.foo()"); } } void main() { A a = new A; void function() fn = &A.foo; U u; u.fake_dg.instance = a; u.fake_dg.fn = fn; // Call it u.real_dg(); } This can be templatized into a more general solution. However, I am worried about how this scales (for functions with more arguments, etc), and of course about the fact that it is not cross-platform /at all/. I now this subject has come up before, but I feel it is important enough to bring up again. -Kirk McDonald
Jun 26 2006
Kirk McDonald wrote:The following dirty, dirty hack /appears/ to work, at least in this trivial case: import std.stdio; struct DG { Object instance; void function() fn; } union U { DG fake_dg;- void delegate() real_dg; + void* real_dg;} class A { void foo() { writefln("A.foo()"); } } void main() { A a = new A; void function() fn = &A.foo; U u; u.fake_dg.instance = a;- u.fake_dg.fn = fn; + u.fake_dg.fn = cast(void*)fn;// Call it u.real_dg(); }That should also work and won't care about types. But it is still really, really dirty. But it's more portable that the last solution I saw, That one used ASM hacking.
Jun 26 2006
BCS wrote:Kirk McDonald wrote:I think you mean: - void function() fn; + void* fn;The following dirty, dirty hack /appears/ to work, at least in this trivial case: import std.stdio; struct DG { Object instance;But yes, that is a good idea. Templatizing real_dg, however, is going to be a royal pain in the ass, but possible. With Daniel Keep's ftype module, we can get something like: struct DG { Object instance; void* fn; } template dg_unionT(Fn) { const uint ARGS = NumberOfArgs!(Fn); alias ReturnType!(Fn) RetType; union U { DG fake_dg; static if (ARGS == 0) { RetType delegate() real_dg; } else static if (ARGS == 1) { RetType delegate(ArgType!(Fn, 1)) real_dg; } else statif if (ARGS == 2) { RetType delegate(ArgType!(Fn, 1), ArgType!(Fn, 2)) real_dg; } // and so on... } } template U(Fn) { alias dg_unionT!(Fn).U U; } void main() { A a = new A; auto fn = &A.foo; U!(typeof(fn)) u; u.fake_dg.instance = a; u.fake_dg.fn = cast(void*)fn; u.real_dg(); } Also not pretty, but it should work, insofar as this whole trick works. -Kirk McDonald} union U { DG fake_dg; void delegate() real_dg; } class A { void foo() { writefln("A.foo()"); } } void main() { A a = new A; void function() fn = &A.foo; U u; u.fake_dg.instance = a;- u.fake_dg.fn = fn; + u.fake_dg.fn = cast(void*)fn;// Call it u.real_dg(); }That should also work and won't care about types. But it is still really, really dirty. But it's more portable that the last solution I saw, That one used ASM hacking.
Jun 26 2006
Kirk McDonald wrote:BCS wrote:Actually I did mean what I said, but what I meant (and said) was wrong. [...]Kirk McDonald wrote:I think you mean: - void function() fn; + void* fn;The following dirty, dirty hack /appears/ to work, at least in this trivial case: import std.stdio; struct DG { Object instance;}But yes, that is a good idea. Templatizing real_dg, however, is going to be a royal pain in the ass, but possible. With Daniel Keep's ftype module, we can get something like:[...]Also not pretty, but it should work, insofar as this whole trick works. -Kirk McDonaldhow about <code> int function(int, float, char[], Object) fnp = getFNP(); int delegate(int, float, char[], Object) dg; DG* dgp = cast(DG*)cast(void*)&dg; dgp.fn = cast(void*)fnp; </code> It's about as type safe as ASM (a.k.a. not at all) but it should work cleanly (sorta).
Jun 26 2006
BCS wrote:how about <code> int function(int, float, char[], Object) fnp = getFNP(); int delegate(int, float, char[], Object) dg; DG* dgp = cast(DG*)cast(void*)&dg; dgp.fn = cast(void*)fnp; </code> It's about as type safe as ASM (a.k.a. not at all) but it should work cleanly (sorta).Ah! Now that is appealing as it cuts the union out of the thing entirely. I still need a template that can convert a function type into an equivalent delegate type, but that previous post of mine already outlines how that can be done. (The IsExpression can perform the reverse operation of converting a delegate type into a function type, though I don't believe I need that.) -Kirk McDonald
Jun 27 2006