Note: I'm actually using version 0.9.2 and not hg tip, but 0.9.2 is not in the options list
There are various bugs with the "..." syntax for creating tuples, but
I think they all root back to types being errously converted to
singletons of itself when the number of arguments is >= 2.
// file tup_bug.d
template TupleBug(values...)
{
alias values[0] v0;
alias values[0][0][0][0][0] chain;
pragma(msg, "values: ", values);
pragma(msg, "v0: ", v0);
pragma(msg, "values[0]: ", values[0]);
pragma(msg, "chain: ", chain);
}
pragma(msg, "-- TupleBug!(int):");
alias TupleBug!(int) _;
pragma(msg, "\n-- TupleBug!(int, \"foo\"):");
alias TupleBug!(int, "foo") _0;
void main() {}
Output of ldc 0.9.2 is
$ldc tup_bug.d
-- TupleBug!(int):
values: (int)
v0: int
values[0]: int
chain: int[0LU][0LU][0LU][0LU]
-- TupleBug!(int, "foo"):
values: tuple((int),"foo")
v0: (int)
values[0]: int
chain: (int)
Expected output for TupleBug?!(int, "foo"):
values: tuple(int,"foo")
v0: int
values[0]: int
chain: int[0LU][0LU][0LU][0LU]
The output for TupleBug?!(int) is ok, but when the number of parameters
is 2 or greater, then all types T in the parameter list are implicitly
converted to a singleton tuple (T), as can be seen here in case of
T=int. Even worse, you can not index the singleton tuple, it just
returns a copy of itself, which is evident when looking at the output
of chain.
In TupleBug?!(int), chain is a multidimensional array, which is
correct. But in TupleBug?!(int, "foo"), the output of chain is just
(int).
I also think the usage of tuple(...) and (...) in the output is
inconsistend, it seems like tuple(...) is used for tuples of length >=
2 and (...) is used for singleton tuples only. I would use tuple(...)
in both cases.
============================================================================
One really annoying consequence that's bugging me is that assigning
names to template parameters via aliasing is not possible:
// file tup_bug_consequence.d
struct TypeAndName(args...)
{
alias args[0] type; // "..." bug => type = (args[0]), not args[0]
const char[] name = args[1];
}
template DeclVar(data)
{
mixin("data.type "~data.name~";");
}
void main()
{
mixin DeclVar!(TypeAndName!(int, "foo"));
pragma(msg, "foo: ", foo);
pragma(msg, "typeof(foo): ", typeof(foo));
foo = 3;
}
I expect this to define "int foo;" inside main, but due to the "..."
bug described above, that doesn't work:
$ldc tup_bug_consequence.d
foo : tuple(_foo_field_0)
typeof(foo): (int)
tup_bug_consequence.d(18): Error: foo is not an lvalue
tup_bug_consequence.d(18): Error: cannot implicitly convert expression (3) of type int to (int)
tup_bug_consequence.d(18): Error: cannot cast int to (int)
This TypeAndName? construct is really useful for parsing template
arguments of the form (Type1, "name1", ..., TypeN, "nameN"), but as
soon as you try to get an alias to one of the types, everything
breaks. A workaround is to always work with the parameter tuple
directly and don't alias its items, but then all your templates are
reduced to magic tuple indexing code that no one can understand.