Enumeration Type Proposals ========================== With Jiada's recent work on enumerations (see doc/theses/jiada_liang_MMath/), this is a collection point for some remaining issues with and ideas to further improve enumerations. Fixed Encoding -------------- Because Cforall enumerations are encoded using their position, it can be difficult to give them a stable encoding. The The example (provided by Gregor Richards), is a system header that defines any type that has to be stable across versions. Let's say error codes. ```cfa enum() BigLibError! { BadArgument, ... MissingConfig, LastStartupError = MissingConfig, NoMemory, Timeout, ... }; ``` The actual errors are not important, but note that "LastStartupError" has to be in a particular location relative to some others. If a new version of the header wants to add a new startup error, it should go before the LastStartupError, but that will change the position, and hence the encoding, of all the remaining The most obvious example in an existing lanuage I could find is that Rust usually treats its enum types as opaques algebraic data types, but in certain cases allows you to fix the encoding of enumerations. (Although the motivation seems to be optimization of enumerations that have a lot of common options.) Enumerated Arrays ----------------- Arrays that use an enumeration as their index. The entire enumeration type (instead of a subset of int) is used in the index operation. Although described differently, this is actually a generalization of typed enumerations, as it can be used to safely represent a constant of any type for each possible enumeration value. ```cfa extern string colourNames[Colour]; ``` This example is a forward declaration that declares the symbol but does not give the values or allocate any storage. This is used in header files. The type of colourNames would be a new type `string[Colour]`. In implementation tiles it is safe to give the array's values; whether it the array has been previously forward declared or not. ```cfa string colourNames[Colour] = { "red", "violet", "blue", // Or without worrying about ordering: [Green] = "green", [Orange] = "orange", [Yellow] = "yellow", }; ``` The forward declaration and full definition variants allow the user to manage memory themselves, following the same rules as `extern` variables. The user can use `const` to fix the values in the array. These arrays can also be nested `BlendInfo blend[Colour][Colour]` or used locally. Except for the index type (and that the size of the array is fixed per index type, as it always covers the whole enumeration) it should be the same as a traditional array. Or one of the new safer Cforall arrays, as the features could be combined. (Previously, a compined declaration to declare both an enumeration and an enumerated array was proposed. That only covers the simple case that typed enumerations already cover.) Enumeration Ranges ------------------ We have the simplest iterate over a range of enumerations (can only be used directly in a for loop, always covers the entire type) but it could be generalized to work with the other features of ranges, such as going over just part of the enumeration (see Ranges in doc/proposals/iterators.md). Flag Set Enumerations --------------------- Another common use of enumerations is as a named bitset. This doesn't actually follow from the logical definition of enumerations, but is something that various implementation of "enum" have commonly been used to recreate. This would formalize that, providing an easy way to create typesafe implementations of this pattern. ```cfa enum Directions flag { Up, Down, Left, Right, Upwards = Up, Vertical = Up | Down, }; ``` Uses the existing enumeration syntax, except that all initializers must be bitwise expressions, using only the operators |, & and ~ and, as leaf values, other labels from the enumeration (no cycles) and 0. Each uninitialized label creates a new flag. Every instance of the enumeration will have each flag be set or unset. The labels act as instances of the enumeration with only that flag set. A type created this way automatically supports: default construction, from zero_t construction, copy construction, copy assignment, destruction, equality, inequality and bitwise and (&), or (|) and not (~). Default construction and from zero_t construction create an instance with no flags set. Two instances are the same if the same flags are set. Bitwise operations act on the individual flags in the set. In addition the type can be converted to a Boolean. An flag set is truthy if any flags are set and falsy if no flags are set. This is not a primitive operation, but comes from combining the zero_t constructor and inequality. Note: Scoping rules are also waiting on the namespacing and module system.