| [9d3a4cc] | 1 | \chapter{\texorpdfstring{\CFA}{Cforall} Enumeration} | 
|---|
| [956299b] | 2 |  | 
|---|
| [7568e5c] | 3 | \CFA extends C-Style enumeration by adding a number of new features that bring enumerations in line with other modern programming languages. | 
|---|
|  | 4 | Any enumeration extensions must be intuitive to C programmers in syntax and semantics. | 
|---|
|  | 5 | The following sections detail my new contributions to enumerations in \CFA. | 
|---|
| [38e20a80] | 6 |  | 
|---|
|  | 7 |  | 
|---|
| [0c51c8b4] | 8 | \section{Syntax} | 
|---|
| [c588acb] | 9 |  | 
|---|
| [7568e5c] | 10 | \CFA extends the C enumeration declaration \see{\VRef{s:CEnumeration}} by parameterizing with a type (like a generic type) and adding Plan-9 inheritance \see{\VRef{s:CFAInheritance}} using an @inline@ to another enumeration type. | 
|---|
| [c588acb] | 11 | \begin{cfa}[identifierstyle=\linespread{0.9}\it] | 
|---|
| [e561551] | 12 | $\it enum$-specifier: | 
|---|
| [a03ed29] | 13 | enum @(type-specifier$\(_{opt}\)$)@ identifier$\(_{opt}\)$ { cfa-enumerator-list } | 
|---|
|  | 14 | enum @(type-specifier$\(_{opt}\)$)@ identifier$\(_{opt}\)$ { cfa-enumerator-list , } | 
|---|
| [e561551] | 15 | enum @(type-specifier$\(_{opt}\)$)@ identifier | 
|---|
| [a03ed29] | 16 | cfa-enumerator-list: | 
|---|
|  | 17 | cfa-enumerator | 
|---|
| [c588acb] | 18 | cfa-enumerator-list, cfa-enumerator | 
|---|
| [a03ed29] | 19 | cfa-enumerator: | 
|---|
| [e561551] | 20 | enumeration-constant | 
|---|
| [c588acb] | 21 | @inline $\color{red}enum$-type-name@ | 
|---|
|  | 22 | enumeration-constant = constant-expression | 
|---|
| [38e20a80] | 23 | \end{cfa} | 
|---|
|  | 24 |  | 
|---|
| [e561551] | 25 |  | 
|---|
| [0c51c8b4] | 26 | \section{Operations} | 
|---|
| [e561551] | 27 |  | 
|---|
| [c588acb] | 28 | \CFA enumerations have access to the three enumerations properties \see{\VRef{s:Terminology}}: label, order (position), and value via three overloaded functions @label@, @posn@, and @value@ \see{\VRef{c:trait} for details}. | 
|---|
|  | 29 | \CFA auto-generates these functions for every \CFA enumeration. | 
|---|
|  | 30 | \begin{cfa} | 
|---|
|  | 31 | enum(int) E { A = 3 } e = A; | 
|---|
|  | 32 | sout | A | @label@( A ) | @posn@( A ) | @value@( A ); | 
|---|
|  | 33 | sout | e | @label@( e ) | @posn@( e ) | @value@( e ); | 
|---|
|  | 34 | A A 0 3 | 
|---|
|  | 35 | A A 0 3 | 
|---|
|  | 36 | \end{cfa} | 
|---|
|  | 37 | For output, the default is to print the label. | 
|---|
|  | 38 | An alternate way to get an enumerator's position is to cast it to @int@. | 
|---|
|  | 39 | \begin{cfa} | 
|---|
|  | 40 | sout | A | label( A ) | @(int)A@ | value( A ); | 
|---|
|  | 41 | sout | A | label( A ) | @(int)A@ | value( A ); | 
|---|
|  | 42 | A A @0@ 3 | 
|---|
|  | 43 | A A @0@ 3 | 
|---|
| [e561551] | 44 | \end{cfa} | 
|---|
| [7568e5c] | 45 | Finally, \CFA introduces an additional enumeration pseudo-function @countof@ (like @sizeof@, @typeof@) that returns the number of enumerators in an enumeration. | 
|---|
| [e561551] | 46 | \begin{cfa} | 
|---|
| [0c51c8b4] | 47 | enum(int) E { A, B, C, D } e; | 
|---|
|  | 48 | countof( E );  // 4, type argument | 
|---|
|  | 49 | countof( e );  // 4, variable argument | 
|---|
| [e561551] | 50 | \end{cfa} | 
|---|
| [7568e5c] | 51 | This built-in function replaces the C idiom for automatically computing the number of enumerators \see{\VRef{s:Usage}}. | 
|---|
| [c588acb] | 52 | \begin{cfa} | 
|---|
|  | 53 | enum E { A, B, C, D, @N@ };  // N == 4 | 
|---|
|  | 54 | \end{cfa} | 
|---|
|  | 55 |  | 
|---|
|  | 56 | \section{Opaque Enumeration} | 
|---|
|  | 57 | \label{s:OpaqueEnum} | 
|---|
| [e561551] | 58 |  | 
|---|
| [7568e5c] | 59 | When an enumeration type is empty. it is an \newterm{opaque} enumeration. | 
|---|
| [c588acb] | 60 | \begin{cfa} | 
|---|
|  | 61 | enum@()@ Mode { O_RDONLY, O_WRONLY, O_CREAT, O_TRUNC, O_APPEND }; | 
|---|
|  | 62 | \end{cfa} | 
|---|
| [7568e5c] | 63 | Here, the compiler chooses the internal representation, which is hidden, so the enumerators cannot be initialized. | 
|---|
|  | 64 | Compared to the C enum, opaque enums are more restrictive regarding typing and cannot be implicitly converted to integers. | 
|---|
| [e561551] | 65 | \begin{cfa} | 
|---|
| [c588acb] | 66 | Mode mode = O_RDONLY; | 
|---|
|  | 67 | int www @=@ mode;                                               $\C{// disallowed}$ | 
|---|
|  | 68 | \end{cfa} | 
|---|
| [7568e5c] | 69 | Opaque enumerations have only two attribute properties, @label@ and @posn@. | 
|---|
| [c588acb] | 70 | \begin{cfa} | 
|---|
|  | 71 | char * s = label( O_TRUNC );                    $\C{// "O\_TRUNC"}$ | 
|---|
|  | 72 | int open = posn( O_WRONLY );                    $\C{// 1}$ | 
|---|
| [dcfcf368] | 73 | s = label( mode );                                              $\C{// "O\_RDONLY"}$ | 
|---|
|  | 74 | int open = posn( mode );                                $\C{// 0}$ | 
|---|
| [c588acb] | 75 | \end{cfa} | 
|---|
| [7568e5c] | 76 | Equality and relational operations are available. | 
|---|
| [c588acb] | 77 | \begin{cfa} | 
|---|
|  | 78 | if ( mode @==@ O_CREAT ) ... | 
|---|
|  | 79 | bool b = mode @<@ O_APPEND; | 
|---|
| [e561551] | 80 | \end{cfa} | 
|---|
|  | 81 |  | 
|---|
|  | 82 |  | 
|---|
| [c588acb] | 83 | \section{Typed Enumeration} | 
|---|
| [e561551] | 84 | \label{s:EnumeratorTyping} | 
|---|
|  | 85 |  | 
|---|
| [7568e5c] | 86 | When an enumeration type is specified, all enumerators have that type and can be initialized with constants of that type or compile-time convertible to that type. | 
|---|
|  | 87 | Figure~\ref{f:EumeratorTyping} shows a series of examples illustrating that all \CFA types can be used with an enumeration, and each type's values are used to set the enumerator constants. | 
|---|
|  | 88 | Note the use of the synonyms @Liz@ and @Beth@ in the last declaration. | 
|---|
| [e561551] | 89 | Because enumerators are constants, the enumeration type is implicitly @const@, so all the enumerator types in Figure~\ref{f:EumeratorTyping} are logically rewritten with @const@. | 
|---|
|  | 90 |  | 
|---|
|  | 91 | \begin{figure} | 
|---|
|  | 92 | \begin{cfa} | 
|---|
|  | 93 | // integral | 
|---|
|  | 94 | enum( @char@ ) Currency { Dollar = '$\textdollar$', Cent = '$\textcent$', Yen = '$\textyen$', Pound = '$\textsterling$', Euro = 'E' }; | 
|---|
|  | 95 | enum( @signed char@ ) srgb { Red = -1, Green = 0, Blue = 1 }; | 
|---|
|  | 96 | enum( @long long int@ ) BigNum { X = 123_456_789_012_345,  Y = 345_012_789_456_123 }; | 
|---|
|  | 97 | // non-integral | 
|---|
|  | 98 | enum( @double@ ) Math { PI_2 = 1.570796, PI = 3.141597, E = 2.718282 }; | 
|---|
|  | 99 | enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i }; | 
|---|
|  | 100 | // pointer | 
|---|
| [38e20a80] | 101 | enum( @char *@ ) Name { Fred = "FRED", Mary = "MARY", Jane = "JANE" }; | 
|---|
| [e561551] | 102 | int i, j, k; | 
|---|
|  | 103 | enum( @int *@ ) ptr { I = &i,  J = &j,  K = &k }; | 
|---|
|  | 104 | enum( @int &@ ) ref { I = i,   J = j,   K = k }; | 
|---|
|  | 105 | // tuple | 
|---|
|  | 106 | enum( @[int, int]@ ) { T = [ 1, 2 ] }; $\C{// new \CFA type}$ | 
|---|
|  | 107 | // function | 
|---|
|  | 108 | void f() {...}   void g() {...} | 
|---|
|  | 109 | enum( @void (*)()@ ) funs { F = f,  G = g }; | 
|---|
|  | 110 | // aggregate | 
|---|
|  | 111 | struct Person { char * name; int age, height; }; | 
|---|
| [c588acb] | 112 | enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz, | 
|---|
| [e561551] | 113 | Jon = { "JONATHAN", 35, 190 } }; | 
|---|
|  | 114 | \end{cfa} | 
|---|
| [c588acb] | 115 | % synonym feature unimplemented | 
|---|
| [e561551] | 116 | \caption{Enumerator Typing} | 
|---|
|  | 117 | \label{f:EumeratorTyping} | 
|---|
|  | 118 | \end{figure} | 
|---|
|  | 119 |  | 
|---|
|  | 120 | An advantage of the typed enumerations is eliminating the \emph{harmonizing} problem between an enumeration and companion data \see{\VRef{s:Usage}}: | 
|---|
|  | 121 | \begin{cfa} | 
|---|
|  | 122 | enum( char * ) integral_types { | 
|---|
|  | 123 | chr = "char", schar = "signed char", uschar = "unsigned char", | 
|---|
|  | 124 | sshort = "signed short int", ushort = "unsigned short int", | 
|---|
|  | 125 | sint = "signed int", usint = "unsigned int", | 
|---|
|  | 126 | ... | 
|---|
|  | 127 | }; | 
|---|
|  | 128 | \end{cfa} | 
|---|
| [7568e5c] | 129 | Note that the enumeration type can be a structure (see @Person@ in Figure~\ref{f:EumeratorTyping}), so it is possible to have the equivalent of multiple arrays of companion data using an array of structures. | 
|---|
| [e561551] | 130 |  | 
|---|
| [c588acb] | 131 | While the enumeration type can be any C aggregate, the aggregate's \CFA constructors are \emph{not} used to evaluate an enumerator's value. | 
|---|
| [e561551] | 132 | \CFA enumeration constants are compile-time values (static); | 
|---|
|  | 133 | calling constructors happens at runtime (dynamic). | 
|---|
|  | 134 |  | 
|---|
| [dcfcf368] | 135 |  | 
|---|
| [29c8675] | 136 | \section{Implementation} | 
|---|
| [e561551] | 137 |  | 
|---|
| [0bda8d7] | 138 | \CFA-cc is a transpiler translating \CFA code into C, which is compiled by a C compiler. | 
|---|
|  | 139 | During transpiling, \CFA-cc breaks a \CFA enumeration definition into a definition of a C enumeration with the same name and auxiliary arrays: a label and value array for a typed enumeration. | 
|---|
| [29c8675] | 140 | For example: | 
|---|
|  | 141 | \begin{cfa} | 
|---|
| [dcfcf368] | 142 | enum( T ) E { E1 = t1, E2 = t2, E3 = t3 }; | 
|---|
| [29c8675] | 143 | \end{cfa} | 
|---|
|  | 144 | is compiled into: | 
|---|
|  | 145 | \begin{cfa} | 
|---|
|  | 146 | enum E { E1, E2, E3 }; | 
|---|
| [0c88135] | 147 | const char * E_labels[3] = { "E1", "E2", "E3" }; | 
|---|
|  | 148 | const T E_values[3] = { t1, t2, t3 }; | 
|---|
| [29c8675] | 149 | \end{cfa} | 
|---|
| [dcfcf368] | 150 | The generated C enumeration has enumerator values that match \CFA enumerator positions because of C's auto-initialization. | 
|---|
|  | 151 | A \CFA enumeration variable definition is the same in \CFA as C, \eg: | 
|---|
| [d93b813] | 152 | \begin{cfa} | 
|---|
|  | 153 | enum E e = E1; | 
|---|
| [dcfcf368] | 154 | e = E2; | 
|---|
| [d93b813] | 155 | \end{cfa} | 
|---|
| [dcfcf368] | 156 | so these expressions remain unchanged by \CFA-cc. | 
|---|
|  | 157 | Therefore, a \CFA enumeration variable has the same underlying representation as its generated C enumeration. | 
|---|
| [68a7028] | 158 | This semantics implies a \CFA enumeration variable uses the same storage as a C enumeration variable, that @posn@ can use as its underlying representation, and the label and value arrays take little storage. | 
|---|
| [c329bca] | 159 | The arrays are annotated with @linkonce@, which are replaced later by gcc attribute @section(".gnu.linkonce.NAME")@, to prevent multiple definitions. | 
|---|
| [0bda8d7] | 160 | It should be possible to eliminate the two arrays if unused, either by \CFA if local to a translation unit and unused, or by the linker if global but unreferenced. | 
|---|
| [dcfcf368] | 161 | Also, the label and value arrays are declared @static@ and initialized with constants, so the arrays are allocated in the @.data@ section and initialized before program execution. | 
|---|
| [0bda8d7] | 162 | Hence, there is no additional execution cost unless new enumeration features are used, and storage usage is minimal as the number of enumerations in a program is small as is the number of enumerators in an enumeration. | 
|---|
| [dcfcf368] | 163 |  | 
|---|
|  | 164 | Along with the enumeration definition, \CFA-cc generates definitions of the attribute functions, @posn@, @label@ and @value@, for each enumeration: | 
|---|
| [29c8675] | 165 | \begin{cfa} | 
|---|
|  | 166 | inline int posn( E e ) { return (int) e; } | 
|---|
|  | 167 | inline const * label( E e ) { return E_labels[ (int) e ]; } | 
|---|
|  | 168 | inline const * E_value( E e ) { return E_values[ (int) e ]; } | 
|---|
|  | 169 | \end{cfa} | 
|---|
| [dcfcf368] | 170 | where the function calls are normally inlined by the backend C compiler into a few instructions. | 
|---|
|  | 171 | These functions simplify the job of getting the enumerations types through the type system in the same way as normal functions and calls. | 
|---|
|  | 172 | Note, the cast to @int@ is actually an internal reinterpreted cast added before type resolution to stop further reduction on the expression by the type resolver \see{\VRef{s:ValueConversion}} and removed in code generation. | 
|---|
|  | 173 | Finally, to further mitigate \CFA enumeration costs, calls to @label@ and @value@ with an enumeration constant are unrolled into the appropriate constant expression, although this could be left to the backend C compiler. | 
|---|
| [0bda8d7] | 174 | Hence, in space and time costs, \CFA enumerations follow the C philosophy of only paying for what is used, modulo some future work to convince the linker to remove un-accessed @label@ and @value@ arrays, possibly with @weak@ attributes. | 
|---|
| [29c8675] | 175 |  | 
|---|
|  | 176 |  | 
|---|
|  | 177 | \section{Value Conversion} | 
|---|
|  | 178 | \label{s:ValueConversion} | 
|---|
| [e561551] | 179 | C has an implicit type conversion from an enumerator to its base type @int@. | 
|---|
| [c588acb] | 180 | Correspondingly, \CFA has an implicit conversion from a typed enumerator to its base type, allowing typed enumeration to be seamlessly used as the value of its base type | 
|---|
|  | 181 | For example, using type @Currency@ in \VRef[Figure]{f:EumeratorTyping}: | 
|---|
| [e561551] | 182 | \begin{cfa} | 
|---|
| [c588acb] | 183 | char currency = Dollar;         $\C{// implicit conversion to base type}$ | 
|---|
|  | 184 | void foo( char ); | 
|---|
|  | 185 | foo( Dollar );                          $\C{// implicit conversion to base type}$ | 
|---|
| [e561551] | 186 | \end{cfa} | 
|---|
| [c588acb] | 187 | The implicit conversion induces a \newterm{value cost}, which is a new category (8 tuple) in \CFA's conversion cost model \see{\VRef{s:ConversionCost}} to disambiguate function overloading over a \CFA enumeration and its base type. | 
|---|
| [fcf3493] | 188 | \begin{cfa} | 
|---|
|  | 189 | void baz( char ch );            $\C{// (1)}$ | 
|---|
|  | 190 | void baz( Currency cu );        $\C{// (2)}$ | 
|---|
| [c588acb] | 191 | baz( Dollar ); | 
|---|
| [fcf3493] | 192 | \end{cfa} | 
|---|
| [c588acb] | 193 | While both @baz@ functions are applicable to the enumerator @Dollar@, @candidate (1)@ comes with a @value@ cost for the conversion to the enumeration's base type, while @candidate (2)@ has @zero@ cost. | 
|---|
|  | 194 | Hence, \CFA chooses the exact match. | 
|---|
|  | 195 | Value cost is defined to be a more significant factor than an @unsafe@ but less than the other conversion costs: @(unsafe,@ {\color{red}@value@}@, poly, safe, sign, vars, specialization,@ @reference)@. | 
|---|
| [38e20a80] | 196 | \begin{cfa} | 
|---|
| [c588acb] | 197 | void bar( @int@ ); | 
|---|
|  | 198 | Math x = PI;                            $\C{// (1)}$ | 
|---|
|  | 199 | double x = 5.5;                         $\C{// (2)}$ | 
|---|
|  | 200 | bar( x );                                       $\C{// costs (1, 0, 0, 0, 0, 0, 0, 0) or (0, 1, 0, 0, 0, 0, 0, 0)}$ | 
|---|
| [38e20a80] | 201 | \end{cfa} | 
|---|
| [7568e5c] | 202 | Here, the candidate (1) has a @value@ conversion cost to convert to the base type, while the candidate (2) has an @unsafe@ conversion from @double@ to @int@, | 
|---|
|  | 203 | which is a more expensive conversion. | 
|---|
| [c588acb] | 204 | Hence, @bar( x )@ resolves @x@ as type @Math@. | 
|---|
| [38e20a80] | 205 |  | 
|---|
| [c588acb] | 206 | % \begin{cfa} | 
|---|
|  | 207 | % forall(T | @CfaEnum(T)@) void bar(T); | 
|---|
| [dcfcf368] | 208 | % | 
|---|
| [c588acb] | 209 | % bar(a);                                       $\C{// (3), with cost (0, 0, 1, 0, 0, 0, 0, 0)}$ | 
|---|
|  | 210 | % \end{cfa} | 
|---|
|  | 211 | % % @Value@ is designed to be less significant than @poly@ to allow function being generic over \CFA enumeration (see ~\ref{c:trait}). | 
|---|
|  | 212 | % Being generic over @CfaEnum@ traits (a pre-defined interface for \CFA enums) is a practice in \CFA to implement functions over \CFA enumerations, as will see in chapter~\ref{c:trait}. | 
|---|
|  | 213 | % @Value@ is a being a more significant cost than @poly@ implies if a overloaeded function defined for @CfaEnum@ (and other generic type), \CFA always try to resolve it as a @CfaEnum@, rather to insert a @value@ conversion. | 
|---|
| [38e20a80] | 214 |  | 
|---|
| [f6321173] | 215 |  | 
|---|
| [d93b813] | 216 | \section{Initialization} | 
|---|
| [acab1bd] | 217 | \CFA extends C's auto-initialization scheme to \CFA enumeration. For an enumeration type with base type T, the initialization scheme is the following: | 
|---|
|  | 218 | \begin{enumerate} | 
|---|
|  | 219 | \item the first enumerator is initialized with @T@'s @zero_t@. | 
|---|
|  | 220 | \item Every other enumerator is initialized with its previous enumerator's value "+1", where "+1" is defined in terms of overloaded operator @?+?(T, one_t)@. | 
|---|
|  | 221 | \end{enumerate} | 
|---|
| [7568e5c] | 222 |  | 
|---|
|  | 223 | \begin{cfa} | 
|---|
|  | 224 | struct S { int i; }; | 
|---|
|  | 225 | S ?+?( S & s, one_t ) { return s.i++; } | 
|---|
|  | 226 | void ?{}( S & s, zero_t ) { s.i = 0; } | 
|---|
|  | 227 | enum(S) E { A, B, C, D }; | 
|---|
|  | 228 | \end{cfa} | 
|---|
| [c588acb] | 229 |  | 
|---|
| [dcfcf368] | 230 | The restriction on C's enumeration initializers being constant expression is relaxed on \CFA enumeration. | 
|---|
|  | 231 | Therefore, an enumerator initializer allows function calls like @?+?( S & s, one_t )@ and @?{}( S & s, zero_t )@. | 
|---|
|  | 232 | It is because the values of \CFA enumerators are not stored in the compiled enumeration body but in the @value@ array, which | 
|---|
| [29c8675] | 233 | allows dynamic initialization. | 
|---|
|  | 234 |  | 
|---|
| [0c51c8b4] | 235 | \section{Subset} | 
|---|
|  | 236 |  | 
|---|
|  | 237 | An enumeration's type can be another enumeration. | 
|---|
|  | 238 | \begin{cfa} | 
|---|
| [3b10778] | 239 | enum( char ) Letter { A = 'A', ..., Z = 'Z' }; | 
|---|
|  | 240 | enum( @Letter@ ) Greek { Alph = @A@, Beta = @B@, Gamma = @G@, ..., Zeta = @Z@ }; // alphabet intersection | 
|---|
|  | 241 | \end{cfa} | 
|---|
|  | 242 | Enumeration @Greek@ may have more or less enumerators than @Letter@, but its enumerator values \emph{must} be from @Letter@. | 
|---|
| [dcfcf368] | 243 | Therefore, the set of @Greek@ enumerator values in a subset of the @Letter@ enumerator values. | 
|---|
| [3b10778] | 244 | @Letter@ is type compatible with enumeration @Letter@ because value conversions are inserted whenever @Letter@ is used in place of @Greek@. | 
|---|
|  | 245 | \begin{cfa} | 
|---|
|  | 246 | Letter l = A;                                           $\C{// allowed}$ | 
|---|
|  | 247 | Greek g = Alph;                                         $\C{// allowed}$ | 
|---|
|  | 248 | l = Alph;                                                       $\C{// allowed, conversion to base type}$ | 
|---|
|  | 249 | g = A;                                                          $\C{// {\color{red}disallowed}}$ | 
|---|
|  | 250 | void foo( Letter ); | 
|---|
|  | 251 | foo( Beta );                                            $\C{// allowed, conversion to base type}$ | 
|---|
|  | 252 | void bar( Greek ); | 
|---|
|  | 253 | bar( A );                                                       $\C{// {\color{red}disallowed}}$ | 
|---|
| [0c51c8b4] | 254 | \end{cfa} | 
|---|
| [7568e5c] | 255 | Hence, @Letter@ enumerators are not type-compatible with the @Greek@ enumeration, but the reverse is true. | 
|---|
| [0c51c8b4] | 256 |  | 
|---|
|  | 257 |  | 
|---|
|  | 258 | \section{Inheritance} | 
|---|
|  | 259 | \label{s:CFAInheritance} | 
|---|
| [e561551] | 260 |  | 
|---|
| [0bda8d7] | 261 | \CFA Plan-9 inheritance may be used with \CFA enumerations, where Plan-9 inheritance is containment inheritance with implicit un-scoping (like a nested unnamed @struct@/@union@ in C). | 
|---|
| [c588acb] | 262 | Containment is nominative: an enumeration inherits all enumerators from another enumeration by declaring an @inline statement@ in its enumerator lists. | 
|---|
| [956299b] | 263 | \begin{cfa} | 
|---|
| [3b10778] | 264 | enum( char * ) Names { /* $\see{\VRef[Figure]{f:EumeratorTyping}}$ */  }; | 
|---|
| [e561551] | 265 | enum( char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" }; | 
|---|
|  | 266 | enum( char * ) Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" }; | 
|---|
| [956299b] | 267 | \end{cfa} | 
|---|
| [1697c40] | 268 | In the preceding example, @Names2@ is defined with five enumerators, three of which are from @Name@ through containment, and two are self-declared. | 
|---|
| [c588acb] | 269 | @Names3@ inherits all five members from @Names2@ and declares two additional enumerators. | 
|---|
|  | 270 | Hence, enumeration inheritance forms a subset relationship. | 
|---|
|  | 271 | Specifically, the inheritance relationship for the example above is: | 
|---|
| [1697c40] | 272 | \begin{cfa} | 
|---|
|  | 273 | Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\C{// enum type of Names}$ | 
|---|
|  | 274 | \end{cfa} | 
|---|
|  | 275 |  | 
|---|
|  | 276 | Inheritance can be nested, and a \CFA enumeration can inline enumerators from more than one \CFA enumeration, forming a tree-like hierarchy. | 
|---|
| [7568e5c] | 277 | However, the uniqueness of the enumeration name applies to enumerators, including those from supertypes, meaning an enumeration cannot name an enumerator with the same label as its subtype's members or inherits | 
|---|
|  | 278 | from multiple enumeration that has overlapping enumerator labels. Consequently, a new type cannot inherit from an enumeration and its supertype or two enumerations with a | 
|---|
|  | 279 | common supertype (the diamond problem) since such would unavoidably introduce duplicate enumerator labels. | 
|---|
| [1697c40] | 280 |  | 
|---|
| [c141c09] | 281 | The base type must be consistent between subtype and supertype. | 
|---|
| [7568e5c] | 282 | When an enumeration inherits enumerators from another enumeration, it copies the enumerators' @value@ and @label@, even if the @value@ is auto-initialized. | 
|---|
| [0bda8d7] | 283 | However, the underlying representation's position is the enumerator's order in the new enumeration. | 
|---|
| [956299b] | 284 | \begin{cfa} | 
|---|
| [dcfcf368] | 285 | enum() E1 { B };                                                                        $\C{// B}$ | 
|---|
| [3b10778] | 286 | enum() E2 { C, D };                                             $\C{// C D}$ | 
|---|
|  | 287 | enum() E3 { inline E1, inline E2, E };  $\C{// {\color{red}[\(_{E1}\)} B {\color{red}]} {\color{red}[\(_{E2}\)} C D {\color{red}]} E}$ | 
|---|
|  | 288 | enum() E4 { A, inline E3, F};                   $\C{// A {\color{blue}[\(_{E3}\)} {\color{red}[\(_{E1}\)} B {\color{red}]} {\color{red}[\(_{E2}\)} C D {\color{red}]} E {\color{blue}]} F}$ | 
|---|
| [e561551] | 289 | \end{cfa} | 
|---|
| [0bda8d7] | 290 | In this example, @B@ is at position 0 in @E1@ and @E3@, but position 1 in @E4@ as @A@ takes position 0 in @E4@. | 
|---|
| [3b10778] | 291 | @C@ is at position 0 in @E2@, 1 in @E3@, and 2 in @E4@. | 
|---|
| [dcfcf368] | 292 | @D@ is at position 1 in @E2@, 2 in @E3@, and 3 in @E4@. | 
|---|
| [e561551] | 293 |  | 
|---|
| [dcfcf368] | 294 | A subtype enumeration can be casted, or implicitly converted into its supertype, with a @safe@ cost, called \newterm{enumeration conversion}. | 
|---|
| [e561551] | 295 | \begin{cfa} | 
|---|
| [c588acb] | 296 | enum E2 e2 = C; | 
|---|
| [63d5b9c8] | 297 | posn( e2 );                     $\C[1.75in]{// 0}$ | 
|---|
| [92a0ee8] | 298 | enum E3 e3 = e2;        $\C{// Assignment with enumeration conversion E2 to E3}$ | 
|---|
| [c1c0efdb] | 299 | posn( e2 );                     $\C{// 1 cost}$ | 
|---|
| [c588acb] | 300 | void foo( E3 e ); | 
|---|
| [92a0ee8] | 301 | foo( e2 );                      $\C{// Type compatible with enumeration conversion E2 to E3}$ | 
|---|
|  | 302 | posn( (E3)e2 );         $\C{// Explicit cast with enumeration conversion E2 to E3}$ | 
|---|
|  | 303 | E3 e31 = B;                     $\C{// No conversion: E3.B}$ | 
|---|
| [c1c0efdb] | 304 | posn( e31 );            $\C{// 0 cost}\CRT$ | 
|---|
| [c588acb] | 305 | \end{cfa} | 
|---|
|  | 306 | The last expression is unambiguous. | 
|---|
| [c1c0efdb] | 307 | While both @E2.B@ and @E3.B@ are valid candidates, @E2.B@ has an associated safe cost and @E3.B@ needs no conversion (@zero@ cost). | 
|---|
|  | 308 | \CFA selects the lowest cost candidate @E3.B@. | 
|---|
| [e561551] | 309 |  | 
|---|
|  | 310 | For the given function prototypes, the following calls are valid. | 
|---|
|  | 311 | \begin{cquote} | 
|---|
|  | 312 | \begin{tabular}{ll} | 
|---|
|  | 313 | \begin{cfa} | 
|---|
|  | 314 | void f( Names ); | 
|---|
|  | 315 | void g( Names2 ); | 
|---|
|  | 316 | void h( Names3 ); | 
|---|
|  | 317 | void j( const char * ); | 
|---|
|  | 318 | \end{cfa} | 
|---|
|  | 319 | & | 
|---|
|  | 320 | \begin{cfa} | 
|---|
|  | 321 | f( Fred ); | 
|---|
|  | 322 | g( Fred );   g( Jill ); | 
|---|
|  | 323 | h( Fred );   h( Jill );   h( Sue ); | 
|---|
|  | 324 | j( Fred );    j( Jill );    j( Sue );    j( "WILL" ); | 
|---|
|  | 325 | \end{cfa} | 
|---|
|  | 326 | \end{tabular} | 
|---|
|  | 327 | \end{cquote} | 
|---|
|  | 328 | Note, the validity of calls is the same for call-by-reference as for call-by-value, and @const@ restrictions are the same as for other types. | 
|---|
|  | 329 |  | 
|---|
| [3b10778] | 330 |  | 
|---|
| [63d5b9c8] | 331 | \subsection{Offset Calculation} | 
|---|
| [3b10778] | 332 |  | 
|---|
| [63d5b9c8] | 333 | As discussed in \VRef{s:OpaqueEnum}, \CFA chooses position as a representation of a \CFA enumeration variable. | 
|---|
| [0bda8d7] | 334 | When a cast or implicit conversion moves an enumeration from subtype to supertype, the position can be unchanged or increased. | 
|---|
| [3b10778] | 335 | \CFA determines the position offset with an \newterm{offset calculation} function. | 
|---|
| [63d5b9c8] | 336 |  | 
|---|
|  | 337 | \begin{figure} | 
|---|
|  | 338 | \begin{cfa} | 
|---|
|  | 339 | struct Enumerator; | 
|---|
|  | 340 | struct CFAEnum { vector<variant<CFAEnum, Enumerator>> members; string name; }; | 
|---|
|  | 341 | inline static bool operator==(CFAEnum& lhs, CFAEnum& rhs) { return lhs.name == rhs.name; } | 
|---|
|  | 342 | pair<bool, int> calculateEnumOffset(CFAEnum src, CFAEnum dst) { | 
|---|
|  | 343 | int offset = 0; | 
|---|
| [3b10778] | 344 | if ( src == dst ) return make_pair(true, 0); | 
|---|
|  | 345 | for ( auto v : dst.members ) { | 
|---|
|  | 346 | if ( holds_alternative<Enumerator>(v) ) { | 
|---|
| [63d5b9c8] | 347 | offset++; | 
|---|
|  | 348 | } else { | 
|---|
|  | 349 | auto m = get<CFAEnum>(v); | 
|---|
| [3b10778] | 350 | if ( m == src ) @return@ make_pair( true, offset ); | 
|---|
|  | 351 | auto dist = calculateEnumOffset( src, m ); | 
|---|
|  | 352 | if ( dist.first ) { | 
|---|
|  | 353 | @return@ make_pair( true, offset + dist.second ); | 
|---|
| [63d5b9c8] | 354 | } else { | 
|---|
|  | 355 | offset += dist.second; | 
|---|
|  | 356 | } | 
|---|
|  | 357 | } | 
|---|
|  | 358 | } | 
|---|
| [3b10778] | 359 | @return@ make_pair( false, offset ); | 
|---|
| [63d5b9c8] | 360 | } | 
|---|
|  | 361 | \end{cfa} | 
|---|
|  | 362 | \caption{Compute Offset from Subtype Enumeration to a Supertype} | 
|---|
|  | 363 | \label{s:OffsetSubtypeSuperType} | 
|---|
|  | 364 | \end{figure} | 
|---|
|  | 365 |  | 
|---|
| [3b10778] | 366 | Figure~\ref{s:OffsetSubtypeSuperType} shows an outline of the offset calculation in \CC. | 
|---|
|  | 367 | Structure @CFAEnum@ represents the \CFA enumeration with a vector of variants of @CFAEnum@ or @Enumerator@. | 
|---|
|  | 368 | The algorithm takes two @CFAEnums@ parameters, @src@ and @dst@, with @src@ being the type of expression the conversion applies to, and @dst@ being the type the expression is cast to. | 
|---|
|  | 369 | The algorithm iterates over the members in @dst@ to find @src@. | 
|---|
| [7568e5c] | 370 | If a member is an enumerator of @dst@, the positions of all subsequent members are incremented by one. | 
|---|
| [0bda8d7] | 371 | If the current member is @dst@, the function returns true, indicating \emph{found} and the accumulated offset. | 
|---|
| [3b10778] | 372 | Otherwise, the algorithm recurses into the current @CFAEnum@ @m@ to check if its @src@ is convertible to @m@. | 
|---|
|  | 373 | If @src@ is convertible to the current member @m@, this means @src@ is a subtype-of-subtype of @dst@. | 
|---|
|  | 374 | The offset between @src@ and @dst@ is the sum of the offset of @m@ in @dst@ and the offset of @src@ in @m@. | 
|---|
|  | 375 | If @src@ is not a subtype of @m@, the loop continues but with the offset shifted by the size of @m@. | 
|---|
|  | 376 | If the loop ends, than @src@ is not convertible to @dst@, and false is returned. | 
|---|
|  | 377 |  | 
|---|
| [c588acb] | 378 |  | 
|---|
| [0c51c8b4] | 379 | \section{Control Structures} | 
|---|
| [956299b] | 380 |  | 
|---|
| [0bda8d7] | 381 | Enumerators are used in various contexts. | 
|---|
| [956299b] | 382 | In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution). | 
|---|
| [0bda8d7] | 383 | However, in some contexts, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect. | 
|---|
|  | 384 | A programmer's intuition assumes an implicit conversion to position in these contexts. | 
|---|
| [956299b] | 385 |  | 
|---|
| [09dd830] | 386 | For example, an intuitive use of enumerations is with the \CFA @switch@/@choose@ statement, where @choose@ performs an implicit @break@ rather than a fall-through at the end of a @case@ clause. | 
|---|
| [10a99d87] | 387 | (For this discussion, ignore the fact that @case@ requires a compile-time constant.) | 
|---|
|  | 388 | \begin{cfa}[belowskip=0pt] | 
|---|
| [956299b] | 389 | enum Count { First, Second, Third, Fourth }; | 
|---|
|  | 390 | Count e; | 
|---|
|  | 391 | \end{cfa} | 
|---|
| [10a99d87] | 392 | \begin{cquote} | 
|---|
|  | 393 | \setlength{\tabcolsep}{15pt} | 
|---|
|  | 394 | \noindent | 
|---|
|  | 395 | \begin{tabular}{@{}ll@{}} | 
|---|
|  | 396 | \begin{cfa}[aboveskip=0pt] | 
|---|
| [956299b] | 397 |  | 
|---|
|  | 398 | choose( e ) { | 
|---|
|  | 399 | case @First@: ...; | 
|---|
|  | 400 | case @Second@: ...; | 
|---|
|  | 401 | case @Third@: ...; | 
|---|
|  | 402 | case @Fourth@: ...; | 
|---|
|  | 403 | } | 
|---|
|  | 404 | \end{cfa} | 
|---|
|  | 405 | & | 
|---|
| [10a99d87] | 406 | \begin{cfa}[aboveskip=0pt] | 
|---|
| [956299b] | 407 | // rewrite | 
|---|
|  | 408 | choose( @value@( e ) ) { | 
|---|
|  | 409 | case @value@( First ): ...; | 
|---|
|  | 410 | case @value@( Second ): ...; | 
|---|
|  | 411 | case @value@( Third ): ...; | 
|---|
|  | 412 | case @value@( Fourth ): ...; | 
|---|
|  | 413 | } | 
|---|
|  | 414 | \end{cfa} | 
|---|
|  | 415 | \end{tabular} | 
|---|
|  | 416 | \end{cquote} | 
|---|
| [de3a579] | 417 | Here, the intuitive code on the left is implicitly transformed into the standard implementation on the right, using the value of the enumeration variable and enumerators. | 
|---|
| [f9da761] | 418 | However, this implementation is fragile, \eg if the enumeration is changed to: | 
|---|
| [956299b] | 419 | \begin{cfa} | 
|---|
|  | 420 | enum Count { First, Second, Third @= First@, Fourth }; | 
|---|
|  | 421 | \end{cfa} | 
|---|
| [10a99d87] | 422 | making @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicate @case@ clauses. | 
|---|
| [ec20ab9] | 423 | To better match with programmer intuition, \CFA toggles between value and position semantics depending on the language context. | 
|---|
| [09dd830] | 424 | For conditional clauses and switch statements, \CFA uses the robust position implementation. | 
|---|
| [956299b] | 425 | \begin{cfa} | 
|---|
| [10a99d87] | 426 | if ( @posn@( e ) < posn( Third ) ) ... | 
|---|
|  | 427 | choose( @posn@( e ) ) { | 
|---|
|  | 428 | case @posn@( First ): ...; | 
|---|
|  | 429 | case @posn@( Second ): ...; | 
|---|
|  | 430 | case @posn@( Third ): ...; | 
|---|
|  | 431 | case @posn@( Fourth ): ...; | 
|---|
| [956299b] | 432 | } | 
|---|
|  | 433 | \end{cfa} | 
|---|
|  | 434 |  | 
|---|
| [10a99d87] | 435 | \CFA provides a special form of for-control for enumerating through an enumeration, where the range is a type. | 
|---|
| [956299b] | 436 | \begin{cfa} | 
|---|
| [10a99d87] | 437 | for ( cx; @Count@ ) { sout | cx | nonl; } sout | nl; | 
|---|
| [c588acb] | 438 | for ( cx; ~= Count ) { sout | cx | nonl; } sout | nl; | 
|---|
| [10a99d87] | 439 | for ( cx; -~= Count ) { sout | cx | nonl; } sout | nl; | 
|---|
|  | 440 | First Second Third Fourth | 
|---|
|  | 441 | First Second Third Fourth | 
|---|
|  | 442 | Fourth Third Second First | 
|---|
| [956299b] | 443 | \end{cfa} | 
|---|
| [10a99d87] | 444 | The enumeration type is syntax sugar for looping over all enumerators and assigning each enumerator to the loop index, whose type is inferred from the range type. | 
|---|
| [0bda8d7] | 445 | The prefix @+~=@ or @-~=@ iterate forward or backward through the inclusive enumeration range, where no prefix defaults to @+~=@. | 
|---|
| [7d9a805b] | 446 |  | 
|---|
| [10a99d87] | 447 | C has an idiom for @if@ and loop predicates of comparing the predicate result ``not equal to 0''. | 
|---|
| [dc1c430] | 448 | \begin{cfa} | 
|---|
| [c588acb] | 449 | if ( x + y /* != 0 */  ) ... | 
|---|
|  | 450 | while ( p /* != 0 */  ) ... | 
|---|
| [dc1c430] | 451 | \end{cfa} | 
|---|
| [0bda8d7] | 452 | This idiom extends to enumerations because there is a boolean conversion regarding the enumeration value if and only if such a conversion is available. | 
|---|
| [10a99d87] | 453 | For example, such a conversion exists for all numerical types (integral and floating-point). | 
|---|
|  | 454 | It is possible to explicitly extend this idiom to any typed enumeration by overloading the @!=@ operator. | 
|---|
| [dc1c430] | 455 | \begin{cfa} | 
|---|
| [10a99d87] | 456 | bool ?!=?( Name n, zero_t ) { return n != Fred; } | 
|---|
|  | 457 | Name n = Mary; | 
|---|
|  | 458 | if ( n ) ... // result is true | 
|---|
| [dc1c430] | 459 | \end{cfa} | 
|---|
| [10a99d87] | 460 | Specialize meanings are also possible. | 
|---|
| [dc1c430] | 461 | \begin{cfa} | 
|---|
|  | 462 | enum(int) ErrorCode { Normal = 0, Slow = 1, Overheat = 1000, OutOfResource = 1001 }; | 
|---|
| [10a99d87] | 463 | bool ?!=?( ErrorCode ec, zero_t ) { return ec >= Overheat; } | 
|---|
|  | 464 | ErrorCode code = ...; | 
|---|
|  | 465 | if ( code ) { problem(); } | 
|---|
| [dc1c430] | 466 | \end{cfa} | 
|---|
| [7d9a805b] | 467 |  | 
|---|
| [f6321173] | 468 |  | 
|---|
| [0c51c8b4] | 469 | \section{Dimension} | 
|---|
| [f6321173] | 470 |  | 
|---|
| [c588acb] | 471 | \VRef{s:EnumeratorTyping} introduces the harmonizing problem between an enumeration and secondary information. | 
|---|
| [10a99d87] | 472 | When possible, using a typed enumeration for the secondary information is the best approach. | 
|---|
|  | 473 | However, there are times when combining these two types is not possible. | 
|---|
|  | 474 | For example, the secondary information might precede the enumeration and/or its type is needed directly to declare parameters of functions. | 
|---|
|  | 475 | In these cases, having secondary arrays of the enumeration size are necessary. | 
|---|
| [f6321173] | 476 |  | 
|---|
| [10a99d87] | 477 | To support some level of harmonizing in these cases, an array dimension can be defined using an enumerator type, and the enumerators used as subscripts. | 
|---|
| [dc1c430] | 478 | \begin{cfa} | 
|---|
| [c141c09] | 479 | enum E1 { A, B, C, N }; // possibly predefined | 
|---|
|  | 480 | enum(int) E2 { A, B, C }; | 
|---|
| [c588acb] | 481 | float H1[N] = { [A] :$\footnotemark$ 3.4, [B] : 7.1, [C] : 0.01 }; // C | 
|---|
| [c141c09] | 482 | float H2[@E2@] = { [A] : 3.4, [B] : 7.1, [C] : 0.01 }; // CFA | 
|---|
| [d69f7114] | 483 | \end{cfa} | 
|---|
| [c588acb] | 484 | \footnotetext{C uses symbol \lstinline{'='} for designator initialization, but \CFA changes it to \lstinline{':'} because of problems with tuple syntax.} | 
|---|
| [0bda8d7] | 485 | This approach is also necessary for a predefined typed enumeration (unchangeable) when additional secondary information needs to be added. | 
|---|
| [c588acb] | 486 | The array subscript operator, namely @?[?]@, is overloaded so that when a \CFA enumerator is used as an array index, it implicitly converts to its position over value to sustain data harmonization. | 
|---|
|  | 487 | This behaviour can be reverted by explicit overloading: | 
|---|
| [c141c09] | 488 | \begin{cfa} | 
|---|
| [c588acb] | 489 | float ?[?]( float * arr, E2 index ) { return arr[ value( index ) ]; } | 
|---|
| [c141c09] | 490 | \end{cfa} | 
|---|
| [c1c0efdb] | 491 | While enumerator labels @A@, @B@ and @C@ are being defined twice in different enumerations, they are unambiguous within the context. | 
|---|
|  | 492 | Designators in @H1@ are unambiguous becasue @E2@ has a @value@ cost to @int@, which is more expensive than @safe@ cost from C-Enum @E1@ to @int@. | 
|---|
|  | 493 | Designators in @H2@ are resolved as @E2@ because when a \CFA enumeration type is being used as an array dimension, \CFA adds the enumeration type to the initializer's resolution context. | 
|---|
|  | 494 |  | 
|---|
| [bc17be98] | 495 |  | 
|---|
| [0c51c8b4] | 496 | \section{I/O} | 
|---|
| [c1c0efdb] | 497 |  | 
|---|
| [92a0ee8] | 498 | As seen in multiple examples, \CFA enumerations can be printed and the default property printed is the enumerator's label, which is similar in other programming languages. | 
|---|
| [6f47834] | 499 | However, very few programming languages provide a mechanism to read in enumerator values. | 
|---|
|  | 500 | Even the @boolean@ type in many languages does not have a mechanism for input using the enumerators @true@ or @false@. | 
|---|
|  | 501 | \VRef[Figure]{f:EnumerationI/O} show \CFA enumeration input based on the enumerator labels. | 
|---|
|  | 502 | When the enumerator labels are packed together in the input stream, the input algorithm scans for the longest matching string. | 
|---|
| [7568e5c] | 503 | For basic types in \CFA, the rule is that the same constants used to initialize a variable in a program are available to initialize a variable using input, where string constants can be quoted or unquoted. | 
|---|
| [6f47834] | 504 |  | 
|---|
|  | 505 | \begin{figure} | 
|---|
|  | 506 | \begin{cquote} | 
|---|
|  | 507 | \setlength{\tabcolsep}{15pt} | 
|---|
|  | 508 | \begin{tabular}{@{}ll@{}} | 
|---|
|  | 509 | \begin{cfa} | 
|---|
|  | 510 | int main() { | 
|---|
|  | 511 | enum(int ) E { BBB = 3, AAA, AA, AB, B }; | 
|---|
|  | 512 | E e; | 
|---|
|  | 513 |  | 
|---|
| [3ac5fd8] | 514 | try { | 
|---|
|  | 515 | for () { | 
|---|
|  | 516 | try { | 
|---|
|  | 517 | @sin | e@; | 
|---|
|  | 518 | } catch( missing_data * ) { | 
|---|
|  | 519 | sout | "missing data"; | 
|---|
|  | 520 | continue; // try again | 
|---|
|  | 521 | } | 
|---|
|  | 522 | sout | e | "= " | value( e ); | 
|---|
| [6f47834] | 523 | } | 
|---|
| [3ac5fd8] | 524 | } catch( end_of_file ) {} | 
|---|
| [6f47834] | 525 | } | 
|---|
|  | 526 | \end{cfa} | 
|---|
|  | 527 | & | 
|---|
|  | 528 | \begin{cfa} | 
|---|
|  | 529 | $\rm input$ | 
|---|
|  | 530 | BBBABAAAAB | 
|---|
|  | 531 | BBB AAA AA AB B | 
|---|
|  | 532 |  | 
|---|
|  | 533 | $\rm output$ | 
|---|
|  | 534 | BBB = 3 | 
|---|
|  | 535 | AB = 6 | 
|---|
|  | 536 | AAA = 4 | 
|---|
|  | 537 | AB = 6 | 
|---|
|  | 538 | BBB = 3 | 
|---|
|  | 539 | AAA = 4 | 
|---|
|  | 540 | AA = 5 | 
|---|
|  | 541 | AB = 6 | 
|---|
|  | 542 | B = 7 | 
|---|
|  | 543 |  | 
|---|
|  | 544 | \end{cfa} | 
|---|
|  | 545 | \end{tabular} | 
|---|
|  | 546 | \end{cquote} | 
|---|
|  | 547 | \caption{Enumeration I/O} | 
|---|
|  | 548 | \label{f:EnumerationI/O} | 
|---|
|  | 549 | \end{figure} | 
|---|
|  | 550 |  | 
|---|
|  | 551 |  | 
|---|
| [7d9a805b] | 552 | \section{Planet Example} | 
|---|
|  | 553 |  | 
|---|
| [f6321173] | 554 | \VRef[Figure]{f:PlanetExample} shows an archetypal enumeration example illustrating most of the \CFA enumeration features. | 
|---|
| [caaf424] | 555 | @Planet@ is an enumeration of type @MR@. | 
|---|
| [09dd830] | 556 | Each planet enumerator is initialized to a specific mass/radius, @MR@, value. | 
|---|
| [caaf424] | 557 | The unnamed enumeration provides the gravitational-constant enumerator @G@. | 
|---|
|  | 558 | Function @surfaceGravity@ uses the @with@ clause to remove @p@ qualification from fields @mass@ and @radius@. | 
|---|
| [29092213] | 559 | The program main uses the pseudo function @countof@ to obtain the number of enumerators in @Planet@, and safely converts the random value into a @Planet@ enumerator using @fromInt@. | 
|---|
|  | 560 | The resulting random orbital-body is used in a @choose@ statement. | 
|---|
| [09dd830] | 561 | The enumerators in the @case@ clause use the enumerator position for testing. | 
|---|
| [29092213] | 562 | The prints use @label@ to print an enumerator's name. | 
|---|
| [29c8675] | 563 | Finally, a loop enumerates through the planets computing the weight on each planet for a given Earth mass. | 
|---|
| [29092213] | 564 | The print statement does an equality comparison with an enumeration variable and enumerator (@p == MOON@). | 
|---|
| [7d9a805b] | 565 |  | 
|---|
|  | 566 | \begin{figure} | 
|---|
| [caaf424] | 567 | \small | 
|---|
| [7d9a805b] | 568 | \begin{cfa} | 
|---|
| [c588acb] | 569 | struct MR { double mass, radius; };                     $\C[3.5in]{// planet definition}$ | 
|---|
| [29092213] | 570 | enum( @MR@ ) Planet {                                           $\C{// typed enumeration}$ | 
|---|
| [f6321173] | 571 | //                      mass (kg)   radius (km) | 
|---|
|  | 572 | MERCURY = { 0.330_E24, 2.4397_E6 }, | 
|---|
|  | 573 | VENUS      = { 4.869_E24, 6.0518_E6 }, | 
|---|
| [7d9a805b] | 574 | EARTH       = { 5.976_E24, 6.3781_E6 }, | 
|---|
| [29092213] | 575 | MOON        = { 7.346_E22, 1.7380_E6 }, $\C{// not a planet}$ | 
|---|
| [f6321173] | 576 | MARS         = { 0.642_E24, 3.3972_E6 }, | 
|---|
|  | 577 | JUPITER    = { 1898._E24, 71.492_E6 }, | 
|---|
|  | 578 | SATURN     = { 568.8_E24, 60.268_E6 }, | 
|---|
|  | 579 | URANUS    = { 86.86_E24, 25.559_E6 }, | 
|---|
|  | 580 | NEPTUNE  = { 102.4_E24, 24.746_E6 }, | 
|---|
| [29092213] | 581 | PLUTO       = { 1.303_E22, 1.1880_E6 }, $\C{// not a planet}$ | 
|---|
| [7d9a805b] | 582 | }; | 
|---|
| [29092213] | 583 | enum( double ) { G = 6.6743_E-11 };                     $\C{// universal gravitational constant (m3 kg-1 s-2)}$ | 
|---|
| [caaf424] | 584 | static double surfaceGravity( Planet p ) @with( p )@ { | 
|---|
| [29092213] | 585 | return G * mass / ( radius @\@ 2 );             $\C{// no qualification, exponentiation}$ | 
|---|
| [7d9a805b] | 586 | } | 
|---|
|  | 587 | static double surfaceWeight( Planet p, double otherMass ) { | 
|---|
|  | 588 | return otherMass * surfaceGravity( p ); | 
|---|
|  | 589 | } | 
|---|
|  | 590 | int main( int argc, char * argv[] ) { | 
|---|
| [29092213] | 591 | if ( argc != 2 ) @exit@ | "Usage: " | argv[0] | "earth-weight";  // terminate program | 
|---|
| [7d9a805b] | 592 | double earthWeight = convert( argv[1] ); | 
|---|
| [d69f7114] | 593 | double earthMass = earthWeight / surfaceGravity( EARTH ); | 
|---|
| [29092213] | 594 | Planet rp = @fromInt@( prng( @countof@( Planet ) ) ); $\C{// select random orbiting body}$ | 
|---|
|  | 595 | @choose( rp )@ {                                                $\C{// implicit breaks}$ | 
|---|
| [caaf424] | 596 | case MERCURY, VENUS, EARTH, MARS: | 
|---|
| [62a38e7] | 597 | sout | @rp@ | "is a rocky planet"; | 
|---|
| [29092213] | 598 | case JUPITER, SATURN, URANUS, NEPTUNE: | 
|---|
| [62a38e7] | 599 | sout | rp | "is a gas-giant planet"; | 
|---|
| [caaf424] | 600 | default: | 
|---|
| [62a38e7] | 601 | sout | rp | "is not a planet"; | 
|---|
| [caaf424] | 602 | } | 
|---|
| [c588acb] | 603 | for ( @p; Planet@ ) {                                   $\C{// enumerate}\CRT$ | 
|---|
| [62a38e7] | 604 | sout | "Your weight on" | ( @p == MOON@ ? "the" : " " ) | p | 
|---|
| [29092213] | 605 | | "is" | wd( 1,1,  surfaceWeight( p, earthMass ) ) | "kg"; | 
|---|
| [7d9a805b] | 606 | } | 
|---|
|  | 607 | } | 
|---|
| [f6321173] | 608 | $\$$ planet 100 | 
|---|
| [caaf424] | 609 | JUPITER is a gas-giant planet | 
|---|
| [f6321173] | 610 | Your weight on MERCURY is 37.7 kg | 
|---|
|  | 611 | Your weight on VENUS is 90.5 kg | 
|---|
|  | 612 | Your weight on EARTH is 100.0 kg | 
|---|
| [caaf424] | 613 | Your weight on the MOON is 16.6 kg | 
|---|
| [f6321173] | 614 | Your weight on MARS is 37.9 kg | 
|---|
|  | 615 | Your weight on JUPITER is 252.8 kg | 
|---|
|  | 616 | Your weight on SATURN is 106.6 kg | 
|---|
|  | 617 | Your weight on URANUS is 90.5 kg | 
|---|
|  | 618 | Your weight on NEPTUNE is 113.8 kg | 
|---|
| [29092213] | 619 | Your weight on PLUTO is 6.3 kg | 
|---|
| [7d9a805b] | 620 | \end{cfa} | 
|---|
|  | 621 | \caption{Planet Example} | 
|---|
|  | 622 | \label{f:PlanetExample} | 
|---|
|  | 623 | \end{figure} | 
|---|