Variadic functions work slightly different in my D.NET implementation than under the native D compiler.
For functions with variable numbers of arguments, the native compiler synthesizes two parameters: _arguments and _argptr; _arguments is an array of TypeInfo objects, and _argptr is a pointer to the beginning of the variable arguments on the stack. The user is supposed to query the type information in _arguments, and do the proper pointer arithmetic to navigate the arguments. You can see some examples at http://www.digitalmars.com/d/2.0/function.html:
void printargs(int x, ...)
{
writefln("%d arguments", _arguments.length);
for (int i = 0; i < _arguments.length; i++)
{ _arguments[i].print();
if (_arguments[i] == typeid(int))
{
int j = *cast(int *)_argptr;
_argptr += int.sizeof;
writefln("\t%d", j);
}
else if (_arguments[i] == typeid(long))
{
long j = *cast(long *)_argptr;
_argptr += long.sizeof;
writefln("\t%d", j);
}
// ...
The pointer arithmetic is not verifiable in managed code. A separate array of type descriptors is not necessary in .net, because the type meta-data can be passed in with the arguments.
In D.NET, the variable arguments are passed as an array of objects. For example, for a D function with the prototype
void fun(...) the compiler outputs:
.method public void '_D23funFYv' (object[] _arguments)
I handled variadic support slightly differently from the native compiler: I dropped _argptr and provided a new helper function, _argtype, that can be used as demonstrated in this example:
void fun(...)
{
foreach(arg; _arguments)
{
if (_argtype(arg) == typeid(int))
{
int i = arg;
Console.WriteLine("int={0}".sys, i);
}
else if (_argtype(arg) == typeid(string))
{
string s = arg;
Console.WriteLine(s.sys);
}
}
}
If the type of the arguments is known, there is no need to check for the typeid:
void fun(...)
{
foreach(arg; _arguments)
{
int i = arg;
Console.WriteLine(i);
}
}
If an incorrect type is passed in, it is still okay, because the error is detected at runtime.
fun("one", "two", "three"); // int i = arg will throw
The downside of this approach is that it is not compatible with the native code. This does not affect template variadic functions, which should be perfectly portable.

0 comments:
Post a Comment