Thread overview
dynamic function call
May 24, 2010
Chris
May 24, 2010
Simen kjaeraas
May 24, 2010
Robert Clipsham
May 24, 2010
Robert Clipsham
May 25, 2010
Chris
May 24, 2010
I need to simulate a function available in PHP called

call_user_func_array()
http://us.php.net/manual/en/function.call-user-func-array.php

I am new to D and need some guidance. It looks as if I need to use delegate, but despite trying to make sense of a few examples of doing callbacks using templates, I still don't quite get it. Could someone post a newbie friendly explanation?
May 24, 2010
Chris <hammer65@gmail.com> wrote:

> I need to simulate a function available in PHP called
>
> call_user_func_array()
> http://us.php.net/manual/en/function.call-user-func-array.php
>
> I am new to D and need some guidance. It looks as if I need to use delegate, but despite trying to make
> sense of a few examples of doing callbacks using templates, I still don't quite get it. Could someone post a
> newbie friendly explanation?

In the future, please use digitalmars.D, rather than the D newsgroup,
as it is no longer in use.

As for your problem, I believe this calls for templates.

The solution might be as follows:

T call_user_func( T, U... )( T delegate( U ) dg, U args ) {
  dg( args );
}

T call_user_func( T, U... )( T function( U ) fn, U args ) {
  fn( args );
}

--
Simen
May 24, 2010
On 24/05/10 23:11, Chris wrote:
> I need to simulate a function available in PHP called
>
> call_user_func_array()
> http://us.php.net/manual/en/function.call-user-func-array.php
>
> I am new to D and need some guidance. It looks as if I need to use delegate, but despite trying to make
> sense of a few examples of doing callbacks using templates, I still don't quite get it. Could someone post a
> newbie friendly explanation?

For future reference, questions like this should be posted in digitalmars.D.learn, and general comments in digitalmars.D - this newsgroup is unused now. Moving on:

Using the first example from the page I came up with this (only rough, it can be improved):
----
import std.stdio;

void foobar(string arg, string arg2) {
        writefln("foobar got %s and %s", arg, arg2);
}

class Foo {
        void bar(string arg, string arg2) {
                writefln( "foo.bar got %s and %s", arg, arg2 );
        }
}

Rt call_user_func_array(Rt, T...)( Rt delegate(T) dg, T args) {
        return dg(args);
}

Rt call_user_func_array(Rt, T...)( Rt function(T) dg, T args) {
        return dg(args);
}


void main() {
        call_user_func_array(&foobar, "one", "two");
        auto foo = new Foo;
        call_user_func_array(&foo.bar, "three", "four");
}
----
Some notes:
 - You can get the function/method names without hard coding them, I was lazy so didn't do this
 - There are loads of other ways to do this in D depending on what you want to do

Hope this helps, let me know if you have any questions :)

Robert
May 24, 2010
On 25/05/10 00:05, Robert Clipsham wrote:
> On 24/05/10 23:11, Chris wrote: Could someone post a newbie friendly
> explanation?

I forgot to do this bit!

Let's cover one at a time:
----
Rt call_user_func_array(Rt, T...)( Rt delegate(T) dg, T args) {
        return dg(args);
}
----

This scary piece of code is syntactic sugar for the following:
----
template call_user_func_array(Rt, T...) {
	Rt call_user_func_array(Rt delegate(T) dg, T args) {
		return dg(args);
	}
}
----
This is a lot of code to get your head around if you're new to D and or template metaprogramming. You can think of the above template just like a function call, but rather than passing a list of values to it, you pass a list of types. For example:
----
template Type(T) {
	T myType;
}
Type!int myType;
myType.myType = 3;
----
Here we define a template, Type, and require one parameter which we call T. It has one member of type T called myType. We then use Type, passing the type int to it, calling it myType. We can then set its value just like anything else.

Back to the original example, you'll see we pass the template 2 types, Rt and T... . You can use T... when you want to accept an unknown number of arguments and call them all T. We then define a function using these 2 types. By using the same name as the template we can avoid having to type call_user_func_array.call_user_func_array everywhere and just use it once.

This function takes 2 arguments, the first a delegate (a function pointer with context, a method in a class instance for example) which has arguments of type(s) T, and a return type of type Rt. The second is a list of arguments to pass, of type(s) T (we don't use T... when we want to refer to T now). The function then returns whatever the delegate does, and passes the arguments.

Looking at this all together now, how do we go about calling it? The explicit syntax is this:
----
call_user_func_array!(void delegate(string, string), string string).call_user_func_array(&foo.bar, "three", "four");
----
Which... Is a bit of a monster. As I mentioned above, by using the same name for the function as the template, we can reduce that to this:
----
call_user_func_array!(void delegate(string, string), string string)(&foo.bar, "three", "four");
----
Which still isn't the greatest. Fortunately the D compiler does something called implicit function template instantiation (IFTI), which allows you to omit the types and let the compiler guess what you meant from the arguments you pass to the function. This leaves us with a much nicer looking:
----
call_user_func_array(&foo.bar, "three", "four");
----

A similar thing goes for the other template, which allows you to pass a function pointer instead of a delegate.

Hope this helps, let me know if you need anything explaining better!

Robert
May 25, 2010
This is outstanding and exactly what I was looking for. I am a PHP programmer looking to start doing some web related things in D. My apologies for posting in the wrong forum. Your explanation was very helpful thanks.