digitalmars.D.learn - CTFE & enums & static assert
- =?iso-8859-1?Q?Robert_M._M=FCnch?= (13/13) May 04 2015 I find this a bit strange:
- ketmar (9/22) May 04 2015 that's due to `enum` keyword abusing. "enum type" is something like this...
- =?iso-8859-1?Q?Robert_M._M=FCnch?= (28/39) May 04 2015 Hmm... Ok, I understand that these seems to be two different things.
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (45/61) May 04 2015 There are many different kinds of tuples in D, only two of which I can
- =?iso-8859-1?Q?Robert_M._M=FCnch?= (12/30) May 15 2015 Is there a way I can build an ENUM from within the FOREACH? What I want
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (34/51) May 15 2015 Sorry, I don't understand your question. :(
- =?iso-8859-1?Q?Robert_M._M=FCnch?= (38/51) May 18 2015 Hi, yes to both. I have solved it now like this:
- ketmar (10/24) May 04 2015 `typeid` is runtime thing, you can't use it in compile-time.
- =?iso-8859-1?Q?Robert_M._M=FCnch?= (8/13) May 05 2015 No, that makes it much more clearer for me. The compiler should print
I find this a bit strange: // get all rules that start with p... enum BolRules = StaticFilter!(beginsWithP, __traits(allMembers,BolSource)); static assert(is(BolRules == enum)); Compiling using dmd... source/app.d(114): Error: static assert (is(BolRules == enum)) is false I'm trying to construct an enum that can be used in a "final switch" to check if all cases were handled. But so far it's not working, because I can't get the enum constructed. -- Robert M. Münch http://www.saphirion.com smarter | better | faster
May 04 2015
On Mon, 04 May 2015 18:21:59 +0200, Robert M. M=C3=BCnch wrote:I find this a bit strange: =20 // get all rules that start with p... enum BolRules =3D StaticFilter!(beginsWithP, __traits(allMembers,BolSource)); static assert(is(BolRules =3D=3D enum)); =20 Compiling using dmd... source/app.d(114): Error: static assert (is(BolRules =3D=3D enum)) is fa=lse=20 I'm trying to construct an enum that can be used in a "final switch" to check if all cases were handled. But so far it's not working, because I can't get the enum constructed.that's due to `enum` keyword abusing. "enum type" is something like this: enum MyEnum { A, B } and enum val =3D false; is a compile-time boolean constant, which will be inlined on using. i.e.=20 compiler will inline such "enum constants", and that constants has the=20 corresponding type, they aren't enums.=
May 04 2015
On 2015-05-04 17:21:34 +0000, ketmar said:that's due to `enum` keyword abusing. "enum type" is something like this: enum MyEnum { A, B } and enum val = false; is a compile-time boolean constant, which will be inlined on using. i.e. compiler will inline such "enum constants", and that constants has the corresponding type, they aren't enums.Hmm... Ok, I understand that these seems to be two different things. Not sure if I now understand this correct then: enum A {a, b, c}; enum members1 = __traits(allMembers, A); auto members2 = __traits(allMembers, A); pragma(msg, typeof(members1)); pragma(msg, typeid(members1)); pragma(msg, typeof(members2)); pragma(msg, typeid(members2)); Gives this: (string, string, string) playground.d(9): Error: no type for typeid(members1) playground.d(9): while evaluating pragma(msg, typeid(members1)) (string, string, string) playground.d(12): Error: no type for typeid(members2) playground.d(12): while evaluating pragma(msg, typeid(members2)) 1. So the (string, string, string) output is based on the expression of members1? Meaning, the right-hand-side. 2. I'm wondering why members1 doesn't has a type at all. So, we don't have a compile-time boolean? 3. For members2, where auto is used, I would expect that the return type of "allMembers" is used. Which would be a tuple. But again, no type for members2. Which I find quite strange. -- Robert M. Münch http://www.saphirion.com smarter | better | faster
May 04 2015
On 05/04/2015 11:07 AM, Robert M. Münch wrote:enum A {a, b, c}; enum members1 = __traits(allMembers, A); auto members2 = __traits(allMembers, A);1. So the (string, string, string) output is based on the expression of members1? Meaning, the right-hand-side.There are many different kinds of tuples in D, only two of which I can handle: 1) Tuple from std.typecons, which are ordinarily created at run time 2) TypeTuple from std.typetuple, which are compile-time entities The documentation is not clear that __traits(allMembers) returns a TypeTuple, which additionally has a bad name. TypeTuple is great because it enables "compile-time foreach" (unfortunately, implicitly): foreach (m; __traits(allMembers, A)) { // This body is repeated for each member at compile time } It is also possible to expand members of a TypeTuple just by putting it inside an array: [ __traits(allMembers, A) ]On 05/04/2015 11:07 AM, Robert M. Münch wrote:enum A {a, b, c}; enum members1 = __traits(allMembers, A); auto members2 = __traits(allMembers, A);1. So the (string, string, string) output is based on the expression of members1? Meaning, the right-hand-side.There are many differents kinds of tuples in D, only two of which I can handle: 1) Tuple from std.typecons, which are ordinarily created at run time 2) TypeTuple from std.typetuple, which are compile-time entities The documentation is not clear that __traits(allMembers) returns a TypeTuple, which additionally has a bad name. TypeTuple is great because it enables "compile-time foreach" (unfortunately, implicitly): foreach (m; __traits(allMembers, A)) { // This body is repeated for each member at compile time } It is also possible to expand members of a TypeTuple just by putting it inside an array: [ __traits(allMembers, A) ] However, it should be obvious that all members must have a common type to be members of the same array. (True to its name, TypeTuple can have types themselves as well.) Powerful stuff. :)2. I'm wondering why members1 doesn't has a type at all.Because it is a TypeTuple of values of various types and even types themselves.So, we don't have a compile-time boolean?I don't understand that one. :( Ali However, it should be obvious that all members must have a common type to be members of the same array. (True to its name, TypeTuple can have types themselves as well.) Powerful stuff. :)2. I'm wondering why members1 doesn't has a type at all.Because it is a TypeTuple of values of various types and even types themselves.So, we don't have a compile-time boolean?I don't understand that one. :( Ali
May 04 2015
On 2015-05-04 18:22:17 +0000, Ali Çehreli said:There are many different kinds of tuples in D, only two of which I can handle: 1) Tuple from std.typecons, which are ordinarily created at run time 2) TypeTuple from std.typetuple, which are compile-time entities The documentation is not clear that __traits(allMembers) returns a TypeTuple, which additionally has a bad name. TypeTuple is great because it enables "compile-time foreach" (unfortunately, implicitly): foreach (m; __traits(allMembers, A)) { // This body is repeated for each member at compile time }Is there a way I can build an ENUM from within the FOREACH? What I want to achive is, that I would like to use: final switch (myEnum) ... and have myEnum build at compiletime. With this the compiler would give an error whenever I have forgotten to update my code to handle a new case.> 2. I'm wondering why members1 doesn't has a type at all. Because it is a TypeTuple of values of various types and even types themselves.But shouldn't be the type than be "TypeTuple"? -- Robert M. Münch http://www.saphirion.com smarter | better | faster
May 15 2015
On 05/15/2015 09:45 AM, Robert M. Münch wrote:On 2015-05-04 18:22:17 +0000, Ali Çehreli said:Sorry, I don't understand your question. :( Do you want to define an enum at compile time? Then you can use mixins. Do you want to build an enum value inside the foreach? Yes, it is possible as well.TypeTuple is great because it enables "compile-time foreach" (unfortunately, implicitly): foreach (m; __traits(allMembers, A)) { // This body is repeated for each member at compile time }Is there a way I can build an ENUM from within the FOREACH? What I want to achive is, that I would like to use: final switch (myEnum) ...and have myEnum build at compiletime. With this the compiler would give an error whenever I have forgotten to update my code to handle a newcase. I need a code example. Sorry. :(A TypeTuple can contain types and values, which can be checked at compile time: import std.stdio; import std.typetuple; // A function template void foo(T...)() { foreach (i, a; T) { static if (is (a)) { writefln("Argument %s is a type: %s", i, a.stringof); } else { writefln("Argument %s is not : %s", i, a.stringof); } } } // Another one: void bar(T, size_t N)() { T[N] arr; } void main() { alias args = TypeTuple!(int, 42); foo!args(); bar!args(); } Ali> 2. I'm wondering why members1 doesn't has a type at all. Because it is a TypeTuple of values of various types and even types themselves.But shouldn't be the type than be "TypeTuple"?
May 15 2015
On 2015-05-15 17:26:50 +0000, Ali Çehreli said:On 05/15/2015 09:45 AM, Robert M. Münch wrote: > Is there a way I can build an ENUM from within the FOREACH? What I want > to achive is, that I would like to use: > > final switch (myEnum) ... Sorry, I don't understand your question. :( Do you want to define an enum at compile time? Then you can use mixins. Do you want to build an enum value inside the foreach? Yes, it is possible as well.Hi, yes to both. I have solved it now like this: enum A {a, b, c}; enum members1 = __traits(allMembers, A); // returns TypeTuple // function that generates a string which is used as a mixin at compile time // result string must conform to syntax as it was hand-written code string generateEnum(T...)(string type){ string code = "enum " ~ type ~ " {"; // this is a static foreach (compile time) foreach(m; T){ debug pragma(msg, m ~ ","); // check what code we get at compile time code ~= m ~ ","; } return(code ~ "}"); } int main(){ A switch_var_a; final switch(switch_var_a){ case A.a: case A.b: case A.c: } mixin(generateEnums!members1("B")); B switch_var_b; final switch(switch_var_b){ case B.a: // case B.b: // if commeted will cause a compiler error case B.c: } return(0); } So, the solution was to use a "string mixin". IMO it's a very powerful pattern to build an ENUM at compile time that can be used with a FINAL SWITCH. -- Robert M. Münch http://www.saphirion.com smarter | better | faster
May 18 2015
On Mon, 04 May 2015 20:07:27 +0200, Robert M. M=C3=BCnch wrote:=20 Gives this: =20 (string, string, string) playground.d(9): Error: no type for typeid(members1) playground.d(9): while evaluating pragma(msg, typeid(members1))`typeid` is runtime thing, you can't use it in compile-time. besides, as Ali said, `allMembers` returns tuple, which is very special=20 thing that exists only in compile-time.1. So the (string, string, string) output is based on the expression of members1? Meaning, the right-hand-side.that's three field names for `enum A`. and field name is a string.2. I'm wondering why members1 doesn't has a type at all. So, we don't have a compile-time boolean?it's a tuple. actually, `(string, string, string)` is a special type.3. For members2, where auto is used, I would expect that the return type of "allMembers" is used.it is. ;-)Which would be a tuple. But again, no type for members2. Which I find quite strange.as i said, `typeid` is runtime feature, so you can't print it with pragma.=20 and tuples aren't exist in runtime, it's compile-time only. i think you are even more confused now. ;-) sorry.=
May 04 2015
On 2015-05-04 22:22:51 +0000, ketmar said:as i said, `typeid` is runtime feature, so you can't print it with pragma. and tuples aren't exist in runtime, it's compile-time only. i think you are even more confused now. ;-) sorry.No, that makes it much more clearer for me. The compiler should print it: "No type. typeid() is run-time only." And everything would be clear. -- Robert M. Münch http://www.saphirion.com smarter | better | faster
May 05 2015