www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Places a TypeTuple can be used

reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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
Aug 15 2013
next sibling parent reply "Meta" <jared771 gmail.com> writes:
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); }
Aug 15 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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
Aug 15 2013
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, August 15, 2013 23:09:55 Ali =C3=87ehreli wrote:
 On 08/15/2013 10:39 PM, Meta wrote:
  > On Friday, 16 August 2013 at 04:14:04 UTC, Ali =C3=87ehreli wrote:=
  >> 1) Function parameter list
  >>=20
  >> 2) Template parameter list
  >>=20
  >> 3) Array literal element list
  >>=20
  >> Are there more?
  >=20
  > I'm not sure if it should be considered a separate case, but there=
is
=20
 this:
  > foreach(type; TypeTuple!(ubyte, uint, ulong))
  > {
  >=20
  >      writeln(type.max);
  >=20
  > }
=20
 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:
=20
      foreach (type; ubyte, uint, ulong) {    // compilation error
That's because what you just wrote is not equivalent to what TypeTuple = is.=20 TypeTuple is an alias for a parameter or argument list, not simply a li= st of=20 types or values. I don't know of a way to write the equivalent in a for= each=20 loop without TypeTuple or some other alias which was the same as TypeTu= ple. - Jonathan M Davis
Aug 15 2013
prev sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
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)"
Aug 16 2013
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, August 15, 2013 21:14:03 Ali =C3=87ehreli wrote:
 I know of three places a TypeTuple can be used at:
=20
 1) Function parameter list
=20
 2) Template parameter list
=20
 3) Array literal element list
=20
 Are there more?
=20
 import std.typetuple;
=20
 void foo(int, string, double)
 {}
=20
 struct S(T, float f)
 {}
=20
 void main()
 {
      // 1) Function parameter list: May not contain types
      foo(TypeTuple!(42, "hello", 1.5));
=20
      // 2) Template parameter list: May contain types
      auto s =3D S!(TypeTuple!(char, 2.5))();
=20
      // 3) Array elements: Elements must be the same type
      auto a =3D [ TypeTuple!(1, 2, 3, 4) ];
=20
      // Are there other places that a TypeTuple can be used?
 }
It can be used in foreach, which essentially makes it a static foreach.= This=20 is extremely useful when unit testing. e.g. foreach(T; TypeTuple!(char[], wchar[], dchar[], string, wstring, dstrin= g)) { assert(stripLeft(to!T(" foo ")) =3D=3D to!T("foo ")); } The code within the foreach is duplicated, because the loop is run at c= ompile=20 time. So, the above code becomes something like {assert(stripLeft(to!(char[])(" foo ")) =3D=3D to!(char[])("foo "));= } {assert(stripLeft(to!(wchar[])(" foo ")) =3D=3D to!(wchar[])("foo ")= );} {assert(stripLeft(to!(dchar[])(" foo ")) =3D=3D to!(dchar[])("foo ")= );} {assert(stripLeft(to!string(" foo ")) =3D=3D to!string("foo "));} {assert(stripLeft(to!wstring(" foo ")) =3D=3D to!wstring("foo "));} {assert(stripLeft(to!dstring(" foo ")) =3D=3D to!dstring("foo "));} You can use TypeTuple in enums, though the enum value would have to be = used in=20 a context that TypeTuples can be used in. You can also alias them. There are probably others, especially when you start messing with templ= ates=20 and parameter lists, but while those use the built-in tuples which Type= Tuple=20 aliases, I can't think of any case at the moment where you would explic= itly=20 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 inst= ead of=20 std.typetuple.TypeTuple, and then it talks about expression tuples vs t= ype=20 tuples (whereas a TypeTuple could be either an expression tuple or a ty= pe=20 tuple), but that just highlights how confusing this is and how badly na= med=20 TypeTuple is (but unfortunately, it's used in so much code now, that re= naming=20 it just isn't going to happen). That article should probably be rewritt= en so=20 that it takes TypeTuple into account. But it does contain some good inf= o if=20 you can properly understand the difference between TypeTuple and a type= tuple. - Jonathan M Davis
Aug 15 2013
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
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
Aug 16 2013
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 08/16/2013 01:09 PM, Timon Gehr wrote:
 - Arguments to string mixins:

 mixin(Seq!"int x=2;"); // error
fixed.
Aug 16 2013
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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
Aug 16 2013
parent reply "Dicebot" <public dicebot.lv> writes:
On Friday, 16 August 2013 at 15:40:35 UTC, Ali Çehreli wrote:
 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.
It does complicate things that sometimes TypeTuple is accepted in cases where comma-separated list does not: import std.typetuple; void main() { //alias TT = TypeTuple!(int, string); //TT twoVars; (int, string) twoVars; // do you expect this to work? static assert(is(typeof(twoVars[0]) == int)); static assert(is(typeof(twoVars[1]) == string)); } The fact that built-in concept of tuple can't be expressed with built-in syntax creates lot of learning issues. In that regard, defining "list of expressions/types" as language construct goes as a solution both ways. I honestly think it is one of the cases where idea "wow, we can have library support for type tuples instead of language support!" has failed with an enormous technical debt.
Aug 16 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/16/2013 09:02 AM, Dicebot wrote:

 It does complicate things that sometimes TypeTuple is accepted in cases
 where comma-separated list does not:

 import std.typetuple;

 void main()
 {
      //alias TT = TypeTuple!(int, string);
      //TT twoVars;
      (int, string) twoVars; // do you expect this to work?
      static assert(is(typeof(twoVars[0]) == int));
      static assert(is(typeof(twoVars[1]) == string));
 }
No, I would not expect that line to work. However, I am totally amazed that your commented-out code works! Wow! :) import std.typetuple; void main() { alias TT = TypeTuple!(int, string); TT twoVars; static assert(is(typeof(twoVars[0]) == int)); static assert(is(typeof(twoVars[1]) == string)); } I am speechless. :) Ali
Aug 16 2013
parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Friday, 16 August 2013 at 21:41:10 UTC, Ali Çehreli wrote:
 import std.typetuple;

 void main()
 {
     alias TT = TypeTuple!(int, string);
     TT twoVars;
     static assert(is(typeof(twoVars[0]) == int));
     static assert(is(typeof(twoVars[1]) == string));
 }

 I am speechless. :)

 Ali
Seeing as TypeTuple aliases itself away on instantiation (There is no such thing as a TypeTuple, only a builtin tuple created with TypeTuple), this is the same principle as void foo(T ...)() { T t = T.init; foreach(el; t) write(el,","); } foo!(int, double)(); //prints: "0,nan"
Aug 16 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
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.
Aug 16 2013
prev sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Aug 15, 2013 at 11:18:21PM -0700, Jonathan M Davis wrote:
[...]
 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
On Fri, Aug 16, 2013 at 02:32:08PM +0200, Dicebot 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.
Argh, can somebody *pretty please* submit a pull to fix the docs? It's things like this that turns newbies away ("What's this? The docs contradict each other! I don't understand this language! Hmm let's look at the next language on the list"). I would do it myself, except that after reading Kenji's notes on #10803 I'm no longer so sure I understand it myself. :-/ T -- One Word to write them all, One Access to find them, One Excel to count them all, And thus to Windows bind them. -- Mike Champion
Aug 16 2013
parent "Dicebot" <public dicebot.lv> writes:
On Friday, 16 August 2013 at 14:15:50 UTC, H. S. Teoh wrote:
 I would do it myself, except that after reading Kenji's notes 
 on #10803
 I'm no longer so sure I understand it myself. :-/
+1 :D
Aug 16 2013