digitalmars.D - [Suggestion] A few small improvements to variadic functions
- Stewart Gordon (70/70) Sep 29 2004 1. http://www.digitalmars.com/d/function.html#variadic
- Ben Hinkle (19/89) Sep 29 2004 I agree that first example should be removed - just show people "the rig...
- Stewart Gordon (14/35) Sep 29 2004 Except for the absurdity of effectively importing a language feature. I...
- Ben Hinkle (28/63) Sep 29 2004 writing
- Stewart Gordon (14/39) Sep 30 2004 Good question. But probably.
- pragma (6/16) Sep 30 2004 Just a thought: this is another one of D's quirks that could use some at...
1. http://www.digitalmars.com/d/function.html#variadic "To protect against the vagaries of stack layouts on different CPU architectures, use std.stdarg to access the variadic arguments: " By the looks of it, you show us how to access variadic arguments by incrementing _argptr, but then tell us that the method isn't portable and that we should use std.stdarg. Ever since I discovered stdarg.h in C I've thought it ridiculous, as it means that C isn't self-contained. If the ability to declare a variadic function is built in, so should the means of accessing the arguments. Having invented a system for variadicity that's built in and typesafe, it ought to at least be portable. My idea is to give D-linkage variadic functions one more implicit parameter, void*[] _argList, which points to each argument's data. Then the example code would become: ---------- void foo(int x, ...) { printf("%d arguments\n", _arguments.length); for (int i = 0; i < _arguments.length; i++) { _arguments[i].print(); if (_arguments[i] == typeid(int)) { int j = *cast(int*) _argList[i]; printf("\t%d\n", j); } else if (_arguments[i] == typeid(long)) { long j = *cast(long*) _argList[i]; printf("\t%lld\n", j); } else if (_arguments[i] == typeid(double)) { double d = *cast(double*) _argList[i]; printf("\t%g\n", d); } else if (_arguments[i] == typeid(FOO)) { FOO f = *cast(FOO*) _argList[i]; printf("\t%p\n", f); } else { assert(0); } } } ---------- 2. There ought to be a way of passing the arglist of one variadic function directly to another. The simple solution, probably thought of by many, would be to allow the token '...' to be passed in. Example: void writeMultiple(int count, ...) { for (int i = 0; i < count; i++) writefln(...); } Further, I suppose the '...' passed to the function shouldn't have to be the whole '...' of the callee. For example, this might just as well be valid: void printError(char[] formatStr, ...) { writefln("Error: " ~ formatStr, ...); } or equivalently void printError(...) { writefln("Error: ", ...); } or possibly even void printError(...) { writefln("The error ", ..., " has occurred"); } (Should we allow slicing of '...'? Hmm....) Stewart.
Sep 29 2004
"Stewart Gordon" <Stewart_member pathlink.com> wrote in message news:cjee0g$1034$1 digitaldaemon.com...1. http://www.digitalmars.com/d/function.html#variadic "To protect against the vagaries of stack layouts on different CPU architectures, use std.stdarg to access the variadic arguments: " By the looks of it, you show us how to access variadic arguments by incrementing _argptr, but then tell us that the method isn't portable and that we should use std.stdarg.I agree that first example should be removed - just show people "the right way" from the start.Ever since I discovered stdarg.h in C I've thought it ridiculous, as it means that C isn't self-contained. If the ability to declare a variadic function is built in, so should the means of accessing the arguments. Having invented a system for variadicity that's built in and typesafe, it ought to at least be portable. My idea is to give D-linkage variadic functions one more implicit parameter, void*[] _argList, which points to each argument's data.It would be nice but there isn't much difference to the user between writing int j = *cast(int*)_argList[i]; and int j = va_arg!(int)(_argptr); I suppose the _argList version lets you arbitrarily index the i^{th} parameter while the va_arg version only lets you access the parameters in order. It takes time to fill those pointers, though. The _arguments array can be determined at compile time so it doesn't add much overhead to the call (I don't know exactly how DMD create _arguments, though).Then the example code would become: ---------- void foo(int x, ...) { printf("%d arguments\n", _arguments.length); for (int i = 0; i < _arguments.length; i++) { _arguments[i].print(); if (_arguments[i] == typeid(int)) { int j = *cast(int*) _argList[i]; printf("\t%d\n", j); } else if (_arguments[i] == typeid(long)) { long j = *cast(long*) _argList[i]; printf("\t%lld\n", j); } else if (_arguments[i] == typeid(double)) { double d = *cast(double*) _argList[i]; printf("\t%g\n", d); } else if (_arguments[i] == typeid(FOO)) { FOO f = *cast(FOO*) _argList[i]; printf("\t%p\n", f); } else { assert(0); } } } ---------- 2. There ought to be a way of passing the arglist of one variadic function directly to another.The C way is to typically have a variadic version and a va_list version (eg printf and vprintf). That way you can pass va_lists around. In D the pattern would become void foo(...) { } void vfoo(TypeInfo[] arguments, va_list argptr) { } Such functions should be added to std.stdio (or just make writex public).The simple solution, probably thought of by many, would be to allow the token '...' to be passed in. Example: void writeMultiple(int count, ...) { for (int i = 0; i < count; i++) writefln(...); } Further, I suppose the '...' passed to the function shouldn't have to be the whole '...' of the callee. For example, this might just as well be valid: void printError(char[] formatStr, ...) { writefln("Error: " ~ formatStr, ...); } or equivalently void printError(...) { writefln("Error: ", ...); } or possibly even void printError(...) { writefln("The error ", ..., " has occurred"); } (Should we allow slicing of '...'? Hmm....) Stewart.
Sep 29 2004
Ben Hinkle wrote: <snip>Except for the absurdity of effectively importing a language feature. I thought half the point of the D vararg system was to be built in.My idea is to give D-linkage variadic functions one more implicit parameter, void*[] _argList, which points to each argument's data.It would be nice but there isn't much difference to the user between writing int j = *cast(int*)_argList[i]; and int j = va_arg!(int)(_argptr);I suppose the _argList version lets you arbitrarily index the i^{th} parameter while the va_arg version only lets you access the parameters in order. It takes time to fill those pointers, though.It could be filled iff it's used.... <snip>To add my suggestion would protect us all from lib developers forgetting or not being bothered to do this. It would also be simple to do AFAICS.2. There ought to be a way of passing the arglist of one variadic function directly to another.The C way is to typically have a variadic version and a va_list version (eg printf and vprintf). That way you can pass va_lists around.In D the pattern would become void foo(...) { } void vfoo(TypeInfo[] arguments, va_list argptr) { } Such functions should be added to std.stdio (or just make writex public).<snip> Is it allowed for the two versions to be called the same? Or does D reject such potential backward incompatibility, no matter how likely or not someone really is to want to output an array of TypeInfos followed by a va_list? Stewart.
Sep 29 2004
"Stewart Gordon" <smjg_1998 yahoo.com> wrote in message news:cjepmv$18ij$1 digitaldaemon.com...Ben Hinkle wrote: <snip>writingMy idea is to give D-linkage variadic functions one more implicit parameter, void*[] _argList, which points to each argument's data.It would be nice but there isn't much difference to the user betweentrue enough. Walter does prefer language support over standard library support. I don't think I'd say the current scheme is "absurd", though.int j = *cast(int*)_argList[i]; and int j = va_arg!(int)(_argptr);Except for the absurdity of effectively importing a language feature. I thought half the point of the D vararg system was to be built in.inI suppose the _argList version lets you arbitrarily index the i^{th} parameter while the va_arg version only lets you access the parameters(egorder. It takes time to fill those pointers, though.It could be filled iff it's used.... <snip>2. There ought to be a way of passing the arglist of one variadic function directly to another.The C way is to typically have a variadic version and a va_list versionI suppose - though I don't exactly know how the mechanism would work. For example would it be compatible with extern(C) variadic declarations: extern (C) printf(char* str, ...); void foo(char* str,...) { printf(str,...); } Does the body of foo copy the inputs to foo from foo's stack frame so that the printf stack frame sees them in the right place? One benefit of the va_list declarations is that it is obvious a pointer is being passed around instead of stack frames being copied.printf and vprintf). That way you can pass va_lists around.To add my suggestion would protect us all from lib developers forgetting or not being bothered to do this. It would also be simple to do AFAICS.public).In D the pattern would become void foo(...) { } void vfoo(TypeInfo[] arguments, va_list argptr) { } Such functions should be added to std.stdio (or just make writex<snip> Is it allowed for the two versions to be called the same?Do you mean instead of void foo(...) { } void vfoo(TypeInfo[] arguments, va_list argptr) { } have void foo(...) { } void foo(TypeInfo[] arguments, va_list argptr) { } The problem is that there is an ambiguity since the code foo(_arguments, _argptr) could match either one of the two functions. According to D's overloading rules it would error.Or does D reject such potential backward incompatibility, no matter how likely or not someone really is to want to output an array of TypeInfos followed by a va_list?Where is the backward incompatibility? I don't understand the problem. Can you give an example?
Sep 29 2004
Ben Hinkle wrote: <snip>I suppose - though I don't exactly know how the mechanism would work. For example would it be compatible with extern(C) variadic declarations:Good question. But probably.extern (C) printf(char* str, ...); void foo(char* str,...) { printf(str,...); } Does the body of foo copy the inputs to foo from foo's stack frame so that the printf stack frame sees them in the right place? One benefit of the va_list declarations is that it is obvious a pointer is being passed around instead of stack frames being copied.Good question. Maybe Walter or someone could comment.... <snip>Do you mean instead of void foo(...) { } void vfoo(TypeInfo[] arguments, va_list argptr) { } have void foo(...) { } void foo(TypeInfo[] arguments, va_list argptr) { } The problem is that there is an ambiguity since the code foo(_arguments, _argptr) could match either one of the two functions. According to D's overloading rules it would error.That's half what I said. But does the spec indicate anywhere that matching '...' is classed as an exact match?Suppose at first only void foo(...) () is defined. And then someone tries calling it, meaning this form, with a TypeInfo[] and a va_list. And then in a later version of the lib, void foo(TypeInfo[] arguments, va_list argptr) {} is defined. Then the effect of the call changes. Stewart.Or does D reject such potential backward incompatibility, no matter how likely or not someone really is to want to output an array of TypeInfos followed by a va_list?Where is the backward incompatibility? I don't understand the problem. Can you give an example?
Sep 30 2004
In article <cjf0hd$1chb$1 digitaldaemon.com>, Ben Hinkle says...Do you mean instead of void foo(...) { } void vfoo(TypeInfo[] arguments, va_list argptr) { } have void foo(...) { } void foo(TypeInfo[] arguments, va_list argptr) { } The problem is that there is an ambiguity since the code foo(_arguments, _argptr) could match either one of the two functions. According to D's overloading rules it would error.Just a thought: this is another one of D's quirks that could use some attention. Suppose if the variadic function signatures were given the *lowest* priority for matching function overloads? At the very least, it would be consistent with how D matches individual parameters where the specific case is investigated first. version(DNG) pragma(EricAnderton,"yahoo");
Sep 30 2004