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









Kirk McDonald <kirklin.mcdonald gmail.com> 