www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Variadic functions: How to pass another variadic function the variadic

reply "Gabi" <galim120 bezeqint.net> writes:
void F1(...)
{

}

void F2(...)
{
   //HOW TO pass F1(..) the args we were called with ?

}
Aug 03 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Gabi:

   //HOW TO pass F1(..) the args we were called with ?
import std.stdio; void f1(Args...)(Args args) { foreach (arg; args) arg.writeln; } void f2(Args...)(Args args) { f1(args); } void main() { f2(10, "hello", 1.5); } Bye, bearophile
Aug 03 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/03/2013 07:58 AM, bearophile wrote:

 Gabi:

   //HOW TO pass F1(..) the args we were called with ?
import std.stdio; void f1(Args...)(Args args) { foreach (arg; args) arg.writeln;
Would you expect the following two lines behave the same? writeln(args); writefln("%s", args); Apparently not: 10hello1.5 10 Why?
 }

 void f2(Args...)(Args args) {
      f1(args);
 }

 void main() {
      f2(10, "hello", 1.5);
 }


 Bye,
 bearophile
Ali
Aug 03 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 3 August 2013 at 15:10:20 UTC, Ali Çehreli wrote:
 On 08/03/2013 07:58 AM, bearophile wrote:

 Gabi:

   //HOW TO pass F1(..) the args we were called with ?
import std.stdio; void f1(Args...)(Args args) { foreach (arg; args) arg.writeln;
Would you expect the following two lines behave the same? writeln(args); writefln("%s", args);
I wouldn't.
 Apparently not:

 10hello1.5
 10

 Why?
writeln simply prints all the args it receives, then a line break. writefln, on the other end, only prints its single "fmt" arg. The rest of the args are only used as they are referenced in fmt. Your code basically boils down to: writefln("%s", 10, "hello", 1.5); => 10
Aug 03 2013
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
monarch_dodra:

 writefln("%s", 10, "hello", 1.5);
 => 10
According to a recent discussion with Andrei, that's (thankfully) going to become a run-time exception: http://d.puremagic.com/issues/show_bug.cgi?id=4927 Bye, bearophile
Aug 03 2013
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/03/2013 09:05 AM, monarch_dodra wrote:

 On Saturday, 3 August 2013 at 15:10:20 UTC, Ali Çehreli wrote:
 On 08/03/2013 07:58 AM, bearophile wrote:

 Gabi:

   //HOW TO pass F1(..) the args we were called with ?
import std.stdio; void f1(Args...)(Args args) { foreach (arg; args) arg.writeln;
Would you expect the following two lines behave the same? writeln(args); writefln("%s", args);
I wouldn't.
 Apparently not:

 10hello1.5
 10

 Why?
writeln simply prints all the args it receives, then a line break. writefln, on the other end, only prints its single "fmt" arg. The rest of the args are only used as they are referenced in fmt. Your code basically boils down to: writefln("%s", 10, "hello", 1.5); => 10
Does args have a type that makes it a single entity? If so, the two should behave the same. For example, the output is the same tuples and slices: import std.stdio; import std.typecons; void foo(Args...)(Args args) { // Both outputs are the same: writeln(tuple(1, "abc", 1.5)); writefln("%s", tuple(1, "abc", 1.5)); // Both outputs are the same: writeln([ 1, 2, 3 ]); writefln("%s", [ 1, 2, 3 ]); // Unfortunately, not here: writeln(args); writefln("%s", args); // Let's see why that may be... // Prints "(int, string, double)" writeln(Args.stringof); } void main() { foo(10, "hello", 1.5); } According to the last line in foo(), args is three types together. Is that a TypeTuple I wonder... Yes, it is a TypeTuple: import typetuple; // ... // Passes static assert( is (Args == typeof(TypeTuple!(int.init, string.init, double.init)))); Now I see... Since writefln is also a variadic function, it naturally peels off the TypeTuple one %s at a time. It is silly of me to stumble on this :) but I learned that there exists one type that is printed differently by the following two lines: writeln(a); writefln("%s", a); Can you think of any other type of 'a' that would be different? (Modulo formatting like square brackets around slices, commas between elements, etc.) Ali
Aug 04 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Sunday, 4 August 2013 at 15:29:48 UTC, Ali Çehreli wrote:
 On 08/03/2013 09:05 AM, monarch_dodra wrote:

 On Saturday, 3 August 2013 at 15:10:20 UTC, Ali Çehreli wrote:
 On 08/03/2013 07:58 AM, bearophile wrote:

 Gabi:

   //HOW TO pass F1(..) the args we were called with ?
import std.stdio; void f1(Args...)(Args args) { foreach (arg; args) arg.writeln;
Would you expect the following two lines behave the same? writeln(args); writefln("%s", args);
I wouldn't.
 Apparently not:

 10hello1.5
 10

 Why?
writeln simply prints all the args it receives, then a line
break.
 writefln, on the other end, only prints its single "fmt" arg.
The rest
 of the args are only used as they are referenced in fmt. Your
code
 basically boils down to:

 writefln("%s", 10, "hello", 1.5);
 => 10
Does args have a type that makes it a single entity? If so, the two should behave the same. For example, the output is the same tuples and slices: import std.stdio; import std.typecons; void foo(Args...)(Args args) { // Both outputs are the same: writeln(tuple(1, "abc", 1.5)); writefln("%s", tuple(1, "abc", 1.5)); // Both outputs are the same: writeln([ 1, 2, 3 ]); writefln("%s", [ 1, 2, 3 ]); // Unfortunately, not here: writeln(args); writefln("%s", args); // Let's see why that may be... // Prints "(int, string, double)" writeln(Args.stringof); } void main() { foo(10, "hello", 1.5); } According to the last line in foo(), args is three types together. Is that a TypeTuple I wonder... Yes, it is a TypeTuple: import typetuple; // ... // Passes static assert( is (Args == typeof(TypeTuple!(int.init, string.init, double.init)))); Now I see... Since writefln is also a variadic function, it naturally peels off the TypeTuple one %s at a time. It is silly of me to stumble on this :) but I learned that there exists one type that is printed differently by the following two lines: writeln(a); writefln("%s", a); Can you think of any other type of 'a' that would be different? (Modulo formatting like square brackets around slices, commas between elements, etc.) Ali
Yes, you can build a single "std.typecons.Tuple" out of a "generic tuple of values". However, this prints because the *type* "Tuple" is itself printed with all its internals, as opposed to writefln itself extracting the members of the Tuple. Any format specifier would be lost, for example. Note that technically, the type "TypeTuple" doesn't exist. It's a template that simply forwards "Args". The type itself does not exist. When you write "TypeTuple!Args", it is immediatly replaced by "Args" by the compiler. It's only use is that it allows some syntax that the compiler would not know how to parse without a bit of help. For example, if your write "pragma(msg, Args.stringof)", it'll print: "(int, string, double)". As you can see, no TypeTuple. Here, the use of TypeTuple is obvious though: The code: "static assert(is(Args == (int, string, double));" This would not compile, as the compiler would not understand those tokens. TypeTuple is a simple way of adding grouping, without confusing the compiler. Another interesting aspect of TypeTuple (that I found confusing at first), is that since it is not a type "per se", a TypeTyple of a TypeTuple is simply the expanded TypeTuple: TypeTuple!(TypeTuple!(int, string), TypeTuple!(int, string)); is TypeTuple!(int, string, int, string); is (int, string, int, string); An interesting read which came up recently: "Variadic grouping" http://forum.dlang.org/thread/wyokmbxiuetwigbpyumz forum.dlang.org Long story short, if you need actual grouping then a plain old: template Group(Args...) { alias Ungroup = Args; } or template Pack(Args...) { alias Unpack = Args; } Using this will achieve passing several Args as a single grouped type. However, since it is explicitly packed/grouped, extracting the actual members will also need to be explicit.
Aug 04 2013
prev sibling parent reply "Gabi" <galim120 bezeqint.net> writes:
On Saturday, 3 August 2013 at 14:58:49 UTC, bearophile wrote:
 Gabi:

  //HOW TO pass F1(..) the args we were called with ?
import std.stdio; void f1(Args...)(Args args) { foreach (arg; args) arg.writeln; } void f2(Args...)(Args args) { f1(args); } void main() { f2(10, "hello", 1.5); } Bye, bearophile
Thanks but how do I do this for variadic functions (using _arguments and friends) ? Not variadic templates.. More specifically I want to know at runtime the type of each parameter
Aug 03 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 3 August 2013 at 16:57:41 UTC, Gabi wrote:
 On Saturday, 3 August 2013 at 14:58:49 UTC, bearophile wrote:
 Gabi:

 //HOW TO pass F1(..) the args we were called with ?
import std.stdio; void f1(Args...)(Args args) { foreach (arg; args) arg.writeln; } void f2(Args...)(Args args) { f1(args); } void main() { f2(10, "hello", 1.5); } Bye, bearophile
Thanks but how do I do this for variadic functions (using _arguments and friends) ? Not variadic templates.. More specifically I want to know at runtime the type of each parameter
I don't know how to do runtime variadics in D, and quite frankly, I don't want to know: They are an abomination, and I don't want to be anywhere near these things. My guess though, is that it's the same syntax as in C? Use a straight up elispis: void foo(...). Note that you *can't* extract the types from the vararg unless you *guess* them from an alternative source (for example, "fmt" in the printf function) Also, importing "core.vararg" should get you whatever you'd get in 'vararg.h'/"stdarg.h". From there, I don't think D does anything specific that's not actually just C.
Aug 03 2013
next sibling parent "Gabi" <galim120 bezeqint.net> writes:
On Saturday, 3 August 2013 at 18:48:17 UTC, monarch_dodra wrote:
 On Saturday, 3 August 2013 at 16:57:41 UTC, Gabi wrote:
 On Saturday, 3 August 2013 at 14:58:49 UTC, bearophile wrote:
 Gabi:

 //HOW TO pass F1(..) the args we were called with ?
import std.stdio; void f1(Args...)(Args args) { foreach (arg; args) arg.writeln; } void f2(Args...)(Args args) { f1(args); } void main() { f2(10, "hello", 1.5); } Bye, bearophile
Thanks but how do I do this for variadic functions (using _arguments and friends) ? Not variadic templates.. More specifically I want to know at runtime the type of each parameter
I don't know how to do runtime variadics in D, and quite frankly, I don't want to know: They are an abomination, and I don't want to be anywhere near these things. My guess though, is that it's the same syntax as in C? Use a straight up elispis: void foo(...). Note that you *can't* extract the types from the vararg unless you *guess* them from an alternative source (for example, "fmt" in the printf function) Also, importing "core.vararg" should get you whatever you'd get in 'vararg.h'/"stdarg.h". From there, I don't think D does anything specific that's not actually just C.
Ok, I got an alternative solution. What do you think about the following ? void f(T:long) (T arg) { ... } void f(T:int) (T arg) { ... } void f(T:int) (T arg) { ... } void f(T:string) (T arg) { ... } void f1(ARGS...)(ARGS args) { foreach(arg; args) { f(arg); } }
Aug 03 2013
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
monarch_dodra:

 My guess though, is that it's the same syntax as in C? Use a 
 straight up elispis:

 void foo(...).

 Note that you *can't* extract the types from the vararg unless 
 you *guess* them from an alternative source (for example, "fmt" 
 in the printf function)

 Also, importing "core.vararg" should get you whatever you'd get 
 in 'vararg.h'/"stdarg.h". From there, I don't think D does 
 anything specific that's not actually just C.
D supports both C and D style variadiac functions. D variadiac functions also have a _arguments of type TypeInfo[]. See here about in the middle of the page: http://dlang.org/function (This is why we ask people like JS "why do you need that?", because very often there are better solutions if you know the real problem to solve). Bye, bearophile
Aug 03 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 3 August 2013 at 19:12:40 UTC, bearophile wrote:
 monarch_dodra:

 My guess though, is that it's the same syntax as in C? Use a 
 straight up elispis:

 void foo(...).

 Note that you *can't* extract the types from the vararg unless 
 you *guess* them from an alternative source (for example, 
 "fmt" in the printf function)

 Also, importing "core.vararg" should get you whatever you'd 
 get in 'vararg.h'/"stdarg.h". From there, I don't think D does 
 anything specific that's not actually just C.
D supports both C and D style variadiac functions. D variadiac functions also have a _arguments of type TypeInfo[]. See here about in the middle of the page: http://dlang.org/function
The more you know I guess. Good to see D made the whole thing more robust. I've never had a usecase for runtime variadic, but thanks for the link.
Aug 03 2013