digitalmars.D.learn - iterate over enum name:value pairs
- Jay Norwood (14/14) Dec 07 2013 In Ali Çehreli very nice book there is this example of iterating
- bearophile (31/45) Dec 07 2013 min and max of enumeratinos are traps, I don't use them.
- Jay Norwood (26/26) Dec 07 2013 Thanks. This is exactly what I was looking for.
- bearophile (8/10) Dec 08 2013 Here 'i' is the index of the enumeration type tuple.
- Jay Norwood (33/33) Dec 08 2013 I see comments about enums being somehow implemented as tuples,
- bearophile (21/29) Dec 08 2013 Enums are usually implemented as ints, unless you specify a
- Jay Norwood (51/51) Dec 08 2013 Yes, thanks, that syntax does work for the initialization.
- bearophile (16/27) Dec 08 2013 Giving a struct a name is often a good idea. But if you don't
- bearophile (4/5) Dec 08 2013 Sometimes you have to use:
- Jay Norwood (26/30) Dec 08 2013 yeah, that's pretty nice.
- bearophile (31/39) Dec 08 2013 You have missed my suggestions above regarding the struct :-)
- bearophile (6/12) Dec 08 2013 Also, in D it's better to put a space after every comma, to
- Jay Norwood (41/41) Dec 08 2013 It looks like the writeln() does a pretty good job, even for enum
- bearophile (19/26) Dec 08 2013 In some cases you can also use with() to avoid struct/enum name
- Jay Norwood (5/17) Dec 08 2013 Thanks. That's looking pretty clean.
- Jay Norwood (5/20) Dec 08 2013 I notice that if Suit and SuitShort have an enum with the same
- bearophile (5/10) Dec 09 2013 Yes, that's named anti-shadowing, the D type system tried to
In Ali Çehreli very nice book there is this example of iterating over enum range which, as he notes, fails http://ddili.org/ders/d.en/enum.html enum Suit { spades, hearts, diamonds, clubs } foreach (suit; Suit.min .. Suit.max) { writefln("%s: %d", suit, suit); } spades: 0 hearts: 1 diamonds: 2 ← clubs is missing It seems like there is interest in iterating over the name:value pairs of an enum. Is this is already available with some D programming trick?
Dec 07 2013
Jay Norwood:In Ali Çehreli very nice book there is this example of iterating over enum range which, as he notes, fails http://ddili.org/ders/d.en/enum.html enum Suit { spades, hearts, diamonds, clubs } foreach (suit; Suit.min .. Suit.max) { writefln("%s: %d", suit, suit); } spades: 0 hearts: 1 diamonds: 2 ← clubs is missing It seems like there is interest in iterating over the name:value pairs of an enum. Is this is already available with some D programming trick?min and max of enumeratinos are traps, I don't use them. enum Suit { spades = -10, hearts = 10 } Here max and min are worse than useless to list the enumeration members. Also don't define "max" and "min" as members of the enumeration, because this causes a silent silly name clash: enum Suit { spades, hearts, max, min, diamonds, clubs } This is how you usually iterate them: void main() { import std.stdio, std.traits; enum Suit { spades, hearts, diamonds, clubs } foreach (immutable suit; [EnumMembers!Suit]) writefln("%s: %d", suit, suit); } But keep in mind that too has a trap: void main() { import std.stdio, std.traits; enum Suit { spades = 0, hearts = 1, diamonds = 1, clubs = 2 } foreach (immutable suit; [EnumMembers!Suit]) writefln("%s: %d", suit, suit); } Prints: spades: 0 hearts: 1 hearts: 1 clubs: 2 There are cases where the supposed "strong typing" of D is a joke :-) Try to do the same things with Ada enumerations. Bye, bearophile
Dec 07 2013
Thanks. This is exactly what I was looking for. I tried this iteration below, based on the example shown in the std.traits documentation, and the int values are not what I expected, but your example works fine. import std.traits; void main() { enum Suit { spades, hearts=4, diamonds=10, clubs } foreach (i, member; EnumMembers!Suit) { writefln("%s: %d", member, i); } } D:\dprojects\ConsoleApp1\ConsoleApp1>dmd -run main.d spades: 0 hearts: 1 diamonds: 2 clubs: 3 but the same example, substituting writefln("%s: %d", member, member) prints D:\dprojects\ConsoleApp1\ConsoleApp1>dmd -run main.d spades: 0 hearts: 4 diamonds: 10 clubs: 11
Dec 07 2013
Jay Norwood:enum Suit { spades, hearts=4, diamonds=10, clubs } foreach (i, member; EnumMembers!Suit)Here 'i' is the index of the enumeration type tuple. This code lacks the [] I added in my code, so your foreach is a static one. To tell them apart when I read the code I sometimes add a comment: /*static*/ foreach (i, member; EnumMembers!Suit) Bye, bearophile
Dec 08 2013
I see comments about enums being somehow implemented as tuples, and comments about tuples somehow being implemented as structs, but I couldn't find examples of static initialization of arrays of either. Finally after playing around with it for a while, it appears this example below works for static array of struct initialization. It also doesn't display the enum bug of hearts2 coming back as hearts in the iteration. I tried C static array of struct initialization syntax, and it didn't work, which kind of surprises me. module main; import std.stdio; void main() { struct Suit {string nm; int val;}; static Suit[5] suits = [ Suit("spades",1), Suit("hearts",4), Suit("hearts2",4), Suit("diamonds",10), Suit("clubs",11) ]; foreach (member; suits) { writefln("%s: %d", member.nm, member.val); } } D:\dprojects\ConsoleApp1\ConsoleApp1>dmd -run main.d spades: 1 hearts: 4 hearts2: 4 diamonds: 10 clubs: 11
Dec 08 2013
Jay Norwood:I see comments about enums being somehow implemented as tuples,Enums are usually implemented as ints, unless you specify a different type.and comments about tuples somehow being implemented as structs,Phobos Tuples are implemented with structs.but I couldn't find examples of static initialization of arrays of either.Here it is: import std.typecons; enum Foo { A, B, C } Foo[] a1 = [Foo.A, Foo.B]; alias T = Tuple!(int, int); T[] a1 = [T(1, 2), T(3, 4)]; void main() {}It also doesn't display the enum bug of hearts2 coming back as hearts in the iteration.Because those are different strings.I tried C static array of struct initialization syntax, and it didn't work, which kind of surprises me.Here it is: void main() { static struct Suit { string nm; int val; } static Suit[5] suits = [ {"spades", 1}, {"hearts", 4}]; } Bye, bearophile
Dec 08 2013
Yes, thanks, that syntax does work for the initialization. The C syntax that failed for me was using the curly brace form shown in the following link. http://www.c4learn.com/c-programming/c-initializing-array-of-structure/ Also, I think I was trying forms of defining the struct and initializing the array in the same line... something like this C: static struct Suit{ int i; long lv;} suits[3] = {{1, 2L},{2, 4L},{3,9L}}; It looks to me like D requires a named struct definition in a separate line from the array definition. If that is so, then the C initialization of an array with an unnamed struct type, like this, would require a struct type name. static struct { int i; long lv;} suits[3] = {{1, 2L},{2, 4L},{3,9L}}; So, from your static intialization example, this works. Also, the conversion of struct to tuple makes the writefln tupleof conversion on the struct a little cleaner, since you only have to specify the single tuple parameter. module main; import std.stdio; void main() { struct Suit {string nm; int val; int val2; string shortNm;}; static Suit[5] suits = [ {"spades",1,6,"spd"}, {"hearts",4,10,"hrt"}, {"hearts2",4,10,"hrt2"}, {"diamonds",10,16,"dmd"}, {"clubs",11,17,"clb"} ]; foreach (member; suits) { auto tup = member.tupleof; writefln("%s %d %d %s", tup); } } prints spades 1 6 spd hearts 4 10 hrt hearts2 4 10 hrt2 diamonds 10 16 dmd clubs 11 17 clb I also tried using writefln(tup) and writeln(tup) in the example above. The output from writeln(tup) looks like it is headed in the right direction. Maybe a writecsv(tup) would be useful. spades16spd hearts410hrt hearts2410hrt2 diamonds1016dmd clubs1117clb
Dec 08 2013
Jay Norwood:If that is so, then the C initialization of an array with an unnamed struct type, like this, would require a struct type name. static struct { int i; long lv;} suits[3] = {{1, 2L},{2, 4L},{3,9L}};Giving a struct a name is often a good idea. But if you don't want to name it, then you can use a Phobos Tuple. You can even omit its field names if you want.struct Suit {string nm; int val; int val2; string shortNm;};Better: static struct Suit {string nm; int val; int val2; string shortNm;} Generally inside functions it's better to define static struct. And struct definitions don't need a trailing semicolon.foreach (member; suits)Generally it's better to attach an 'immutable' there, this is not always possible, but it's a good habit: foreach (immutable member; suits)I also tried using writefln(tup) and writeln(tup) in the example above. The output from writeln(tup) looks like it is headed in the right direction. Maybe a writecsv(tup) would be useful.Try: member.writeln; Bye, bearophile
Dec 08 2013
foreach (immutable member; suits)Sometimes you have to use: foreach (const member; suits) Bye, bearophile
Dec 08 2013
On Sunday, 8 December 2013 at 22:30:25 UTC, bearophile wrote:Try: member.writeln; Bye, bearophileyeah, that's pretty nice. module main; import std.stdio; void main() { struct Suit {string nm; int val; int val2; string shortNm;}; static Suit[5] suits = [ {"spades",1,6,"spd"}, {"hearts",4,10,"hrt"}, {"hearts2",4,10,"hrt2"}, {"diamonds",10,16,"dmd"}, {"clubs",11,17,"clb"} ]; foreach (immutable member; suits) { member.writeln(); } } output: immutable(Suit)("spades", 1, 6, "spd") immutable(Suit)("hearts", 4, 10, "hrt") immutable(Suit)("hearts2", 4, 10, "hrt2") immutable(Suit)("diamonds", 10, 16, "dmd") immutable(Suit)("clubs", 11, 17, "clb")
Dec 08 2013
Jay Norwood:struct Suit {string nm; int val; int val2; string shortNm;};You have missed my suggestions above regarding the struct :-) Look at this: void main() { int x; struct Foo1 { int bar1() { return x; } } pragma(msg, Foo1.sizeof); static struct Foo2 { // this gives an error int bar2() { return x; } } pragma(msg, Foo2.sizeof); } bar2() gives an error because it can't access x. If you comment out the bar2 line, the output is: 4u 1u Usually you don't want your struct defined inside a function to contain a pointer to the enclosing function.static Suit[5] suits = [ {"spades",1,6,"spd"}, {"hearts",4,10,"hrt"}, {"hearts2",4,10,"hrt2"}, {"diamonds",10,16,"dmd"}, {"clubs",11,17,"clb"} ];Unless you have to mutate the contents of a variable, like your suits, define it const or immutable: static immutable Suit[5] suits = [ {"spades",1,6,"spd"}, ... ]; Generally in D add const/immutable to all variables that you don't need to mutate, if/where you can. Bye, bearophile
Dec 08 2013
Also, in D it's better to put a space after every comma, to increase readability a little: static immutable Suit[5] suits = [ {"spades", 1, 6, "spd"}, Bye, bearophilestatic Suit[5] suits = [ {"spades",1,6,"spd"}, {"hearts",4,10,"hrt"}, {"hearts2",4,10,"hrt2"}, {"diamonds",10,16,"dmd"}, {"clubs",11,17,"clb"}
Dec 08 2013
It looks like the writeln() does a pretty good job, even for enum names. I also saw a prettyprint example that prints the structure member name, and compared its output. http://forum.dlang.org/thread/ip23ld$93u$1 digitalmars.com module main; import std.stdio; import std.traits; void main() { enum Suit { spades, hearts=4, diamonds=10, clubs } enum SuitShort { spd, hrt=4, dmd=10, clb } static struct Suits { Suit nm; int val; int val2; SuitShort shortNm;} static Suits[] suits = [ {Suit.spades, 1, 6, SuitShort.spd}, {Suit.hearts, 4, 10, SuitShort.hrt}, {Suit.diamonds, 4, 10, SuitShort.dmd}, {Suit.clubs, 10, 16, SuitShort.clb} ]; foreach (immutable member; suits) { auto fields = __traits(allMembers, typeof(member)); auto values = member.tupleof; foreach (index, value; values) { writef("%s=%s, ", fields[index], value); } writeln(); member.writeln(); } } output: nm=spades, val=1, val2=6, shortNm=spd, immutable(Suits)(spades, 1, 6, spd) nm=hearts, val=4, val2=10, shortNm=hrt, immutable(Suits)(hearts, 4, 10, hrt) nm=diamonds, val=4, val2=10, shortNm=dmd, immutable(Suits)(diamonds, 4, 10, dmd) nm=clubs, val=10, val2=16, shortNm=clb, immutable(Suits)(clubs, 10, 16, clb)
Dec 08 2013
Jay Norwood: Using enums, despite their problems, if often better than strings.static Suits[] suits = [ {Suit.spades, 1, 6, SuitShort.spd}, {Suit.hearts, 4, 10, SuitShort.hrt}, {Suit.diamonds, 4, 10, SuitShort.dmd}, {Suit.clubs, 10, 16, SuitShort.clb} ]; foreach (immutable member; suits)In some cases you can also use with() to avoid struct/enum name repetitions (unfortunately it creates a scope, so if you define an immutable variable inside it, it will be invisible and destroyed once the with() scope ends. This reduces the usefulness of with()). with (Suit) with (SuitShort) { static Suits[] suits = [ {spades, 1, 6, spd}, {hearts, 4, 10, hrt}, {diamonds, 4, 10, dmd}, {clubs, 10, 16, clb} ]; foreach (immutable member; suits) ... Bye, bearophile
Dec 08 2013
Thanks. That's looking pretty clean. I had already tried the shorter enum names without using the with statement, and it failed to compile. I thought it might work since the struct definition already specifies the enum type for the two members.with (Suit) with (SuitShort) { static Suits[] suits = [ {spades, 1, 6, spd}, {hearts, 4, 10, hrt}, {diamonds, 4, 10, dmd}, {clubs, 10, 16, clb} ]; foreach (immutable member; suits) ... Bye, bearophile
Dec 08 2013
I notice that if Suit and SuitShort have an enum with the same name, then you still have to fully qualify the enum names when using the with statement. So, for example, if spd in SuitShort was renamed spades, the first entry in the array initialization would have to be {Suit.spades, 1, 6, SuitShort.spades}.with (Suit) with (SuitShort) { static Suits[] suits = [ {spades, 1, 6, spd}, {hearts, 4, 10, hrt}, {diamonds, 4, 10, dmd}, {clubs, 10, 16, clb} ]; foreach (immutable member; suits) ... Bye, bearophile
Dec 08 2013
Jay Norwood:I notice that if Suit and SuitShort have an enum with the same name, then you still have to fully qualify the enum names when using the with statement. So, for example, if spd in SuitShort was renamed spades, the first entry in the array initialization would have to be {Suit.spades, 1, 6, SuitShort.spades}.Yes, that's named anti-shadowing, the D type system tried to avoid such bugs in your code. Bye, bearophile
Dec 09 2013