www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - How to delegate varargs

reply Frank Benoit <keinfarbton googlemail.com> writes:
How can I delegate the variadic argument list to another variadic
argument function?

e.g.
void myWritef( char[] frm, ... ){
  writefln( frm, ??? );
}

And how can I add or remove arguments to these varargs?
Nov 20 2007
parent reply Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Frank Benoit wrote:
 How can I delegate the variadic argument list to another variadic
 argument function?
 
 e.g.
 void myWritef( char[] frm, ... ){
   writefln( frm, ??? );
 }
 
 And how can I add or remove arguments to these varargs?

You have to write a "wrapper" function that explicitly takes the hidden arguments. In the case of writefln, phobos provides OutputStream.writefx. To modify the hidden arguments, you would have to know the size of the buffer _argptr points to. I don't see how this is possible with DMD :/
Nov 20 2007
parent reply Sean Kelly <sean f4.ca> writes:
Tomas Lindquist Olsen wrote:
 Frank Benoit wrote:
 How can I delegate the variadic argument list to another variadic
 argument function?

 e.g.
 void myWritef( char[] frm, ... ){
   writefln( frm, ??? );
 }

 And how can I add or remove arguments to these varargs?

You have to write a "wrapper" function that explicitly takes the hidden arguments. In the case of writefln, phobos provides OutputStream.writefx.

Yup, and this stinks. I don't suppose some language feature could be provided for working around this? Sean
Nov 20 2007
next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Sean Kelly" <sean f4.ca> wrote in message 
news:fhvhck$204d$5 digitalmars.com...
 Tomas Lindquist Olsen wrote:
 Frank Benoit wrote:
 How can I delegate the variadic argument list to another variadic
 argument function?

 e.g.
 void myWritef( char[] frm, ... ){
   writefln( frm, ??? );
 }

 And how can I add or remove arguments to these varargs?

You have to write a "wrapper" function that explicitly takes the hidden arguments. In the case of writefln, phobos provides OutputStream.writefx.

Yup, and this stinks. I don't suppose some language feature could be provided for working around this? Sean

It would be nice if varargs were passed instead as a reference to an array that's built on the stack out of (typeinfo, value) pairs. Problem with that, of course, is that each value can be a different size.. Tricky indeed.
Nov 20 2007
prev sibling parent reply Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Sean Kelly wrote:
 Tomas Lindquist Olsen wrote:
 Frank Benoit wrote:
 How can I delegate the variadic argument list to another variadic
  argument function?
 
 e.g. void myWritef( char[] frm, ... ){ writefln( frm, ??? ); }
 
 And how can I add or remove arguments to these varargs?

You have to write a "wrapper" function that explicitly takes the hidden arguments. In the case of writefln, phobos provides OutputStream.writefx.

Yup, and this stinks. I don't suppose some language feature could be provided for working around this? Sean

It should be possible, I can't really see anything that could be a showstopper. Except using real variadic function to implement it. On x86-64 va_list is not a simple pointer to data, so the storage for the variadic arguments would have to alloca'd by the caller for this idea to work. This is exactly what I do in LLVMDC [1] btw, as implementing a variadic function is broken on x86-64 (my development platform). Only calling one works... Ok :) Here's the idea, it's very simple! The way it currently works: // --------------------------- // the function: void func(...); // really gets the prototype void func_impl(TypeInfo[], void*); // calling it like this: void func(3.0f, "hello"[]); // is implemented like this: TypeInfo[2] arg_ti = [typeid(float), typeid(char[])]; struct Tmp { float f, char[] c; } Tmp arg_val = Tmp(3.0f, "hello"); func_impl(arg_ti[], cast(void*)&arg_val); // ---------------------------- Now to be able to pass on the arguments (and possible add to them), we need another parameter: size_t _argptrLength; Further, we also need to be able to pass ... as an argument in a call expression. // --------------------------- // lets implement func2 void func2(...) { // call the first one adding some params func(42, ... , 8.0i); } // --------------------------- // now... // the function: void func2(...); // really gets the prototype void func(TypeInfo[], void*, size_t); // calling it like this: func(42, ...); // gets implemented like this: TypeInfo[] arg_ti = (cast(TypeInfo*)alloca(TypeInfo.size*(1+_arguments.length)))[0..1+_arguments.length]; arg_ti[0] = typeid(int); arg_ti[1..1+arguments.length] = _arguments[]; void* arg_val = alloca(int.sizeof + _argptrLength); *(cast(int*)arg_val) = 42; func_impl(arg_ti, arg_val); // ---------------------------- I hope this makes sense, it could be written better, but it should show the idea. All this is stuff the compiler could figure out. Thinking in terms of LLVMDC and codegen, it could be done fairly easily. I'm not sure how much work it would be to get the DMD frontend to accept the '...' token as a function argument and generate something meaningful in the AST though. Excuse all the LLVMDC references, I know nobody is using it yet (with good reason), but it's my only reference to compiler development :) Hope to get some feedback, don't think I've spent this much time on a NG post before :P - Tomas Lindquist Olsen [1] LLVMDC - LLVM D Compiler - http://www.dsource.org/projects/llvmdc
Nov 20 2007
next sibling parent Tomas Lindquist Olsen <tomas famolsen.dk> writes:
ok seem I should have read the code again before posting, hope the message
comes across even 
with the flaws.
Nov 20 2007
prev sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Tomas Lindquist Olsen wrote:
 Sean Kelly wrote:
 Tomas Lindquist Olsen wrote:
 Frank Benoit wrote:
 How can I delegate the variadic argument list to another variadic
  argument function?

 e.g. void myWritef( char[] frm, ... ){ writefln( frm, ??? ); }

 And how can I add or remove arguments to these varargs?

You have to write a "wrapper" function that explicitly takes the hidden arguments. In the case of writefln, phobos provides OutputStream.writefx.

Yup, and this stinks. I don't suppose some language feature could be provided for working around this? Sean

It should be possible, I can't really see anything that could be a showstopper. Except using real variadic function to implement it. On x86-64 va_list is not a simple pointer to data, so the storage for the variadic arguments would have to alloca'd by the caller for this idea to work. This is exactly what I do in LLVMDC [1] btw, as implementing a variadic function is broken on x86-64 (my development platform). Only calling one works... Ok :) Here's the idea, it's very simple! The way it currently works: // --------------------------- // the function: void func(...); // really gets the prototype void func_impl(TypeInfo[], void*); // calling it like this: void func(3.0f, "hello"[]); // is implemented like this: TypeInfo[2] arg_ti = [typeid(float), typeid(char[])]; struct Tmp { float f, char[] c; } Tmp arg_val = Tmp(3.0f, "hello"); func_impl(arg_ti[], cast(void*)&arg_val); // ---------------------------- Now to be able to pass on the arguments (and possible add to them), we need another parameter: size_t _argptrLength; Further, we also need to be able to pass ... as an argument in a call expression. // --------------------------- // lets implement func2 void func2(...) { // call the first one adding some params func(42, ... , 8.0i); } // --------------------------- // now... // the function: void func2(...); // really gets the prototype void func(TypeInfo[], void*, size_t); // calling it like this: func(42, ...); // gets implemented like this: TypeInfo[] arg_ti = (cast(TypeInfo*)alloca(TypeInfo.size*(1+_arguments.length)))[0..1 _arguments.length]; arg_ti[0] = typeid(int); arg_ti[1..1+arguments.length] = _arguments[]; void* arg_val = alloca(int.sizeof + _argptrLength); *(cast(int*)arg_val) = 42; func_impl(arg_ti, arg_val); // ---------------------------- I hope this makes sense, it could be written better, but it should show the idea. All this is stuff the compiler could figure out. Thinking in terms of LLVMDC and codegen, it could be done fairly easily. I'm not sure how much work it would be to get the DMD frontend to accept the '...' token as a function argument and generate something meaningful in the AST though. Excuse all the LLVMDC references, I know nobody is using it yet (with good reason), but it's my only reference to compiler development :) Hope to get some feedback, don't think I've spent this much time on a NG post before :P - Tomas Lindquist Olsen [1] LLVMDC - LLVM D Compiler - http://www.dsource.org/projects/llvmdc

I don't care how it works, but some clean way to forward function varargs that doesn't look like a clumsy afterthought would be fantastic. --bb
Nov 20 2007
parent reply Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Bill Baxter wrote:
 
 I don't care how it works, but some clean way to forward function 
 varargs that doesn't look like a clumsy afterthought would be fantastic.
 
 --bb

From a users point of view the only change to the D spec would be: At the end of the section "D-style Variadic Functions" append: <<<<< The variadic arguments can be forwarded to another D-style variadic function by passing '...' as an argument. The forwarded arguments are bit-copied onto a new argument list. void foo(...) { // do something } void bar(...) { foo(1, ..., 3.0); }





With this approach there is still no way to slice the argument list, for that a more high-level approach like the ones mentioned by Jarret in the "Variadic arguments and map" thread is probably needed.
Nov 20 2007
parent reply Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Tomas Lindquist Olsen wrote:
 
  From a users point of view the only change to the D spec would be:
 
 At the end of the section "D-style Variadic Functions" append:
 
 <<<<<
 The variadic arguments can be forwarded to another D-style variadic 
 function by passing '...' as an argument. The forwarded arguments are 
 bit-copied onto a new argument list.
 
     void foo(...)
     {
         // do something
     }
     void bar(...)
     {
         foo(1, ..., 3.0);
     }
  >>>>>
 
 With this approach there is still no way to slice the argument list, for 
 that a more high-level approach like the ones mentioned by Jarret in the 
 "Variadic arguments and map" thread is probably needed.

Possibly also the section about "_argptr" should be changed to: "These variadic functions have a special local variable declared for them, _argptr, which is a void* pointer to the first of the variadic arguments. To access the arguments, _argptr must be cast to a pointer to the expected argument type. There is also a special local variable, _argptrLength, which holds the length in bytes of the variadic argument list" This could however just be an implementation detail.
Nov 20 2007
parent reply Chad J <gamerChad _spamIsBad_gmail.com> writes:
Tomas Lindquist Olsen wrote:
 Tomas Lindquist Olsen wrote:
  From a users point of view the only change to the D spec would be:

 At the end of the section "D-style Variadic Functions" append:

 <<<<<
 The variadic arguments can be forwarded to another D-style variadic 
 function by passing '...' as an argument. The forwarded arguments are 
 bit-copied onto a new argument list.

     void foo(...)
     {
         // do something
     }
     void bar(...)
     {
         foo(1, ..., 3.0);
     }
  >>>>>

 With this approach there is still no way to slice the argument list, 
 for that a more high-level approach like the ones mentioned by Jarret 
 in the "Variadic arguments and map" thread is probably needed.

Possibly also the section about "_argptr" should be changed to: "These variadic functions have a special local variable declared for them, _argptr, which is a void* pointer to the first of the variadic arguments. To access the arguments, _argptr must be cast to a pointer to the expected argument type. There is also a special local variable, _argptrLength, which holds the length in bytes of the variadic argument list" This could however just be an implementation detail.

Why not just make it void[] _argdata? It would save us some naming clutter.
Nov 20 2007
parent Tomas Lindquist Olsen <tomas famolsen.dk> writes:
Chad J wrote:
 
 Why not just make it void[] _argdata?  It would save us some naming 
 clutter.

But it would become a breaking change.
Nov 20 2007