enum

Chad Joan chadjoan at gmail.com
Thu Apr 10 07:03:19 PDT 2014


On Tuesday, 8 April 2014 at 19:08:45 UTC, Andrei Alexandrescu 
wrote:
> (moving http://goo.gl/ZISWwN to this group)
>
> ...
>
>
> Andreiu

Honestly, my biggest issues with enums are name-qualification 
followed by stringizing.

When I say name-qualification, I mean this:
File myFile;
myFile.open("foobar.txt",
     FileAccess.READ |
     FileAccess.WRITE );

Things get long and start to wrap due to enums always requiring 
full name qualification.  This is a mild example; it gets worse 
pretty easily.

I'd much rather write:
File myFile;
myFile.open("foobar.txt", READ | WRITE );

It should be possible, because the argument's context is of the 
(hypothetical) FileAccess enum type.  It should be unambiguous 
that I intend to use FileAccess's "READ" symbol there, and not 
some other symbol from module scope.

I find myself using a module like this: 
http://dpaste.dzfl.pl/9b97c02a26fd
And writing my enums like this:

mixin dequalifyEnum!FileAccess;
mixin toStringifyFlags!FileAccess;
enum FileAccess : int
{
     READ  = (1 << 0),
     WRITE = (1 << 1),
}

It is essentially a reimplementation of the X-macro pattern from 
C, but using CTFE+mixins to accomplish the same thing in D.

It expands to something like this:

alias FileAccess.READ READ;
alias FileAccess.WRITE WRITE;
import std.exception : assumeUnique;
string toString(FileAccess val)
{
     char[] result = "FileAccess{".dup;

     if ( val & FileAccess.READ )
         result ~= "READ|";

     if ( val & FileAccess.WRITE )
         result ~= "WRITE|";

     if ( result[$-1] == '|' )
         result[$-1] = '}';
     else
         result ~= "}";

     return assumeUnique(result);
}
enum FileAccess : int
{
     READ  = (1 << 0),
     WRITE = (1 << 1),
}

I feel that this approach is bad, because it relies on the 
library writer to attach the goodies to the enum.  It also 
exposes the enum symbols at module-level, which seems icky to 
many people.  I still find it worthwhile because I dislike 
line-wrapping and can always disambiguate symbols by prepending 
the module name.

I feel like the following should happen:

File myFile;

// Fine!
myFile.open("foobar.txt", READ | WRITE );

// Fine!
myFile.open("foobar.txt",
    FileAccess.READ |
    FileAccess.WRITE );

// ERROR: READ is not accessible in this scope.
int someInteger = READ;

// Maybe OK, depending on how strict you want to be.
// It is fairly explicit, after all.
int someInteger = FileAccess.READ;

// Fine!  The enum's scope is inferred from context.
FileAccess someInteger = READ | WRITE;


More information about the Digitalmars-d mailing list