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?

Reply via email to