Efficient enum array keys?

Julian julian.fondren at gmail.com
Thu Apr 11 06:20:05 UTC 2019


Hello,

When reading through the following D blog post, I noticed in the
feature chart that D had "Arrays beginning at arbitrary indices" 
as
a +1 feature, the same as in Ada.

https://dlang.org/blog/2018/06/20/how-an-engineering-company-chose-to-migrate-to-d/

That surprised me, and from the code with the blog, that seems to 
be
generous. In Ada you can just say

   Silly : array (2 .. 7) of Integer;

to stack-allocate a six-integer array, with the first accessible
integer at Silly(2) and the last integer at Silly(7). Meanwhile 
the
blog has some epcomat thing that provides this to D:

   alias t = StaticArray!(int, 2, 20);

   t a;

   for (n = 2; n <= 20; n++)
       a[n] = n;

That 'Silly' array isn't very serious. I got a lot more use out of
Ada's feature of any discrete type being usable as an array index.
This gives you the efficiency of normal arrays but with a huge
readability boost. For an example from last year's Advent of Code:

   N : constant Natural := 32;
   type Rune is ('#', 'G', 'E', '.');
   type Runestring is array (1 .. N) of Rune;
   Maze : array (1 .. N) of Runestring :=
     ("################################",
      "#######..#######..#.G..##..#####",
      "######.....#####.....GG.##.#####",
      ... more of this ...);

   subtype Living_Runes is Rune range 'G' .. 'E';
   Initial_States_Table : constant array (Living_Runes) of 
Unit_State :=
     ('G' => (Hit_Points => 200, Attack_Power => 3, Moved => 
False),
      'E' => (Hit_Points => 200, Attack_Power => 3, Moved => 
False));

So you can refer to Initial_States_Table('G').Hit_Points to know
how healthy the goblins start out in this game.

Thinking of that, I came up with the following D code:

   import std.stdio, core.exception;

   enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday, 
Friday, Saturday }

   void main() {
       int[Days] worklog;
       ++worklog[Days.Wednesday];
       writeln("- worklog");
       dumplog(worklog);

       writeln();

       int[Days.max+1] altlog;
       ++altlog[Days.Saturday];
       writeln("- altlog");
       dumplog(altlog);
   }

   void dumplog(T)(T log) {
       foreach (day; Days.Sunday .. Days.Saturday) {
           try {
               writefln("%5d %s", log[day], day);
           }
           catch (core.exception.RangeError e) {}
       }
   }

Which has this output:

   - worklog
       1 Wednesday

   - altlog
       0 Sunday
       0 Monday
       0 Tuesday
       0 Wednesday
       0 Thursday
       0 Friday

And which has these faults, vs. the Ada equivalent:

1. worklog is an associative array and ++worklog[Days.Wednesday]
    compiles to a function call. This is more flexible of course 
but
    here it's unwanted and more expensive than a simple array.

2. worklog needs explicit initialization

3. this is ugly: int[Days.max+1] altlog

4. I can't write foreach (day; Days) { } ?

5. the foreach in that code is wrong: it skips Saturday, and the
    obvious fix of +1 is both ugly and an error:

   Error: cannot implicitly convert expression day of type int to 
Days

This works:

   foreach (day; Days.min .. Days.max+1)
       writefln("%5d %s", log[cast(Days) day], cast(Days) day);

But compare to Ada:

   with Ada.Text_IO; use Ada.Text_IO;

   procedure Enum is
      type Weekdays is
        (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, 
Sunday);

      procedure What_Day (Day : Weekdays) is
      begin
         case Day is
            when Monday | Tuesday | Wednesday | Thursday | Friday 
=>
               Put_Line (Weekdays'Image (Day) & " is a weekday");
            when Saturday | Sunday =>
               Put_Line (Weekdays'Image (Day) & " is a weekend 
day");
         end case;
      end What_Day;
   begin
      for J in Weekdays'Range loop
         What_Day (J);
      end loop;
   end Enum;

... which, OK, has its own problems:

   MONDAY is a weekday
   TUESDAY is a weekday
   WEDNESDAY is a weekday
   THURSDAY is a weekday
   FRIDAY is a weekday
   SATURDAY is a weekend day
   SUNDAY is a weekend day

Is there a nicer way to have enum array keys in D?


More information about the Digitalmars-d-learn mailing list