www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Cannot use function as foreach aggregate.

reply Daniel Keep <daniel.keep.lists gmail.com> writes:
So, I've just discovered that you can't use function pointers as the
aggregate of a foreach.  To put it mildly: this sucks.

Basically I have a bunch of module-level functions used to iterate over
some global state private to that module.  So, two questions:

1. Is this a bug?  If it's not, why can we use delegates but not
function pointers?

2. What's the cleanest way to wrap a function pointer in a delegate?

	-- Daniel

-- 
int getRandomNumber()
{
    return 4; // chosen by fair dice roll.
              // guaranteed to be random.
}

http://xkcd.com/

v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D
i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP  http://hackerkey.com/
Apr 04 2007
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message 
news:ev07p5$17u9$1 digitalmars.com...
 So, I've just discovered that you can't use function pointers as the
 aggregate of a foreach.  To put it mildly: this sucks.

 Basically I have a bunch of module-level functions used to iterate over
 some global state private to that module.  So, two questions:

 1. Is this a bug?  If it's not, why can we use delegates but not
 function pointers?

 2. What's the cleanest way to wrap a function pointer in a delegate?

I don't know if it's the cleanest but it works well. RetType delegate(Args) ToDelegate(RetType, Args...)(RetType function(Args) func) { struct S { RetType function(Args) func; RetType callMe(Args args) { return func(args); } } S* s = new S; s.func = func; return &s.callMe; }
Apr 04 2007
next sibling parent reply BCS <BCS pathlink.com> writes:
Jarrett Billingsley wrote:
 "Daniel Keep" <daniel.keep.lists gmail.com> wrote in message 
 news:ev07p5$17u9$1 digitalmars.com...
 
So, I've just discovered that you can't use function pointers as the
aggregate of a foreach.  To put it mildly: this sucks.

Basically I have a bunch of module-level functions used to iterate over
some global state private to that module.  So, two questions:

1. Is this a bug?  If it's not, why can we use delegates but not
function pointers?

2. What's the cleanest way to wrap a function pointer in a delegate?

I don't know if it's the cleanest but it works well.

I can't help but wonder if this works. template ToDelegate(RetType, RetType function(Args) func, Args...) { struct S { static S s RetType callMe(Args args) { return func(args); } } alias &S.s.callMe ToDelegate; }
Apr 04 2007
next sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
BCS wrote:
  > I can't help but wonder if this works.
 
 template ToDelegate(RetType, RetType function(Args) func, Args...)
 {
     struct S
     {
         static S s
         RetType callMe(Args args)
         {
             return func(args);
         }
     }
     alias &S.s.callMe ToDelegate;
 }

Perhaps it could be simplified to this: ReturnType!(typeof(func)) delegate (A) toDelegate(alias func, A = ParameterTypeTuple!(typeof(func)) )() { return ( A args) { return func(args); } ; } But it seems there is a bug with type tuples in delegate literals, which also affects your example. This can be made to work though with string mixins, expanding the tuples to a parameter list.
Apr 04 2007
prev sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"BCS" <BCS pathlink.com> wrote in message 
news:ev0i44$2io$5 digitalmars.com...
 Jarrett Billingsley wrote:

 I can't help but wonder if this works.

 template ToDelegate(RetType, RetType function(Args) func, Args...)
 {
     struct S
     {
         static S s
         RetType callMe(Args args)
         {
             return func(args);
         }
     }
     alias &S.s.callMe ToDelegate;
 }

Not quite.. you can't alias addresses, and I don't think you can pass function pointers as template arguments (though I might be wrong). Though using your idea of a single static instance of the struct, my function can then become: RetType delegate(Args) ToDelegate(RetType, Args...)(RetType function(Args) func) { struct S { static S s; static RetType function(Args) func; RetType callMe(Args args) { return func(args); } } S.func = func; return &S.s.callMe; } Which is pretty sweet, as it no longer requires a heap allocation with each call.
Apr 04 2007
parent reply BCS <BCS pathlink.com> writes:
Jarrett Billingsley wrote:
 
 Not quite.. you can't alias addresses, and I don't think you can pass 
 function pointers as template arguments (though I might be wrong).
 
 Though using your idea of a single static instance of the struct, my 
 function can then become:
 
 RetType delegate(Args) ToDelegate(RetType, Args...)(RetType function(Args) 
 func)
 {
     struct S
     {
         static S s;
         static RetType function(Args) func;
 
         RetType callMe(Args args)
         {
             return func(args);
         }
     }
 
     S.func = func;
     return &S.s.callMe;
 }
 
 Which is pretty sweet, as it no longer requires a heap allocation with each 
 call. 
 
 

I don't think that will work. It will only allow one delegate per function type. int foo(int i){return 1;} int bar(int i){return 2;} auto a = ToDelegate!(int, int)(foo); auto b = ToDelegate!(int, int)(bar); // stomps on a; a(1); // should return 2 when 1 is expected also it occurs to me that there is no reason that the addressOf is needed. If functions as args works (I think it does) then this should work: template ToDelegate(RetType, RetType function(Args) func, Args...) { struct S { static S s RetType callMe(Args args) { return func(args); } } alias S.s.callMe ToDelegate; } if that doesn't work than this might: template ToDelegate(RetType, alias func, Args...) but it might have problem with overloaded functions.
Apr 05 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"BCS" <BCS pathlink.com> wrote in message 
news:ev379f$1ccm$1 digitalmars.com...
 I don't think that will work. It will only allow one delegate per function 
 type.

Yeah, you're right; I forgot that I didn't use an alias template parameter so it would be based on signature, not name.
 also it occurs to me that there is no reason that the addressOf is needed. 
 If functions as args works (I think it does) then this should work:

 template ToDelegate(RetType, RetType function(Args) func, Args...)
 {
     struct S
     {
         static S s
         RetType callMe(Args args)
         {
             return func(args);
         }
     }
     alias S.s.callMe ToDelegate;
 }

You can't alias expressions. It has to be a function: template ToDelegate(alias func) { ReturnType!(func) delegate(ParameterTypeTuple!(func)) ToDelegate() { struct S { static S s; ReturnType!(func) callMe(ParameterTypeTuple!(func) args) { return func(args); } } return &S.s.callMe; } } ... int foo(int i){return 1;} int bar(int i){return 2;} ... auto a = ToDelegate!(foo); auto b = ToDelegate!(bar); writefln(a(1)); writefln(a(2));
Apr 05 2007
parent reply BCS <BCS pathlink.com> writes:
Jarrett Billingsley wrote:
 
 You can't alias expressions.  It has to be a function:
 
 template ToDelegate(alias func)
 {
     ReturnType!(func) delegate(ParameterTypeTuple!(func)) ToDelegate()
     {
         struct S
         {
             static S s;
             ReturnType!(func) callMe(ParameterTypeTuple!(func) args)
             {
                 return func(args);
             }
         }
 
         return &S.s.callMe;
     }
 }

Of course this all only works for statically known functions. If that isn't the case then the original solution is needed. OTOH this might work template ToDelegate(alias func) { ReturnType!(func) delegate(ParameterTypeTuple!(func)) ToDelegate() { struct S { ReturnType!(func) callMe(ParameterTypeTuple!(func) args) { return(cast(typeof(func))cast(void*)this)(args); } } return &((cast(S*)cast(void*)&func).callMe); } } I'd have to play with it but the same thing could be done for a dynamic pointer just with a few things moved around. Ohh, I'd so fire anyone who tried to get me to pay them for writing that.
Apr 05 2007
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"BCS" <BCS pathlink.com> wrote in message 
news:ev45id$94v$1 digitalmars.com...
 Jarrett Billingsley wrote:

 Of course this all only works for statically known functions. If that 
 isn't the case then the original solution is needed.

 OTOH this might work

 template ToDelegate(alias func)
 {
  ReturnType!(func) delegate(ParameterTypeTuple!(func)) ToDelegate()
  {
   struct S
   {
    ReturnType!(func) callMe(ParameterTypeTuple!(func) args)
    {
     return(cast(typeof(func))cast(void*)this)(args);
    }
   }
   return &((cast(S*)cast(void*)&func).callMe);
  }
 }

 I'd have to play with it but the same thing could be done for a dynamic 
 pointer just with a few things moved around.


 Ohh, I'd so fire anyone who tried to get me to pay them for writing that.

Error: can't convert from void* to a function pointer. Oh well.
Apr 05 2007
parent BCS <BCS pathlink.com> writes:
Jarrett Billingsley wrote:
 "BCS" <BCS pathlink.com> wrote in message 
 news:ev45id$94v$1 digitalmars.com...
 
Jarrett Billingsley wrote:

Of course this all only works for statically known functions. If that 
isn't the case then the original solution is needed.

OTOH this might work

template ToDelegate(alias func)
{
 ReturnType!(func) delegate(ParameterTypeTuple!(func)) ToDelegate()
 {
  struct S
  {
   ReturnType!(func) callMe(ParameterTypeTuple!(func) args)
   {
    return(cast(typeof(func))cast(void*)this)(args);
   }
  }
  return &((cast(S*)cast(void*)&func).callMe);
 }
}

I'd have to play with it but the same thing could be done for a dynamic 
pointer just with a few things moved around.


Ohh, I'd so fire anyone who tried to get me to pay them for writing that.

Error: can't convert from void* to a function pointer. Oh well.

OK, I've tested this one on 0.177 (Yes, I need to update this system :-b) R delegate(Args) ToDelegate(R, Args...)(R function(Args) func) { struct S { void callMe(Args args) { return (cast(R function(Args))cast(void*)this)(args); } } return &((cast(S*)cast(void*)func).callMe); }
Apr 06 2007
prev sibling parent Russell Lewis <webmaster villagersonline.com> writes:
Jarrett Billingsley wrote:
 RetType delegate(Args) ToDelegate(RetType, Args...)(RetType function(Args) 
 func)
 {
     struct S
     {
         RetType function(Args) func;
 
         RetType callMe(Args args)
         {
             return func(args);
         }
     }
 
     S* s = new S;
     s.func = func;
     return &s.callMe;
 }

What you give above is the good, general solution, which allows you to save the resulting delegate, or return it from the function, or whatever. But in cases where the delegate won't be used outside of the current function, it's simpler to use a delegate literal: void myFunc() { int function(int delegate(inout Type)) myAggregateFunc = <whatever>; int delegate(int delegate(inout Type)) myAggregateDelegate = delegate int(int delegate(inout Type) dg) { return myAggregateFunc(dg); } foreach(Type myVar; myAggregateDelegate) { <body> } }
Apr 04 2007
prev sibling parent Downs <default_357-line yahoo.de> writes:
Daniel Keep wrote:

 2. What's the cleanest way to wrap a function pointer in a delegate?
 

Okay, so it's not the cleanest way, and it's not automatic either, but it's easy as heck. import std.stdio; bool test(int e, float f) { return true; } void main() { auto dg=(int e, float f) { return test(e, f); }; dg(4, 3.14159); writefln(typeid(typeof(dg))); }
Apr 05 2007