Most associative domains are empty by default upon declaration. At present, associative domains of enums are not, for historical reasons. Instead, they are fully populated with all of the enums values. This issue asks whether they too should be empty by default for consistency.
The historical reason why we made associative domains of enums full of all enums by default is as follows: When enums coerced to integers, an enumerated range or domain like:
enum color{ red=1, orange, yellow, green, blue, indigo, violet};
const er = color.red..color.violet
const ed = {color.red..color.violet};
would essentially become the integer range 1..7 or domain {1..7}. As a result, arrays over all enums were difficult to express using rectangular domains. The alternative was to use an associative domain, as these preserved the index type. But after writing a few of them, we realized the pattern was always "declare the associative domain, populate it with all symbols from the given enum, then use it" so this felt like a common enough case to optimize for, both in terms of the convenience of not having to populate it and for the knowledge that if all values in an enum were used as indices, the implementation could use dense/linear storage under the covers.
Now that we're on the brink of supporting true enum ranges and arrays over the same (e.g., PR #9781), it seems that we should perhaps make things more uniform by using rectangular domains of enums for the dense/regular/fully populated cases and making associative domains of enums more consistent with other associative domains (in starting early and potentially unifying the implementation).
Tagging @nspark on this, who commented on it recently.
Separate from the support provided by #9781, I don't have a super strong opinion on whether associative domains of enums should be prepopulated or not. In my experience, it was _surprising_ behavior, but not _bad_ behavior. IIRC, I had an associative array over enums that mapped to some timer object. Depending on the phase one's code was in, it would start or stop timers based on the associated enum value. So, I think this tripped me up at first because I was expecting to have to new some object into the array, which it turned out wasn't necessary.
It's probably obvious from my text in the issue above, but I worry that surprises / inconsistencies like this are bad due to the (even momentary) pause that they introduce.
My opinion: yes, associative domains of enums should not be special in this way.
Am I understanding correctly that users will be able to utilize enum ranges to populate the associate domain now?
enum E {a, b, c}
var domEnum: domain(E) = E.a..E.c;
writeln(domEnum);
// {a, b, c}
@ben-albrecht: That's right that they would be able to once this work is done. That said, they might prefer to use:
var domEnum = E.a..E.c;
// or:
var domEnum: domain(1, E) = E.a..E.c;
in order to get the benefits of dense, rectangular indexing (rather than a hash table-based implementation).
That's right that they would be able to once this work is done.
Those patterns seem convenient enough to me, such that special-casing associative domains of enums for convenience is not worth the inconsistency in design.
Most helpful comment
My opinion: yes, associative domains of enums should not be special in this way.