www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Treat a normal function as variadic?

reply Robin Allen <r.a3 ntlworld.com> writes:
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
next sibling parent Don Clugston <dac nospam.com.au> writes:
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
prev sibling parent reply Jarrett Billingsley <kb3ctd2 yahoo.com> writes:
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
parent reply Jarrett Billingsley <kb3ctd2 yahoo.com> writes:
Jarrett Billingsley Wrote:

 ScriptHost.registerFunction(&WrapFunc(foo));

Oops, should be &WrapFunc!(foo).
May 30 2007
parent reply Robin Allen <r.a3 ntlworld.com> writes:
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
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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
parent Robin Allen <r.a3 ntlworld.com> writes:
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.
May 30 2007