Jump to page: 1 2
Thread overview
iterate over enum name:value pairs
Dec 07, 2013
Jay Norwood
Dec 07, 2013
bearophile
Dec 08, 2013
Jay Norwood
Dec 08, 2013
bearophile
Dec 08, 2013
Jay Norwood
Dec 08, 2013
bearophile
Dec 08, 2013
Jay Norwood
Dec 08, 2013
bearophile
Dec 08, 2013
bearophile
Dec 09, 2013
Jay Norwood
Dec 09, 2013
bearophile
Dec 09, 2013
bearophile
Dec 09, 2013
Jay Norwood
Dec 09, 2013
bearophile
Dec 09, 2013
Jay Norwood
Dec 09, 2013
Jay Norwood
Dec 09, 2013
bearophile
December 07, 2013
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?




December 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
December 08, 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.

http://dlang.org/phobos/std_traits.html#.EnumMembers


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
December 08, 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
December 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
December 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
December 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
December 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
December 08, 2013
>       foreach (immutable member;  suits)

Sometimes you have to use:

      foreach (const member;  suits)

Bye,
bearophile
December 09, 2013
On Sunday, 8 December 2013 at 22:30:25 UTC, bearophile wrote:

>
> Try:
>
> member.writeln;
>
> Bye,
> bearophile

yeah, 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")
« First   ‹ Prev
1 2