www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - enum and tuples

reply captaindet <2krnk gmx.net> writes:
hi,

i am still struggling getting to grips with tuples, especially typetuples. i
got into this when trying module introspection and the surprise discovery that
__traits(allMembers, .) seems to return a typetuple of strings. (the tuple
article on dlang and philippe's template tutorial do help a bit, but only so
much.)

typetuples seem to live in a shadow world and quite obscurely should be
referred to/passed around via aliases. even though we have alias a = b now i
regard this as an irregularity/oddity of the language, i.e. that they are not
treated the same way as variables/aggregates. anyhow, i started playing a bit
putting them in enums anyway. surprisingly, "storing" tuples and typetuples in
enums is accepted by the compiler. however, while enum tuples seem to behave
normal/useful at compile time and run time, enum'ed typetuples don't like
compile time, but seem to behave at runtime. (i rather would have expected the
other way around). examples further below.

so i guess my questions are
a) if we are not allowed to put typetuples in enums, why is it not an error?
b) if enums are supposed to handle typetuples, why is it not working at compile
time?

/det

module demo;
import std.stdio, std.typetuple, std.typecons;

enum ok = tuple("one", "two", "three");
pragma(msg, ok, ", ", ok[0]);
	// Tuple("one", "two", "three"), one
enum er = TypeTuple!("one", "two", "three");
//  pragma(msg, er);
	// Error: variable _er_field_0,1,2 cannot be read at compile time

void main(){
	writeln("ok: ", ok, " ok[0]: ", ok[0]);
		// ok: Tuple!(string, string, string)("one", "two", "three") ok[0]: one
	writeln("er: ", er, " er[0]: ", er[0]);
		// er: onetwothree er[0]: one
}
Aug 08 2013
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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. I don't answer your questions; the following is some of what I understand so far: import std.stdio; import std.typetuple; void foo(int i, string s, double d) { writefln("foo: %s %s %s", i, s, d); } void main() { // A TypeTuple is nothing but a combination of three separate entities, // loosely kept together. The following is one that is made of three // values: auto var = TypeTuple!(10, "hello", 1.5); // Although it looks like foo is receiving a single entity, because var is // a list of three entities (not actually a single entity of three // things), it matches what foo expects: foo(var); // prints: "foo: 10 hello 1.5" } Mixing values and types in a TypeTuple changes the kind of the TypeTuple and it becomes something different. Let's say I want it to represent the need of "give me a string array of 10 elements". This can be done by a value and a type: auto var = TypeTuple!(10, string); // compilation ERROR Yeah, although TypeTuple!(10, string) is legal syntax, it cannot be used in the same way as a TypeTuple that consists entirely of values. However, although the alias is only for convenience, the following works: alias var = TypeTuple!(10, string); In this case we know that var[1] is a type itself and var[0] is an int value. So, we can use them in that way: alias var = TypeTuple!(10, string); alias ElemType = var[1]; // it is the 'string' type itself auto length = var[0]; // it is 10 auto arr = new ElemType[length]; writeln(arr); // prints ["", "", "", "", "", "", "", "", "", ""] One difference between a TypeTuple that consists merely of values and a TypeTuple that consists at least one type is that the former can be used as a function parameter list as well as a template parameter lest. However, the latter can only be used as a template parameter list. (This is because a type cannot appear as a function argument.) For example, when combined with compile time foreach, the template can test each argument separately with a static if: void bar(T...)() { foreach (arg; T) { static if (is (arg)) { // I have a type auto var = arg.init; writefln("bar has just created a %s.init.", arg.stringof); } else { // I have a value writefln("bar is looking at the value %s.", arg); } } } alias var = TypeTuple!(10, string); bar!var(); /* Prints: bar is looking at the value 10. bar has just created a string.init. */ Ali
Aug 09 2013
next sibling parent reply captaindet <2krnk gmx.net> writes:
On 2013-08-09 11:36, Ali Çehreli wrote:
 as I am in the process of revising and translating a Tuples chapter.
thanks for the reply, Ali. as a matter of fact, i am checking your website regularly, eagerly awaiting the translations of the tuples chapter. and the __traits and the template chapter too ;) your examples make things a bit clearer in general, but not in the specific case of enums. i investigated my enum cases a bit more and it seems that enums of string value typetuples are good-natured expression by far and large, only pragma(msg, X) fails terribly. enum X = TypeTuple!("only", "strings", "here"); // fine everywhere but pragma(msg hovever, enums of integer or float value typetuples throw a phobos error when appearing outside of main(), but work alright within main() enum er = TypeTuple!(1,2,3); // ...\utf.d(1147): Error: cannot cast int to (int, int, int) void main(){ enum er = TypeTuple!(1,2,3); // fine } quite mysterious. /det
Aug 09 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/09/2013 12:41 PM, captaindet wrote:

 On 2013-08-09 11:36, Ali Çehreli wrote:
 as I am in the process of revising and translating a Tuples chapter.
 as a matter of fact, i am checking your website regularly, eagerly
 awaiting the translations of the tuples chapter. and the __traits and
 the template chapter too ;)
I am very happy to hear that. It also makes me sad because I have been very slow this summer. :-/ In fact, I was in the middle of translating the "More Templates" chapter that I realized I should move tuples before that one. I further realized that TypeTuple deserves more information than a couple of paragraphs and a trivial use in a unittest. ;) And that's when I realized that TypeTuple is a very strange beast indeed. Ali
Aug 09 2013
parent "Dejan Lekic" <dejan.lekic gmail.com> writes:
On Friday, 9 August 2013 at 21:24:30 UTC, Ali Çehreli wrote:
 On 08/09/2013 12:41 PM, captaindet wrote:

 On 2013-08-09 11:36, Ali Çehreli wrote:
 as I am in the process of revising and translating a Tuples
chapter.
 as a matter of fact, i am checking your website regularly,
eagerly
 awaiting the translations of the tuples chapter. and the
__traits and
 the template chapter too ;)
I am very happy to hear that. It also makes me sad because I have been very slow this summer. :-/ In fact, I was in the middle of translating the "More Templates" chapter that I realized I should move tuples before that one. I further realized that TypeTuple deserves more information than a couple of paragraphs and a trivial use in a unittest. ;) And that's when I realized that TypeTuple is a very strange beast indeed. Ali
I could not agree more. TypeTuple is IMHO one of the coolest features that is so underrated! Btw, Ali, everybody loves your book anyway. I recommend the section about Ranges to everyone. :D Keep up with the good work!
Aug 10 2013
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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.
Aug 09 2013
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/09/2013 10:41 AM, H. S. Teoh wrote:

 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".
Thank you and Jonathan. The above is exactly what helped me understand them finally. Your explanation matches my understanding exactly.
 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.
That was the missing piece of the puzzle for me. And a very important point to make is that "the list of function/template arguments" are not TypeTuples. TypeTuple is just a tool that makes them available to the code. Thank you, Ali
Aug 10 2013
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, August 09, 2013 10:41:05 H. S. Teoh wrote:
 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.
[snip]
 Hope this helps! :)
I think that you have it at least mostly right, though I skimmed over most of it, so you might have a minor detail wrong somewhere. The compiler's tuples (TypeTuples) are basically what template and function parameter and argument lists are. TypeTuple itself is then just an alias for them so that you can actually declare and refer to them directly. It's kind of a travesty that they're referred to as tuples, and I really wish that they'd stop being referred to as that, but Walter keeps using the term tuple for them. Personally, I just always call them TypeTuples (as bad as that name is), though technically TypeTuple is just the alias. Regardless, they're completely a compile-time construct, unlike std.typecons.Tuple, which is a real tuple type. Really, the problem is the terminology used. It makes it all way more confusing than it should be. - Jonathan M Davis
Aug 09 2013
prev sibling next sibling parent "anonymous" <anonymous example.com> writes:
On Friday, 9 August 2013 at 06:16:20 UTC, captaindet wrote:
 a) if we are not allowed to put typetuples in enums, why is it 
 not an error?
[...]
 enum er = TypeTuple!("one", "two", "three");
FWIW, it's an error in the current git head dmd: "Error: cannot cast "one" to (string, string, string) at compile time".
Aug 09 2013
prev sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, August 09, 2013 01:16:12 captaindet wrote:
 module demo;
 import std.stdio, std.typetuple, std.typecons;
 
 enum ok = tuple("one", "two", "three");
 pragma(msg, ok, ", ", ok[0]);
 // Tuple("one", "two", "three"), one
 enum er = TypeTuple!("one", "two", "three");
 // pragma(msg, er);
 // Error: variable _er_field_0,1,2 cannot be read at compile time
I'm pretty sure that this is just a bad error message.
 void main(){
 writeln("ok: ", ok, " ok[0]: ", ok[0]);
 // ok: Tuple!(string, string, string)("one", "two", "three") ok[0]: 
one
 writeln("er: ", er, " er[0]: ", er[0]);
 // er: onetwothree er[0]: one
 }
What I expect is happening is that TypeTuples don't convert to string, so the pragma fails, but in the writeln, because writeln is variadic, it unrolls the TypeTuple, giving you writeln("er: ", er[0], er[1], er[2]], "er[0]: ", er[0]); and that works just fine, as each individual element in er converts to string just fine (particularly since they actually _are_ strings in this case). - Jonathan M Davis
Aug 09 2013
parent reply "captaindet" <2krnk gmx.net> writes:
 I'm pretty sure that this is just a bad error message.

 void main(){
 writeln("ok: ", ok, " ok[0]: ", ok[0]);
 // ok: Tuple!(string, string, string)("one", "two", "three") 
 ok[0]:
one
 writeln("er: ", er, " er[0]: ", er[0]);
 // er: onetwothree er[0]: one
 }
What I expect is happening is that TypeTuples don't convert to string, so the pragma fails,
hmm, but it is a TypeTuple of strings and aren't they supposed to automatically expand? and pragma(msg, ...) takes various arguments, e.g. pragma(msg, "this", "and", "that"); so is it just a bad error message or a "bug" in pragma(msg, ...)? (..,i know, pragmas are difficult to blame for anything as they are not part of the language proper. but in lieu of a compile time print this is all we got for debugging our meta stuff.) then there is the thing of assigning value type TypeTuples to variables/enums. is this allowed or not? see my observations regarding enums which are for 2.063.2. according to anonymous in the git head for 2.064 the enum example for string value TypeTuples now fails...i don't think any of this behavior is documented anywhere. what i think is missing is a clearly defined boundary/set of rules for what we can do with the internal "tuples" (aka TypeTuples) and how, and what not. /det
Aug 10 2013
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, August 11, 2013 07:24:52 captaindet wrote:
 I'm pretty sure that this is just a bad error message.
 
 void main(){
 writeln("ok: ", ok, " ok[0]: ", ok[0]);
 // ok: Tuple!(string, string, string)("one", "two", "three")
 ok[0]:
one
 writeln("er: ", er, " er[0]: ", er[0]);
 // er: onetwothree er[0]: one
 }
What I expect is happening is that TypeTuples don't convert to string, so the pragma fails,
hmm, but it is a TypeTuple of strings and aren't they supposed to automatically expand? and pragma(msg, ...) takes various arguments, e.g. pragma(msg, "this", "and", "that"); so is it just a bad error message or a "bug" in pragma(msg, ...)? (..,i know, pragmas are difficult to blame for anything as they are not part of the language proper. but in lieu of a compile time print this is all we got for debugging our meta stuff.) then there is the thing of assigning value type TypeTuples to variables/enums. is this allowed or not? see my observations regarding enums which are for 2.063.2. according to anonymous in the git head for 2.064 the enum example for string value TypeTuples now fails...i don't think any of this behavior is documented anywhere. what i think is missing is a clearly defined boundary/set of rules for what we can do with the internal "tuples" (aka TypeTuples) and how, and what not.
I don't know why you're seeing the problems that you're seeing pragma(msg, "this", "and", "that"); seems to work, so I'd have expected the TypeTuple to work. I expect that it's a compiler bug. And yes, TypeTuples should definitely be assignable to enums (though where you can use such an enum depends on where you can use a TypeTuple - the enum's value is essentially copy-pasted wherever the enum is used). I think that things are far more confusing for you due to compiler bugs. - Jonathan M Davis
Aug 10 2013
parent captaindet <2krnk gmx.net> writes:
On 2013-08-11 01:59, Jonathan M Davis wrote:
 seems to work, so I'd have expected the TypeTuple to work. I expect that it's
 a compiler bug. And yes, TypeTuples should definitely be assignable to enums
 (though where you can use such an enum depends on where you can use a
 TypeTuple - the enum's value is essentially copy-pasted wherever the enum is
 used). I think that things are far more confusing for you due to compiler
 bugs.
thanks jonathan. yours and ali's explanations have been very helpful to understand what is going on. i filed a bug report: http://d.puremagic.com/issues/show_bug.cgi?id=10803 /det
Aug 11 2013