Thread overview
Treat a normal function as variadic?
May 30, 2007
Robin Allen
May 30, 2007
Don Clugston
May 30, 2007
Robin Allen
May 30, 2007
Robin Allen
May 30, 2007
void f0()    {}
void f1(...) {}
void main()
{
	auto pf0 = &f0;
	auto pf1 = &f1;

	writefln(typeid(typeof(pf0)));
	writefln(typeid(typeof(pf1)));
}


The above program shows pf0 and pf1 to have the same type, 'void()*'. (Which, incidentally, isn't a type. Shouldn't it be 'void(*)()'?)

The thing is, I can call pf1(64), but not pf0(64) (wrong number of arguments), even though pf0 and pf1 should behave identically, having the same type.

Basically, I need a way to treat a non-variadic function as if it were variadic. I'm asking because I'm writing a scripting language, and I want to make normal D functions callable from the script, where the number of arguments given isn't known at compile time.
May 30, 2007
Robin Allen wrote:
> void f0()    {}
> void f1(...) {}
> void main()
> {
>     auto pf0 = &f0;
>     auto pf1 = &f1;
> 
>     writefln(typeid(typeof(pf0)));
>     writefln(typeid(typeof(pf1)));
> }
> 
> 
> The above program shows pf0 and pf1 to have the same type, 'void()*'. (Which, incidentally, isn't a type. Shouldn't it be 'void(*)()'?)

Should be 'void function()' and 'void function(...)'
> 
> The thing is, I can call pf1(64), but not pf0(64) (wrong number of arguments), even though pf0 and pf1 should behave identically, having the same type.

They don't have the same type. typeid is telling lies.
Try writefln(pf0.mangleof, pf1.mangleof); and see if the two types are really the same.

> Basically, I need a way to treat a non-variadic function as if it were variadic. I'm asking because I'm writing a scripting language, and I want to make normal D functions callable from the script, where the number of arguments given isn't known at compile time.

Not an easy problem.
May 30, 2007
Robin Allen Wrote:

> 
> Basically, I need a way to treat a non-variadic function as if it were variadic. I'm asking because I'm writing a scripting language, and I want to make normal D functions callable from the script, where the number of arguments given isn't known at compile time.

This is probably a bad idea.  If your scripting language doesn't pass enough arguments, or passes too many arguments, things can go horribly awry.  Furthermore, the calling conventions for non-variadic and variadic functions are completely different: see the calling conventions section in http://www.digitalmars.com/d/abi.html.  And to top it off, anything you do with this will be grossly non-portable.

What would be a lot safer, more portable, and probably easier to implement would be an automatically-generated (using templates) shim function which would convert the scripting language params into native params and call the function.  Something like this:

import std.traits;

template WrapFunc(alias func)
{
	void WrapFunc(ScriptObj[] params, ScriptObj retVal)
	{
		alias ParameterTypeTuple!(func) Args;

		Args args;

		if(params.length != args.length)
			throw new Exception("Function " ~ func.stringof ~ " called with incorrect number of parameters");

		foreach(i, arg; args)
			args[i] = params[i].convertTo!(typeof(args[i]));

		static if(is(ReturnType!(func) == void))
		{
			func(args);
			retVal.setNothing();
		}
		else
		{
			ReturnType!(func) ret = func(args);
			retVal.convertFrom!(typeof(ret))(ret);
		}
	}
}

int foo(int x, char[] y)
{
	writefln("foo: ", x, ", ", y);
}

...

ScriptHost.registerFunction(&WrapFunc(foo));


Designing your ScriptObj struct/class to be templated makes the whole process much easier as well.
May 30, 2007
Jarrett Billingsley Wrote:

> ScriptHost.registerFunction(&WrapFunc(foo));

Oops, should be &WrapFunc!(foo).
May 30, 2007
Thanks, this is how I had been trying to do it before giving up and trying it the hacky way.

By the looks of your code, I almost had it, too, I just assumed that this bit would be impossible:

args[i] = params[i].convertTo!(typeof(args[i]));

because args is a tuple and the docs say the "number and contents of tuple elements are fixed at compile time". Is that wrong?
May 30, 2007
"Robin Allen" <r.a3@ntlworld.com> wrote in message news:f3k9n0$45g$1@digitalmars.com...
>
> Thanks, this is how I had been trying to do it before giving up and trying it the hacky way.
>
> By the looks of your code, I almost had it, too, I just assumed that this bit would be impossible:
>
> args[i] = params[i].convertTo!(typeof(args[i]));
>
> because args is a tuple and the docs say the "number and contents of tuple elements are fixed at compile time". Is that wrong?

What I've done in my example is declare a variable tuple by doing Args args;.  So Args is a tuple of types, and args is a tuple of variables whose types are those of Args.  Because args is a tuple of variables, I can modify their values.  I guess it would be a "symbol tuple."  So if you want to get really technical, args is a tuple which refers to some variables -- you can't change the contents of args, i.e. you can't change what symbols it refers to, but you can change the values of those symbols.

Or something like that.  I'm not really, entirely sure :)


May 30, 2007
Jarrett Billingsley wrote:
> "Robin Allen" <r.a3@ntlworld.com> wrote in message news:f3k9n0$45g$1@digitalmars.com...
>> Thanks, this is how I had been trying to do it before giving up and trying it the hacky way.
>>
>> By the looks of your code, I almost had it, too, I just assumed that this bit would be impossible:
>>
>> args[i] = params[i].convertTo!(typeof(args[i]));
>>
>> because args is a tuple and the docs say the "number and contents of tuple elements are fixed at compile time". Is that wrong?
> 
> What I've done in my example is declare a variable tuple by doing Args args;.  So Args is a tuple of types, and args is a tuple of variables whose types are those of Args.  Because args is a tuple of variables, I can modify their values.  I guess it would be a "symbol tuple."  So if you want to get really technical, args is a tuple which refers to some variables -- you can't change the contents of args, i.e. you can't change what symbols it refers to, but you can change the values of those symbols.
> 
> Or something like that.  I'm not really, entirely sure :) 
> 
> 

Thanks for the explanation! I never twigged that type tuples were actual types that you could declare things with.