enum types ---------- This is the most simple kind of enumeration. The storage type defaults to int and the values default to 0, 1, 2.... typedef filestate = enum ( unchanged, added, removed, modified, ); An enum can be used in a choice type (union in C). If the enum value is immutable then the only the memory space needed for the choice value is allocated. typedef filechange = ( filestate state; choice(state) ( unchanged(), added(int lines), removed(int lines), modified(int added_lines, int removed_lines), ); ); enum values can have a value. On integer enums, it's incremented automatically. Should enums start from zero (like C) or one (allows them to be merged with an optional type which has the "none" value)? Zero could work like false. Then the default start value should be one. Merging enums with "none" isn't safe, because any value can be added later so no value is safe to use as "none". typedef x = enum ( three = 3, four, five, ); Negative values could count down (maybe this should be implemented with a keyword instead, either just "negative" or something that specifies the range of the enum): typedef error = enum ( not_found = -1, no_access, invalid, ); enums can have non-integer values. These can't be incremented automatically. typedef color = enum (int r g b) ( red = (1,0,0), yellow = (1,1,0), green = (0,1,0), blue = (0,0,1), purple = (1,0,1), ); combined enumerations --------------------- Enumerations may be combined with a union type (unions are similar to C unions, except that all types must have disjoint values): typedef status = union( error, enum(connecting, requested, recieving, finished) ); typedef parameter = union( error, uint16, ); The underlying bit representations must be disjoint so it's not possible to combine for instance int and uint. In fact, all but one type in the union must be enums or begin with enums (in case of structs). It's possible to check if a union is of a certain type: status st; if (st is error) { // ... } An enum can be converted to one of it's types. This is subject to compiler and/or runtime checks depending on the compilation options. status st; error err = st as error; We need to be able to reserve values for the enums (for instance in case a new error code needs to be added): // syntax alternative 1: typedef error = enum( not_found = -0x1, no_access, invalid, max_error = -0x101, ); // syntax alternative 2: typedef error = enum range(0x100) ( not_found = -0x1, no_access, invalid, ); // syntax alternative 3: typedef error = enum negative ( not_found, no_access, invalid, max_error = 0x100, ); // syntax alternative 4, with range-limited int types: typedef error = enum int[0,0x100] ( not_found, no_access, invalid, max_error = 0x100, ); enums in arrays --------------- An enum (or nested enum) that contains only values >= 0 or < 0 can be used as an array index. Negative values are converted as -(n-1), so -1=0, -2=1, -3=2... string#[] errnames = ["Not found", "No access", "Invalid"]; io:out << errnames[error:no_access] << io:endl; An array type can specify that the index must be of a certain type: string#[error] errnames = ["Not found", "No access", "Invalid"]; // same as above, but with explicit array indices string#[error] errnames = [ .not_found: "Not found", .no_access: "No access", .invalid: "Invalid" ]; enums in switch/case -------------------- TODO. There are several variants of this: * "switch/case/default" in C/Java * "switch/case/default" in C# * "case/a..b,c:" in Pascal * "alt" in Rust * key/value maps with functions or values in Python. * key/value maps with blocks extensible enums in Java ------------------------ Enums can be made extensible with the following pattern in Java: public enum Values extends Value { A, B, C, } public interface Value { }