On Fri, Aug 09, 2013 at 09:36:16AM -0700, Ali Çehreli wrote: > On 08/08/2013 11:16 PM, captaindet wrote:> hi, > > > i am still struggling getting to grips with tuples, especially > > typetuples. > > Yes, especially TypeTuples. :) > > > typetuples seem to live in a shadow world > > My feelings! :) > > Coincidentally, I am struggling with the same question at the moment > as I am in the process of revising and translating a Tuples chapter. > I got stuck just yesterday but I have not re-read Philippe Sigaud's > document yet. [...]
According to my understanding (please correct me if I'm wrong), there are two *different* kinds of tuples, which may be the source of much of the confusion surrounding tuples. 1) There's the built-in tuple, which is a compiler concept, and basically means any sequential collections of "things" (for lack of a better word). For example, you can have a sequence of types, like (int, string, float), or a sequence of values, like (1, "a", 3.0), or even a mixture of both, like (1, int, "a", float, string, 3.14). These sequences are called "tuples". They have no direct representation in the language's syntax, but they are an underlying concept that exists in the language specs and in the compiler. This concept allows us to deal with variadic functions/templates in a nice way: we abstract away the list of function/template arguments and say those arguments are tuples, so then if something else produces or returns a tuple, then we can plug that in where a parameter list would be expected. This allows us to construct templates the perform various manipulations on tuples, like reordering elements, filtering elements, etc.. These "internal tuples", if you wish to call them that, behave almost like arrays -- they have .length, and you can dereference them with array indexing notation like t[0], t[1], which is what happens when you write a variadic function: auto f(T...)(T args) { // args is a tuple containing function arguments auto a = args[0]; // a = 1, when called from main() below auto b = args[1]; // b = "a" auto c = args[2]; // c = 3.14 auto n = args.length; // n = 3, there are 3 arguments } void main() { f(1, "a", 3.14); } However, unlike arrays, tuples are not full-fledged runtime objects; you can't manipulate them at runtime like real arrays, and any loop over them is always unrolled at compile-time (because each tuple element may be a different type, so it's not possible to have the same loop body in machine code to process every element). 2) Phobos defines a tuple() function, that wraps an internal tuple of values inside a struct called Tuple. This allows a nicer interface to work with tuples of values, since you can explicitly create them, pass them around like runtime objects, etc.. They are more like structs with anonymous members, if you like, which are accessed with array indexing notation. They are NOT the same as internal tuples (though their implementation uses internal tuples), so you can't pass them to variadic functions and expect them to behave the same way (though I believe there *is* a method that returns the internal tuple out of a Tuple struct, so you can use that to get at the "raw" tuple when you need to). Phobos' TypeTuples (in std.typetuple), I believe, are basically just an alias that allows you to explicitly declare and use the internal tuples, so they are basically the same as (1). Hope this helps! :) T -- Guns don't kill people. Bullets do.