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/wyokmbxiuetwigbpy...@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.

Reply via email to