www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - varargs when they're not all the same type?

reply Andy Valencia <dont spam.me> writes:
Can somebody give me a starting point for understanding varadic 
functions?  I know that we can declare them

   int[] args...

and pick through whatever the caller provided.  But if the caller 
wants to pass two int's and a _string_?  That declaration won't 
permit it.

I've looked into the formatter, and also the varargs 
implementation.  But it's a bit of a trip through a funhouse full 
of mirrors.  Can somebody describe the basic language approach to 
non-uniform varargs, and then I can take it the rest of the way 
reading the library.

Thanks in advance!
Andy
Mar 14
next sibling parent monkyyy <crazymonkyyy gmail.com> writes:
On Thursday, 14 March 2024 at 17:57:21 UTC, Andy Valencia wrote:
 Can somebody give me a starting point for understanding varadic 
 functions?  I know that we can declare them

   int[] args...

 and pick through whatever the caller provided.  But if the 
 caller wants to pass two int's and a _string_?  That 
 declaration won't permit it.

 I've looked into the formatter, and also the varargs 
 implementation.  But it's a bit of a trip through a funhouse 
 full of mirrors.  Can somebody describe the basic language 
 approach to non-uniform varargs, and then I can take it the 
 rest of the way reading the library.

 Thanks in advance!
 Andy
there are 3 (or 4?) variadic functions try ```d auto foo(T...)(T args){ static foreach(arg;args){ ... ```
Mar 14
prev sibling parent reply "H. S. Teoh" <hsteoh qfbox.info> writes:
On Thu, Mar 14, 2024 at 05:57:21PM +0000, Andy Valencia via Digitalmars-d-learn
wrote:
 Can somebody give me a starting point for understanding varadic
 functions?  I know that we can declare them
 
   int[] args...
 
 and pick through whatever the caller provided.  But if the caller
 wants to pass two int's and a _string_?  That declaration won't permit
 it.
 
 I've looked into the formatter, and also the varargs implementation.
 But it's a bit of a trip through a funhouse full of mirrors.  Can
 somebody describe the basic language approach to non-uniform varargs,
 and then I can take it the rest of the way reading the library.
[...] The best way to do multi-type varags in D is to use templates: import std; void myFunc(Args...)(Args args) { foreach (i, arg; args) { writefln("parameter %d is a %s with value %s", i, typeof(arg), arg); } } void main() { myFunc(123, 3.14159, "blah blah", [ 1, 2, 3 ], new Object()); } D also supports C-style varags (without templates), but it's not recommended because it's not type-safe. You can find the description in the language docs. T -- "Maybe" is a strange word. When mom or dad says it it means "yes", but when my big brothers say it it means "no"! -- PJ jr.
Mar 14
parent reply Andy Valencia <dont spam.me> writes:
On Thursday, 14 March 2024 at 18:05:59 UTC, H. S. Teoh wrote:
 ...
 The best way to do multi-type varags in D is to use templates:

 	import std;
 	void myFunc(Args...)(Args args) {
Thank you. The first parenthetical list is of types, is it not? I can't find anywhere which says what "type" is inferred for "Args..."? (gdb pretends like "arg" is not a known symbol.) Is it basically a tuple of the suitable type? Andy
Mar 14
next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Thursday, 14 March 2024 at 20:58:21 UTC, Andy Valencia wrote:
 On Thursday, 14 March 2024 at 18:05:59 UTC, H. S. Teoh wrote:
 ...
 The best way to do multi-type varags in D is to use templates:

 	import std;
 	void myFunc(Args...)(Args args) {
Thank you. The first parenthetical list is of types, is it not? I can't find anywhere which says what "type" is inferred for "Args..."? (gdb pretends like "arg" is not a known symbol.) Is it basically a tuple of the suitable type? Andy
Most of the time the variadic template parameters are infered from the run time parameters. In that case indeed `Args` will be a type tuple of `args` types. ```d void myFunc(Args...)(Args args) {} myFunc(0,0.1); // is like the more verbose `myFunc!(int,double)(0,0.1)` ``` However explicit instantiation can take whatever is known at compile time, such as constant expressions or even certain static variables. So that is rather called an `alias sequence` in D. That being said and with the signature of `myFunc` that will effectively only work if `Args` is made of types. About debugging, each individual runtime arg can be inspected using a bit of knowledge of D internals. ![](https://i.imgur.com/XW74nke.png) As you can see the elements are named following this pattern `__param_[0-9]+`. So with gdb used as CLI, `$ p __param_0` will (🤞🤞) print the first variadic element, and so on.
Mar 14
parent reply Andy Valencia <dont spam.me> writes:
On Thursday, 14 March 2024 at 23:13:51 UTC, Basile B. wrote:
 ...
 However explicit instantiation can take whatever is known at 
 compile time, such as constant expressions or even certain 
 static variables. So that is rather called an `alias sequence` 
 in D.
Which statement leads me to section 77.2 of "Programming in D", and now I am deep into the mechanisms behind what you have very kindly shared. Thank you once more. Andy
Mar 14
parent Andy Valencia <dont spam.me> writes:
On Friday, 15 March 2024 at 00:11:11 UTC, Andy Valencia wrote:

(varargs & friends)

 Which statement leads me to section 77.2 of "Programming in D", 
 and now I am deep into the mechanisms behind what you have very 
 kindly shared.  Thank you once more.
As some fruits of my labors here, below is a link to a "fmt" module which does C-style formatting. It supports int/long signed/unsigned, right/left padding and zero padding, plus strings (w. padding). It's memory and type safe; I ended up using unions to tabulate the arguments as I need to access them as an array (rather than walking them--I'm walking the format string instead). It adds 6k to an executable, which means dlang will work out fine for all of my smaller scripting needs in the future. Calls look like: auto s = fmt("%d %u - %20s", 123, 456, "Hi, Mom"); https://sources.vsta.org:7100/dlang/file?name=fmt.d&ci=tip Comments are welcome! I'd post here, but it seems a little long for that? Andy
Mar 16
prev sibling parent "H. S. Teoh" <hsteoh qfbox.info> writes:
On Thu, Mar 14, 2024 at 08:58:21PM +0000, Andy Valencia via Digitalmars-d-learn
wrote:
 On Thursday, 14 March 2024 at 18:05:59 UTC, H. S. Teoh wrote:
 ...
 The best way to do multi-type varags in D is to use templates:
 
 	import std;
 	void myFunc(Args...)(Args args) {
Thank you. The first parenthetical list is of types, is it not? I can't find anywhere which says what "type" is inferred for "Args..."? (gdb pretends like "arg" is not a known symbol.) Is it basically a tuple of the suitable type?
[...] The first set of parenthesis specify compile-time arguments. The specification `Args...` means "zero or more types". So it could be any list of types, which naturally would be chosen according to the arguments given. For example, to pass an int and a float, you'd do something like: myFunc!(int, float)(123, 3.14159f); and to pass a string, two ints, and a char, you'd write: myFunc!(string, int, int, char)("abc", 123, 456, 'z'); Having to specify types manually, of course, is a lot of unnecessary typing, since the compiler already knows what the types are based on what you write in the second pair of parentheses. For this reason, typical D code will omit the first pair of parentheses (the `!(...)`, that is, the compile-time arguments) and just let the compiler infer the types automatically: myFunc(123, 3.14159f); // compiler figures out Args = (int, float) myFunc("abc", 123, 456, 'z'); // compiler figures out Args = (string, int, int, char) T -- A program should be written to model the concepts of the task it performs rather than the physical world or a process because this maximizes the potential for it to be applied to tasks that are conceptually similar and, more important, to tasks that have not yet been conceived. -- Michael B. Allen
Mar 14