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









"bearophile" <bearophileHUGS lycos.com> 