Combining Delegate and Functions

BCS ao at pathlink.com
Tue Jun 30 12:27:20 PDT 2009


Reply to Daniel,

> Jarrett Billingsley wrote:
> 
>> On Tue, Jun 30, 2009 at 11:38 AM, Jesse
>> Phillips<jessekphillips at gmail.com> wrote:
>>> So looking at a post on StackOverflow about D gatchas:
>>> http://stackoverflow.com/questions/743319/why-isnt-the-d-language-pi
>>> cking-up/1059780#1059780
>>> 
>>> "functions that form closures or are attached to objects (ie.
>>> methods) are not the same as regular functions, instead they are
>>> called delegates, and you must be aware of the differences."
>>> 
>>> I seem to recall the distinction was going to be going away or
>>> minimized. Is this already done? Will it be going into D2?
>>> 
>> Nothing's changed in that area.  Theoretically the compiler could
>> implicitly convert function pointers to delegates by creating thunks.
>> It shouldn't be *that* hard to implement..
>> 
> Here's something I have in a project of mine.  I didn't come up with
> the idea, but I forget who did.
> 
> Note that this is not generalised.  I started working on a general
> one, but gave up when it proved too fiddly and difficult to correctly
> rebuild a function's argument list.
> 
> /*
> * This is utterly evil, but also REALLY cool.
> *
> * What we do here is make a dummy struct, and give it a member
> * function.  The member function has a hidden argument (this).
> *
> * We then construct a delegate of the appropriate type, set its
> * funcptr to Wrap.call and its ptr to the function pointer.
> *
> * When dg is called, it is called as (dg.funcptr(dg.ptr, ...))
> * which is the same way the (this) argument of member functions
> * is passed.
> *
> * Thus, inside the member function, we can cast the this pointer
> * back to our function pointer and call it.
> */
> struct Wrap
> {
> void call(Context a, PullParserSlice b)
> {
> return (cast(void function(Context, PullParserSlice)) this)
> (a,b);
> }
> }
> ElementBinding.Handler dg;
> Wrap wrap;
> dg.ptr = handler;
> dg.funcptr = cast(typeof(dg.funcptr)) &wrap.call;

here's a general version that should work but dosn't:

struct Wraper(F)
{
    static if(is(F Fn == Fn*) && is(Fn A == function) && is(Fn R == return))
    {
        static assert(is(F == R function(A)));

        union U
        {
            Wraper* w;
            F f;
        }

        R Call(A a)  /// BUG: this drops ref and out on A
        {
            static assert(is(F == R function(A)));

            U u;
            u.w = this;
            return u.f(a);
        }

        alias R delegate(A) ret;
    }
    else
        static assert(false, "Can't use "~Fn.stringof);

}

Wraper!(F).ret Wrap(F)(F f)
{
    Wraper!(F).U u;
    u.f = f;
    return &u.w.Call;
}

int foo(ref int i, out float x, char[] c)
{
    x = 3.14;
    return i += c.length;
}
import std.stdio;
void main()
{
    auto dg = Wrap(&foo);
    float f = 2.717;
    int i = 3;
    char[] c = "Hello world";

    auto j = dg(i, f, c);
    writef("i=%s, j=%s, f=%s\n", i,j,f);
}





More information about the Digitalmars-d mailing list