Thread overview | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
August 16, 2013 Places a TypeTuple can be used | ||||
---|---|---|---|---|
| ||||
I know of three places a TypeTuple can be used at: 1) Function parameter list 2) Template parameter list 3) Array literal element list Are there more? import std.typetuple; void foo(int, string, double) {} struct S(T, float f) {} void main() { // 1) Function parameter list: May not contain types foo(TypeTuple!(42, "hello", 1.5)); // 2) Template parameter list: May contain types auto s = S!(TypeTuple!(char, 2.5))(); // 3) Array elements: Elements must be the same type auto a = [ TypeTuple!(1, 2, 3, 4) ]; // Are there other places that a TypeTuple can be used? } Ali |
August 16, 2013 Re: Places a TypeTuple can be used | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Friday, 16 August 2013 at 04:14:04 UTC, Ali Çehreli wrote:
> I know of three places a TypeTuple can be used at:
>
> 1) Function parameter list
>
> 2) Template parameter list
>
> 3) Array literal element list
>
> Are there more?
>
> import std.typetuple;
>
> void foo(int, string, double)
> {}
>
> struct S(T, float f)
> {}
>
> void main()
> {
> // 1) Function parameter list: May not contain types
> foo(TypeTuple!(42, "hello", 1.5));
>
> // 2) Template parameter list: May contain types
> auto s = S!(TypeTuple!(char, 2.5))();
>
> // 3) Array elements: Elements must be the same type
> auto a = [ TypeTuple!(1, 2, 3, 4) ];
>
> // Are there other places that a TypeTuple can be used?
> }
>
> Ali
I'm not sure if it should be considered a separate case, but there is this:
foreach(type; TypeTuple!(ubyte, uint, ulong))
{
writeln(type.max);
}
|
August 16, 2013 Re: Places a TypeTuple can be used | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | On 08/15/2013 10:39 PM, Meta wrote: > On Friday, 16 August 2013 at 04:14:04 UTC, Ali Çehreli wrote: >> 1) Function parameter list >> >> 2) Template parameter list >> >> 3) Array literal element list >> >> Are there more? > I'm not sure if it should be considered a separate case, but there is this: > > foreach(type; TypeTuple!(ubyte, uint, ulong)) > { > writeln(type.max); > } Thanks! That's a very interesting one. Other than the peculiarity of the loop being a compile-time foreach, that TypeTuple is appearing at a place where its expansion is not even valid: foreach (type; ubyte, uint, ulong) { // compilation error Ali |
August 16, 2013 Re: Places a TypeTuple can be used | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Thursday, August 15, 2013 23:09:55 Ali Çehreli wrote:
> On 08/15/2013 10:39 PM, Meta wrote:
> > On Friday, 16 August 2013 at 04:14:04 UTC, Ali Çehreli wrote:
> >> 1) Function parameter list
> >>
> >> 2) Template parameter list
> >>
> >> 3) Array literal element list
> >>
> >> Are there more?
> >
> > I'm not sure if it should be considered a separate case, but there is
>
> this:
> > foreach(type; TypeTuple!(ubyte, uint, ulong))
> > {
> >
> > writeln(type.max);
> >
> > }
>
> Thanks! That's a very interesting one. Other than the peculiarity of the loop being a compile-time foreach, that TypeTuple is appearing at a place where its expansion is not even valid:
>
> foreach (type; ubyte, uint, ulong) { // compilation error
That's because what you just wrote is not equivalent to what TypeTuple is. TypeTuple is an alias for a parameter or argument list, not simply a list of types or values. I don't know of a way to write the equivalent in a foreach loop without TypeTuple or some other alias which was the same as TypeTuple.
- Jonathan M Davis
|
August 16, 2013 Re: Places a TypeTuple can be used | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Thursday, August 15, 2013 21:14:03 Ali Çehreli wrote: > I know of three places a TypeTuple can be used at: > > 1) Function parameter list > > 2) Template parameter list > > 3) Array literal element list > > Are there more? > > import std.typetuple; > > void foo(int, string, double) > {} > > struct S(T, float f) > {} > > void main() > { > // 1) Function parameter list: May not contain types > foo(TypeTuple!(42, "hello", 1.5)); > > // 2) Template parameter list: May contain types > auto s = S!(TypeTuple!(char, 2.5))(); > > // 3) Array elements: Elements must be the same type > auto a = [ TypeTuple!(1, 2, 3, 4) ]; > > // Are there other places that a TypeTuple can be used? > } It can be used in foreach, which essentially makes it a static foreach. This is extremely useful when unit testing. e.g. foreach(T; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstring)) { assert(stripLeft(to!T(" foo ")) == to!T("foo ")); } The code within the foreach is duplicated, because the loop is run at compile time. So, the above code becomes something like {assert(stripLeft(to!(char[])(" foo ")) == to!(char[])("foo "));} {assert(stripLeft(to!(wchar[])(" foo ")) == to!(wchar[])("foo "));} {assert(stripLeft(to!(dchar[])(" foo ")) == to!(dchar[])("foo "));} {assert(stripLeft(to!string(" foo ")) == to!string("foo "));} {assert(stripLeft(to!wstring(" foo ")) == to!wstring("foo "));} {assert(stripLeft(to!dstring(" foo ")) == to!dstring("foo "));} You can use TypeTuple in enums, though the enum value would have to be used in a context that TypeTuples can be used in. You can also alias them. There are probably others, especially when you start messing with templates and parameter lists, but while those use the built-in tuples which TypeTuple aliases, I can't think of any case at the moment where you would explicitly use TypeTuple. You should probably read this article if you haven't: http://dlang.org/tuple.html Unfortunately, it muddles things a fair bit, because it uses Tuple instead of std.typetuple.TypeTuple, and then it talks about expression tuples vs type tuples (whereas a TypeTuple could be either an expression tuple or a type tuple), but that just highlights how confusing this is and how badly named TypeTuple is (but unfortunately, it's used in so much code now, that renaming it just isn't going to happen). That article should probably be rewritten so that it takes TypeTuple into account. But it does contain some good info if you can properly understand the difference between TypeTuple and a type tuple. - Jonathan M Davis |
August 16, 2013 Re: Places a TypeTuple can be used | ||||
---|---|---|---|---|
| ||||
Posted in reply to Meta | On Friday, 16 August 2013 at 05:39:32 UTC, Meta wrote:
> On Friday, 16 August 2013 at 04:14:04 UTC, Ali Çehreli wrote:
>> I know of three places a TypeTuple can be used at:
>>
>> 1) Function parameter list
>>
>> 2) Template parameter list
>>
>> 3) Array literal element list
>>
>> Are there more?
>>
>> import std.typetuple;
>>
>> void foo(int, string, double)
>> {}
>>
>> struct S(T, float f)
>> {}
>>
>> void main()
>> {
>> // 1) Function parameter list: May not contain types
>> foo(TypeTuple!(42, "hello", 1.5));
>>
>> // 2) Template parameter list: May contain types
>> auto s = S!(TypeTuple!(char, 2.5))();
>>
>> // 3) Array elements: Elements must be the same type
>> auto a = [ TypeTuple!(1, 2, 3, 4) ];
>>
>> // Are there other places that a TypeTuple can be used?
>> }
>>
>> Ali
>
> I'm not sure if it should be considered a separate case, but there is this:
>
> foreach(type; TypeTuple!(ubyte, uint, ulong))
> {
> writeln(type.max);
> }
This works for values too btw:
This creates an explicitly unrolled loop, for example.
a = 1;
foreach(type; TypeTuple!(1, 2, 3))
a *= i;
Or, extracted and simplified from UTF:
private dchar decodeImpl(auto ref S str, ref size_t index)
{
assert(fst & 0x80);
ubyte tmp = void;
dchar d = fst; // upper control bits are masked out later
fst <<= 1;
foreach (i; TypeTuple!(1, 2, 3))
{
tmp = pstr[i];
if ((tmp & 0xC0) != 0x80)
throw invalidUTF();
d = (d << 6) | (tmp & 0x3F);
fst <<= 1;
if (!(fst & 0x80)) // no more bytes
{
d &= bitMask[i]; // mask out control bits
// overlong, could have been encoded with i bytes
if ((d & ~bitMask[i - 1]) == 0)
throw invalidUTF();
// check for surrogates only needed for 3 bytes
static if (i == 2)
{
if (!isValidDchar(d))
throw invalidUTF();
}
index += i + 1;
return d;
}
}
throw invalidUTF();
}
Here, notice that the loop is repeated 3 times, but loop number 2 is statically different from the other loops, by using a "static if (i == 2)"
|
August 16, 2013 Re: Places a TypeTuple can be used | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On 08/16/2013 06:14 AM, Ali Çehreli wrote: > I know of three places a TypeTuple can be used at: > > 1) Function parameter list > > 2) Template parameter list > In fact, no. template A(Seq!(int,int) a){ enum A=a[0]; } // error > 3) Array literal element list > > Are there more? >... I assume you mean just the contexts where it auto-expands in some way? - Declared type of a tuple of variables (or function parameters): Seq!(int,int) x; assert(is(typeof(x[0])==int)&&is(typeof(x[1])==int)); void foo(Seq!(int,int) x); - Function argument list (including struct constructor calls, excluding arguments to overloaded operators): foo(Seq!(1,2)); - Index argument list: a[Seq!(1)] - new argument list(s): new A(Seq!(1,2)); // new!(Seq!(1,2)) A(Seq!(1,2)); // to be deprecated - Parent list: class A: Seq!(B,C){ } - Array literal element list (for completeness of this list): [Seq!(1,2)] I think those might be all usages accepted by DMD. IMO it should work everywhere a comma-separated list of expressions/types is expected. Some arbitrary limitations implemented by DMD: - Arguments to (static) assert statement: assert(Seq!(false, "boom!")); // error - Arguments to mixin statements: mixin(Seq!"int x=2;"); // error - Arguments to overloaded operators: s.opBinary!"+"(Seq!(s,s)); // ok s+Seq!(s,s); // error - Case lists: switch(1){ case Seq!(1,2): break; // error default: break; } - template parameter lists template A(Seq!(int,int) a){ enum A=a[0]; } // error - Second argument to comma expression in valid context: foo((x++,Seq!(1,2))); // error |
August 16, 2013 Re: Places a TypeTuple can be used | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On 08/16/2013 01:09 PM, Timon Gehr wrote:
>
> - Arguments to string mixins:
>
> mixin(Seq!"int x=2;"); // error
fixed.
|
August 16, 2013 Re: Places a TypeTuple can be used | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Friday, 16 August 2013 at 04:14:04 UTC, Ali Çehreli wrote: > ... dlang.org documentation on this topic is quite confusing, unfortunately. There was a small discussion in this http://d.puremagic.com/issues/show_bug.cgi?id=10803 bug report recently where Kenji has surprised me a lot with explanation how this really is intended to work. |
August 16, 2013 Re: Places a TypeTuple can be used | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | On 08/16/2013 04:09 AM, Timon Gehr wrote: > IMO it should work everywhere a comma-separated list of > expressions/types is expected. Exactly. Only then this concept would be easy to understand and explain. It would make "a comma-separated list of expressions/types" a language construct. Done. Thank you everyone. Great information! I am going over the my tuples chapter where TypeTuple appeared briefly with just a unittest example. I am expanding the information there but I will include only the common uses of it. Ali |
Copyright © 1999-2021 by the D Language Foundation