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;

Reply via email to