Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enum string validator in Phobos? #9937

Open
dlangBugzillaToGithub opened this issue Aug 27, 2012 · 0 comments
Open

Enum string validator in Phobos? #9937

dlangBugzillaToGithub opened this issue Aug 27, 2012 · 0 comments

Comments

@dlangBugzillaToGithub
Copy link

bearophile_hugs reported this on 2012-08-27T12:00:47Z

Transfered from https://issues.dlang.org/show_bug.cgi?id=8594

Description

In the Ada language there is a handy feature, you can define an enumeration of chars, and then give enum arrays literal as strings, and the compiler enforces the usage of just the allowed chars:


procedure Test is
   type Hexa is ('A', 'B', 'C', 'D', 'E', 'F');
   type Hex_Array is array (0 .. 5) of Hexa;
   data : Hex_Array;
begin
  data := "BACEDC";
end;


Similar literals are very useful, there are many kinds of problems that use data defined on a subset of the chars, and the chars are a compact representation. Such strings are able to represent sequence of commands, start configurations of problems, boards of games, and many kinds of discrete problems.

(Note: in Ada stack-allocated arrays like Hex_Array are used quite often, more than heap-allocated arrays.)


If you try to define a literal that contains a wrong char:

procedure Test is
   type Hexa is ('A', 'B', 'C', 'D', 'E', 'F');
   type Hex_Array is array (0 .. 5) of Hexa;
   data : Hex_Array;
begin
  data := "BACgDC";
end;


The Ada compiler gives you a compile-time error:

prog.adb:6:15: character not defined for type "Hexa" defined at line 2


Such compile-time validation is very useful to avoid bugs in the program, and in D using enum literals is useful because it allows you to use a safer "static switch" to process the data, instead of a regular "switch" on string chars.


This is one possible D translation, but even using with() the array literal requires commas (and strings are often more handy literals):

enum Hexa : char { A='A', B='B', C='C', D='D', E='E', F='F' }
alias Hexa[6] HexArray; // this is not a true type as in Ada
void main() {
    HexArray data;
    with (Hexa)
        data = [B,A,C,E,D,C];
}



So I have created a small compile-time function + template that validates a string at compile time:

// - - - - - - - - - - - - - - - -
import std.traits: isSomeChar, EnumMembers;

private E[] _validateEnumString(E)(in string txt)
pure nothrow if (is(E TC == enum) && isSomeChar!TC) {
    auto result = new typeof(return)(txt.length);

    OUTER:
    foreach (i, c; txt) {
        /*static*/ foreach (e; EnumMembers!E)
            if (c == e) {
                result[i] = e;
                continue OUTER;
            }
        assert(false, "Not valid enum char: " ~ c);
    }

    return result;
}

enum Hexa : char { A='A', B='B', C='C', D='D', E='E', F='F' }

template Hexas(string path) {
    enum Hexas = _validateEnumString!Hexa(path);
}

alias Hexa[6] HexArray;
void main() {
    HexArray data = Hexas!"BACEDC";
}
// - - - - - - - - - - - - - - - -




This alternative design uses a cast to avoid the input duplication and maybe reduces the compilation time, but produces only arrays of immutable enums:

// - - - - - - - - - - - - - - - -
import std.traits: isSomeChar, EnumMembers;

private immutable(E)[] _validateEnumString(E)(in string txt)
pure nothrow if (is(E TC == enum) && isSomeChar!TC) {

    OUTER:
    foreach (i, c; txt) {
        /*static*/ foreach (e; EnumMembers!E)
            if (c == e)
                continue OUTER;
        assert(false, "Not valid enum char: " ~ c);
    }

    return cast(typeof(return))txt;
}

enum Hexa : char { A='A', B='B', C='C', D='D', E='E', F='F' }

template Hexas(string path) {
    enum Hexas = _validateEnumString!Hexa(path);
}

alias Hexa[6] HexArray;
void main() {
    HexArray data = Hexas!"BACEDC";
    auto data2 = Hexas!"BACEDC";
    static assert(is(typeof(data2) == immutable(Hexa)[]));
}
// - - - - - - - - - - - - - - - -


Defining enum array literals this way is one of the built-in features of Ada, because it's commonly useful, this is quoted from Wikipedia:
http://en.wikipedia.org/wiki/Enumerated_type#Ada

Like Modula-3 Ada treats Boolean and Character as special pre-defined (in package "Standard") enumerated types. Unlike Modula-3 one can also define own character types:

type Cards is ("7", "8", "9", "J", "Q", "K", "A");


So maybe a template similar to the ones I have shown here is useful enough to be added to Phobos.
@LightBender LightBender removed the P4 label Dec 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants