digitalmars.D.learn - Variadic functions: How to pass another variadic function the variadic
- Gabi (7/7) Aug 03 2013 void F1(...)
- bearophile (14/15) Aug 03 2013 import std.stdio;
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (9/24) Aug 03 2013 Would you expect the following two lines behave the same?
- monarch_dodra (8/26) Aug 03 2013 writeln simply prints all the args it receives, then a line break.
- bearophile (6/8) Aug 03 2013 According to a recent discussion with Andrei, that's (thankfully)
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (43/74) Aug 04 2013 Does args have a type that makes it a single entity? If so, the two
- monarch_dodra (45/129) Aug 04 2013 Yes, you can build a single "std.typecons.Tuple" out of a
- Gabi (5/20) Aug 03 2013 Thanks but how do I do this for variadic functions (using
- monarch_dodra (13/41) Aug 03 2013 I don't know how to do runtime variadics in D, and quite frankly,
- Gabi (26/68) Aug 03 2013 Ok, I got an alternative solution. What do you think about the
- bearophile (10/19) Aug 03 2013 D supports both C and D style variadiac functions. D variadiac
- monarch_dodra (4/21) Aug 03 2013 The more you know I guess. Good to see D made the whole thing
void F1(...) { } void F2(...) { //HOW TO pass F1(..) the args we were called with ? }
Aug 03 2013
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
On 08/03/2013 07:58 AM, bearophile wrote:Gabi:Would you expect the following two lines behave the same? writeln(args); writefln("%s", args); Apparently not: 10hello1.5 10 Why?//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, bearophileAli
Aug 03 2013
On Saturday, 3 August 2013 at 15:10:20 UTC, Ali Çehreli wrote:On 08/03/2013 07:58 AM, bearophile wrote:I wouldn't.Gabi:Would you expect the following two lines behave the same? writeln(args); writefln("%s", args);//HOW TO pass F1(..) the args we were called with ?import std.stdio; void f1(Args...)(Args args) { foreach (arg; args) arg.writeln;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
monarch_dodra:writefln("%s", 10, "hello", 1.5); => 10According 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
On 08/03/2013 09:05 AM, monarch_dodra wrote:On Saturday, 3 August 2013 at 15:10:20 UTC, Ali Çehreli wrote: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.) AliOn 08/03/2013 07:58 AM, bearophile wrote:I wouldn't.Gabi:Would you expect the following two lines behave the same? writeln(args); writefln("%s", args);//HOW TO pass F1(..) the args we were called with ?import std.stdio; void f1(Args...)(Args args) { foreach (arg; args) arg.writeln;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 04 2013
On Sunday, 4 August 2013 at 15:29:48 UTC, Ali Çehreli wrote:On 08/03/2013 09:05 AM, monarch_dodra wrote: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.On Saturday, 3 August 2013 at 15:10:20 UTC, Ali Çehreli wrote:break.On 08/03/2013 07:58 AM, bearophile wrote:I wouldn't.Gabi:Would you expect the following two lines behave the same? writeln(args); writefln("%s", args);//HOW TO pass F1(..) the args we were called with ?import std.stdio; void f1(Args...)(Args args) { foreach (arg; args) arg.writeln;Apparently not: 10hello1.5 10 Why?writeln simply prints all the args it receives, then a linewritefln, on the other end, only prints its single "fmt" arg.The restof the args are only used as they are referenced in fmt. Yourcodebasically boils down to: writefln("%s", 10, "hello", 1.5); => 10Does 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
On Saturday, 3 August 2013 at 14:58:49 UTC, bearophile wrote:Gabi: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//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
On Saturday, 3 August 2013 at 16:57:41 UTC, Gabi wrote:On Saturday, 3 August 2013 at 14:58:49 UTC, bearophile wrote: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.Gabi: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//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
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: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); } }On Saturday, 3 August 2013 at 14:58:49 UTC, bearophile wrote: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.Gabi: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//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
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
On Saturday, 3 August 2013 at 19:12:40 UTC, bearophile wrote:monarch_dodra: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.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
Aug 03 2013