Thread overview
Storing templates
Mar 09, 2007
Simen
Mar 09, 2007
BCS
Mar 09, 2007
Bill Baxter
Mar 12, 2007
Simen
March 09, 2007
Hi.

I'm new to D, and I'm having a little problems using templates for my parser project...

I thought that I could store the functions in a map ala Function[char[]] so I can reference them as functions["TestFunc"], but I don't know how I can store the templates in any sort of list since they have different parameters/return values.
I know I can store them as void pointers, but then I need to cast them to the right type before I can use them. Then I have to have a switch statement or something to be able to cast it to the correct type based on the function name.

I also looked at std.box, and even if it would allow me to store all these functions in a list, I still need to know what object is stored to unbox it.

The important thing is that I can easily reference the functions by name and get the return value (the script is dynamically typed so no return types there). I also have to use Phobos (as my parser is written in Enki which is Phobos only).

Any pointers on how I can solve this? I'm sure this is not the best way to do this, and I'm always open for change. Perhaps I have taken the wrong approach here?


import std.stdio;

class Function(R, P...)
{
	R function(P) fp;
	public this(R function(P) fp)
	{
		this.fp = fp;
	}
}


Function!(R, P) addFunc(R, P...)(R function(P) fp)
{
	writefln("R:", typeid(R));
	writefln("P:", typeid(P));
	return new Function!(R, P)(fp);
}


int add(int a, int b)
{
	return a+b;
}


double addmore(double a, double b, double c)
{
	return a+b+c;
}


void main()
{
	auto func = addFunc(&add);
	writefln( typeid(typeof(func)) );
	writefln("add(3, 4): ", func.fp(3, 4) );
	writefln();

	auto func2 = addFunc(&addmore);
	writefln( typeid(typeof(func2)) );
	writefln("addmore(3, 4, 5): ", func2.fp(3, 4, 5) );
	writefln();
}



OUTPUT
======
R:int
P:(int,int)
dtest.Function!(int,int,int).Function
add(3, 4): 7

R:double
P:(double,double,double)
dtest.Function!(double,double,double,double).Function
addmore(3, 4, 5): 12
March 09, 2007
Simen wrote:
> Hi.
> 
> I'm new to D, and I'm having a little problems using templates for my parser project...
> 
> I thought that I could store the functions in a map ala Function[char[]] so I can reference them as functions["TestFunc"], but I don't know how I can store the templates in any sort of list since they have different parameters/return values.
> I know I can store them as void pointers, but then I need to cast them to the right type before I can use them. Then I have to have a switch statement or something to be able to cast it to the correct type based on the function name.
> 

You might try a tuple, but that will only work if it is totally const: list never changes at run time, all indexing is const.

template Tuple!(V...) { alias V Tuple;}

alias Tuple!(Fn!(int), Fn!(float) /* etc */ ) fnList ;

int i;
fnList[0](i);

float f;
fnList[1](f);
March 09, 2007
Simen wrote:
> Hi.
> 
> I'm new to D, and I'm having a little problems using templates for my parser project...
> 
> I thought that I could store the functions in a map ala Function[char[]] so I can reference them as functions["TestFunc"], but I don't know how I can store the templates in any sort of list since they have different parameters/return values.
> I know I can store them as void pointers, but then I need to cast them to the right type before I can use them. Then I have to have a switch statement or something to be able to cast it to the correct type based on the function name.
> 
> I also looked at std.box, and even if it would allow me to store all these functions in a list, I still need to know what object is stored to unbox it.
> 
> The important thing is that I can easily reference the functions by name and get the return value (the script is dynamically typed so no return types there). I also have to use Phobos (as my parser is written in Enki which is Phobos only).
> 
> Any pointers on how I can solve this? I'm sure this is not the best way to do this, and I'm always open for change. Perhaps I have taken the wrong approach here?

So basically you want to put these functions in a big map and then later be able to query what their actual parameters and types are?

How are you going to supply the necessary arguments in the end?

You may be able to wrap the functions in a templated wrapper class with generic "call(...)" method implemented as a common base class/interface  , and some kind of type info retrieval mechanism. Something like this:

 import std.traits;
 interface Callable {
     void call(...);
     TypeInfo argtypes();
 }
 class FuncWrapper(alias Func) : Callable
 {
     alias ParameterTypeTuple!(Func) ArgTup;
     alias ReturnType!(Func) RetT;
     override void call(...) {
        ArgTup args;
        // check to make sure that all _argument's are
        // of the type expected by ArgTup, and copy args
        // one by one to args[i].  This is a little tricky...
        Func(args);
     }
     override TypeInfo argtypes() { return typeid(typeof(Func)); }
 }

But that introduces a fair amount of calling overhead.  And it won't work 100% if you start throwing in inout parameters.  I don't think TypeInfo really contains everything you need to know about Func's type either so you'll probably have to roll your own mechanism to return info about the args and return type.

For the return value you'll probably have to make the return value be an out parameter of call().

--bb
March 12, 2007
Bill Baxter Wrote:

> Simen wrote:
> > Any pointers on how I can solve this? I'm sure this is not the best way to do this, and I'm always open for change. Perhaps I have taken the wrong approach here?
> 
> So basically you want to put these functions in a big map and then later be able to query what their actual parameters and types are?
> 
> How are you going to supply the necessary arguments in the end?
> 
> You may be able to wrap the functions in a templated wrapper class with
> generic "call(...)" method implemented as a common base class/interface
>   , and some kind of type info retrieval mechanism. Something like this:
> 
>   import std.traits;
>   interface Callable {
>       void call(...);
>       TypeInfo argtypes();
>   }
>   class FuncWrapper(alias Func) : Callable
>   {
>       alias ParameterTypeTuple!(Func) ArgTup;
>       alias ReturnType!(Func) RetT;
>       override void call(...) {
>          ArgTup args;
>          // check to make sure that all _argument's are
>          // of the type expected by ArgTup, and copy args
>          // one by one to args[i].  This is a little tricky...
>          Func(args);
>       }
>       override TypeInfo argtypes() { return typeid(typeof(Func)); }
>   }
> 
> But that introduces a fair amount of calling overhead.  And it won't work 100% if you start throwing in inout parameters.  I don't think TypeInfo really contains everything you need to know about Func's type either so you'll probably have to roll your own mechanism to return info about the args and return type.
> 
> For the return value you'll probably have to make the return value be an out parameter of call().
> 
> --bb


Thanks a lot for the reply. I actually don't need anything this fancy as I already know that all the parameters will have the correct type, but you at least set me off in another direction than the black hole I was digging for myself.

I looked at MiniD by Jarrett Billingsley and used ideas from there.
I now have a general data type, and all my functions return this datatype and takes a list of these as parameters:

MyDataType MyFunc(MyDataType[] params)
{
    auto param1 = params[0].asDataType1;
    auto param2 = params[1].asDataType2;
    MyDataType param3 = param1 + param2;
    return param3;
}

I store these functions in a small struct that also has the return value so I can look this up:

struct Function
{
    MyDataType.Type returnType;
    MyDataType function(MyDataType[] params) func;
}

Then I have my list of functions as Function[char[]] functions. I still guess this isn't the best way, but it at least solves my problem.

Again thanks for the reply.

-Simen