www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - implicitly convert function pointers to delegates

reply Moritz Warning <moritzwarning web.de> writes:
Hi,

some people discovered that functions can be wrapped into delegates 
without allocation.

Here is one out of several similar solutions:

R delegate(T) toDg(R, T...)(R function(T) fp) {
    struct dg {
        R opCall(T t) {
            return (cast(R function(T)) this) (t);
        }
    }
    R delegate(T) t;
    t.ptr = fp;
    t.funcptr = &dg.opCall;
    return t;
}

I would like to ask if we can get this into the language?
It would make working with delegates and function pointers much more 
easier when function pointers implicitly convert to delegates when they 
"have to".
Oct 26 2008
next sibling parent reply KennyTM~ <kennytm gmail.com> writes:
Moritz Warning wrote:
 Hi,
 
 some people discovered that functions can be wrapped into delegates 
 without allocation.
 
 Here is one out of several similar solutions:
 
 R delegate(T) toDg(R, T...)(R function(T) fp) {
     struct dg {
         R opCall(T t) {
             return (cast(R function(T)) this) (t);
         }
     }
     R delegate(T) t;
     t.ptr = fp;
     t.funcptr = &dg.opCall;
     return t;
 }
 
 I would like to ask if we can get this into the language?
 It would make working with delegates and function pointers much more 
 easier when function pointers implicitly convert to delegates when they 
 "have to".

vote++ for implicit conversion. An FP can be *safely* converted to any DGs. BTW, alias float delegate (in float) DG; float area (in float radius) { float r2 = radius * radius; return 3.1415926535 * radius; } DG x; x.ptr = null; x.funcptr = &area; // writefln(typeof(x.funcptr).stringof); // ensure it's an FP not DG. writefln(x(10)); // writes 314.159 without any error. Why this simpler solution is not used? The function pointer can't touch the frame pointer anyway (an FP cannot access stuff outside its scope).
Oct 26 2008
parent reply "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Sun, Oct 26, 2008 at 2:11 PM, KennyTM~ <kennytm gmail.com> wrote:
 Moritz Warning wrote:
 Hi,

 some people discovered that functions can be wrapped into delegates
 without allocation.

 Here is one out of several similar solutions:

 R delegate(T) toDg(R, T...)(R function(T) fp) {
    struct dg {
        R opCall(T t) {
            return (cast(R function(T)) this) (t);
        }
    }
    R delegate(T) t;
    t.ptr = fp;
    t.funcptr = &dg.opCall;
    return t;
 }

 I would like to ask if we can get this into the language?
 It would make working with delegates and function pointers much more
 easier when function pointers implicitly convert to delegates when they
 "have to".

vote++ for implicit conversion. An FP can be *safely* converted to any DGs. BTW, alias float delegate (in float) DG; float area (in float radius) { float r2 = radius * radius; return 3.1415926535 * radius; } DG x; x.ptr = null; x.funcptr = &area; // writefln(typeof(x.funcptr).stringof); // ensure it's an FP not DG. writefln(x(10)); // writes 314.159 without any error. Why this simpler solution is not used? The function pointer can't touch the frame pointer anyway (an FP cannot access stuff outside its scope).

The calling conventions for functions and delegates is different. This method does not work in the general case.
Oct 26 2008
parent reply KennyTM~ <kennytm gmail.com> writes:
Jarrett Billingsley wrote:
 On Sun, Oct 26, 2008 at 2:11 PM, KennyTM~ <kennytm gmail.com> wrote:
 Moritz Warning wrote:
 Hi,

 some people discovered that functions can be wrapped into delegates
 without allocation.

 Here is one out of several similar solutions:

 R delegate(T) toDg(R, T...)(R function(T) fp) {
    struct dg {
        R opCall(T t) {
            return (cast(R function(T)) this) (t);
        }
    }
    R delegate(T) t;
    t.ptr = fp;
    t.funcptr = &dg.opCall;
    return t;
 }

 I would like to ask if we can get this into the language?
 It would make working with delegates and function pointers much more
 easier when function pointers implicitly convert to delegates when they
 "have to".

BTW, alias float delegate (in float) DG; float area (in float radius) { float r2 = radius * radius; return 3.1415926535 * radius; } DG x; x.ptr = null; x.funcptr = &area; // writefln(typeof(x.funcptr).stringof); // ensure it's an FP not DG. writefln(x(10)); // writes 314.159 without any error. Why this simpler solution is not used? The function pointer can't touch the frame pointer anyway (an FP cannot access stuff outside its scope).

The calling conventions for functions and delegates is different. This method does not work in the general case.

I see. And indeed it does not work if I change float to int -- the arguments are shifted by 4 bytes to the left. (How come float works??)
Oct 26 2008
next sibling parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
KennyTM~ wrote:
 Jarrett Billingsley wrote:
 On Sun, Oct 26, 2008 at 2:11 PM, KennyTM~ <kennytm gmail.com> wrote:
 BTW,

  alias float delegate (in float) DG;

  float area (in float radius) {
        float r2 = radius * radius;
        return 3.1415926535 * radius;
  }

  DG x;
  x.ptr = null;
  x.funcptr = &area;
  // writefln(typeof(x.funcptr).stringof); // ensure it's an FP not DG.
  writefln(x(10)); // writes 314.159 without any error.


 Why this simpler solution is not used? The function pointer can't 
 touch the
 frame pointer anyway (an FP cannot access stuff outside its scope).

The calling conventions for functions and delegates is different. This method does not work in the general case.

I see. And indeed it does not work if I change float to int -- the arguments are shifted by 4 bytes to the left. (How come float works??)

Floats are passed differently. For instance, DMD will put the first argument into EAX if it's an int or pointer (including x.ptr in your code), while it passes floats on the stack. My x86-64 GDC passes a float in a floating-point register, while ints and pointers go into general-purpose registers (until it runs out of appropriate registers for that function call, anyway). So on both compilers floats will "work" because they're not moved elsewhere by an extra pointer at the front of the parameter list (which is essentially what happens when you call a function through a delegate's function pointer) while passing in an extra null means the first int an unsuspecting function reads is 0.
Oct 26 2008
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
KennyTM~ wrote:
 (How come float works??)

Because floats are not passed in EAX, they are passed on the stack.
Oct 26 2008
prev sibling parent reply downs <default_357-line yahoo.de> writes:
When asked to convert a function pointer to a delegate, the compiler could
create a small stub that converts from delegate calling convention to FP
calling convention, then put that stub in .funcptr and the FP in .ptr.
Oct 26 2008
next sibling parent reply "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Sun, Oct 26, 2008 at 11:39 PM, downs <default_357-line yahoo.de> wrote:
 When asked to convert a function pointer to a delegate, the compiler could
create a small stub that converts from delegate calling convention to FP
calling convention, then put that stub in .funcptr and the FP in .ptr.

Which is precisely what I suggested here: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=78727
Oct 26 2008
parent downs <default_357-line yahoo.de> writes:
Jarrett Billingsley wrote:
 On Sun, Oct 26, 2008 at 11:39 PM, downs <default_357-line yahoo.de> wrote:
 When asked to convert a function pointer to a delegate, the compiler could
create a small stub that converts from delegate calling convention to FP
calling convention, then put that stub in .funcptr and the FP in .ptr.

Which is precisely what I suggested here: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=78727

Sorry :) I wasn't aware of that.
Oct 27 2008
prev sibling parent ore-sama <spam here.lot> writes:
downs Wrote:

 When asked to convert a function pointer to a delegate, the compiler could
create a small stub that converts from delegate calling convention to FP
calling convention, then put that stub in .funcptr and the FP in .ptr.

Interestingly, on x86-32 this stub can be generated only once and placed before function prologue (and exported): Delegate stub: pop eax Function prologue: push ebp mov ebp, esp if last parameter is not stored in eax, their calling conventions are compatible and stub is empty :)
Oct 27 2008