[7d9a805b] | 1 | \chapter{\CFA Enumeration} |
---|
[956299b] | 2 | |
---|
| 3 | |
---|
[7d9a805b] | 4 | \CFA supports C enumeration using the same syntax and semantics for backwards compatibility. |
---|
[956299b] | 5 | \CFA also extends C-Style enumeration by adding a number of new features that bring enumerations inline with other modern programming languages. |
---|
[f632117] | 6 | Any enumeration extensions must be intuitive to C programmers both in syntax and semantics. |
---|
| 7 | The following sections detail all of my new contributions to enumerations in \CFA. |
---|
[956299b] | 8 | |
---|
| 9 | |
---|
[10a99d87] | 10 | \section{Aliasing} |
---|
| 11 | |
---|
| 12 | {\color{red}@***@} |
---|
| 13 | C already provides @const@-style aliasing using the unnamed enumerator \see{\VRef{s:TypeName}}, even if the keyword @enum@ is misleading (@const@ is better). |
---|
| 14 | However, given the existence of this form, it is straightforward to extend it with heterogeneous types, \ie types other than @int@. |
---|
| 15 | \begin{cfa} |
---|
| 16 | enum { Size = 20u, PI = 3.14159L, Jack = L"John" }; $\C{// not an ADT nor an enumeration}$ |
---|
| 17 | \end{cfa} |
---|
| 18 | which matches with @const@ aliasing in other programming languages. |
---|
| 19 | (See \VRef{s:CenumImplementation} on how @gcc@/@clang@ are doing this for integral types.) |
---|
| 20 | Here, the type of each enumerator is the type of the initialization constant, \eg @typeof(20u)@ for @Size@ implies @unsigned int@. |
---|
| 21 | Auto-initialization is impossible in this case because some types do not support arithmetic. |
---|
| 22 | As seen in \VRef{s:EnumeratorTyping}, this feature is just a shorthand for multiple typed-enumeration declarations. |
---|
[956299b] | 23 | |
---|
[f632117] | 24 | |
---|
[ec20ab9] | 25 | \section{Enumerator Visibility} |
---|
| 26 | \label{s:EnumeratorVisibility} |
---|
[f632117] | 27 | |
---|
[ec20ab9] | 28 | In C, unscoped enumerators present a \newterm{naming problem} when multiple enumeration types appear in the same scope with duplicate enumerator names. |
---|
[bc17be98] | 29 | There is no mechanism in C to resolve these naming conflicts other than renaming one of the duplicates, which may be impossible if the conflict comes from system include files. |
---|
[956299b] | 30 | |
---|
| 31 | The \CFA type-system allows extensive overloading, including enumerators. |
---|
[10a99d87] | 32 | Furthermore, \CFA uses the environment, such as the left-hand of assignment and function arguments, to pinpoint the best overloaded name. |
---|
| 33 | \VRef[Figure]{f:EnumeratorVisibility} shows enumeration overloading and how qualification and casting are used to disambiguate ambiguous situations. |
---|
| 34 | \CFA overloading allows programmers to use the most meaningful names without fear of name clashes within a program or from external sources, like include files. |
---|
| 35 | Experience from \CFA developers is that the type system implicitly and correctly disambiguates the majority of overloaded names. |
---|
| 36 | That is, it is rare to get an incorrect selection or ambiguity, even among hundreds of overloaded variables and functions, that requires disambiguation using qualification or casting. |
---|
| 37 | |
---|
| 38 | \begin{figure} |
---|
[956299b] | 39 | \begin{cfa} |
---|
[7d9a805b] | 40 | enum E1 { First, Second, Third, Fourth }; |
---|
[f632117] | 41 | enum E2 { @Fourth@, @Third@, @Second@, @First@ }; $\C{// same enumerator names}$ |
---|
[bc17be98] | 42 | E1 f() { return Third; } $\C{// overloaded functions, different return types}$ |
---|
| 43 | E2 f() { return Fourth; } |
---|
[10a99d87] | 44 | void g( E1 e ); |
---|
| 45 | void h( E2 e ); |
---|
| 46 | void foo() { $\C{// different resolutions and dealing with ambiguities}$ |
---|
[f632117] | 47 | E1 e1 = First; E2 e2 = First; $\C{// initialization}$ |
---|
| 48 | e1 = Second; e2 = Second; $\C{// assignment}$ |
---|
[dc1c430] | 49 | e1 = f(); e2 = f(); $\C{// function return}$ |
---|
[10a99d87] | 50 | g( First ); h( First ); $\C{// function argument}$ |
---|
[7d9a805b] | 51 | int i = @E1.@First + @E2.@First; $\C{// disambiguate with qualification}$ |
---|
| 52 | int j = @(E1)@First + @(E2)@First; $\C{// disambiguate with cast}$ |
---|
[956299b] | 53 | } |
---|
| 54 | \end{cfa} |
---|
[10a99d87] | 55 | \caption{Enumerator Visibility and Disambiguating} |
---|
| 56 | \label{f:EnumeratorVisibility} |
---|
| 57 | \end{figure} |
---|
[956299b] | 58 | |
---|
| 59 | |
---|
| 60 | \section{Enumerator Scoping} |
---|
| 61 | |
---|
[f632117] | 62 | An enumeration can be scoped, using @'!'@, so the enumerator constants are not projected into the enclosing scope. |
---|
[956299b] | 63 | \begin{cfa} |
---|
[f632117] | 64 | enum Week @!@ { Mon, Tue, Wed, Thu = 10, Fri, Sat, Sun }; |
---|
[7d9a805b] | 65 | enum RGB @!@ { Red, Green, Blue }; |
---|
[956299b] | 66 | \end{cfa} |
---|
[ec20ab9] | 67 | Now the enumerators \emph{must} be qualified with the associated enumeration type. |
---|
[956299b] | 68 | \begin{cfa} |
---|
[f632117] | 69 | Week week = @Week.@Mon; |
---|
| 70 | week = @Week.@Sat; |
---|
| 71 | RGB rgb = @RGB.@Red; |
---|
| 72 | rgb = @RGB.@Blue; |
---|
[956299b] | 73 | \end{cfa} |
---|
[10a99d87] | 74 | {\color{red}@***@}It is possible to toggle back to unscoped using the \CFA @with@ clause/statement (see also \CC \lstinline[language=c++]{using enum} in Section~\ref{s:C++RelatedWork}). |
---|
[956299b] | 75 | \begin{cfa} |
---|
[bc17be98] | 76 | with ( @Week@, @RGB@ ) { $\C{// type names}$ |
---|
| 77 | week = @Sun@; $\C{// no qualification}$ |
---|
[7d9a805b] | 78 | rgb = @Green@; |
---|
[956299b] | 79 | } |
---|
| 80 | \end{cfa} |
---|
[bc17be98] | 81 | As in Section~\ref{s:EnumeratorVisibility}, opening multiple scoped enumerations in a @with@ can result in duplicate enumeration names, but \CFA implicit type resolution and explicit qualification/casting handle this localized scenario. |
---|
| 82 | |
---|
[f632117] | 83 | |
---|
[10a99d87] | 84 | \section{Enumerator Typing} |
---|
[f632117] | 85 | \label{s:EnumeratorTyping} |
---|
[956299b] | 86 | |
---|
| 87 | \CFA extends the enumeration declaration by parameterizing with a type (like a generic type), allowing enumerators to be assigned any values from the declared type. |
---|
| 88 | Figure~\ref{f:EumeratorTyping} shows a series of examples illustrating that all \CFA types can be use with an enumeration and each type's constants used to set the enumerator constants. |
---|
| 89 | Note, the synonyms @Liz@ and @Beth@ in the last declaration. |
---|
[f632117] | 90 | 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@. |
---|
[956299b] | 91 | |
---|
[f632117] | 92 | C has an implicit type conversion from an enumerator to its base type @int@. |
---|
| 93 | Correspondingly, \CFA has an implicit (safe) conversion from a typed enumerator to its base type. |
---|
[956299b] | 94 | \begin{cfa} |
---|
| 95 | char currency = Dollar; |
---|
| 96 | string fred = Fred; $\C{// implicit conversion from char * to \CFA string type}$ |
---|
| 97 | Person student = Beth; |
---|
| 98 | \end{cfa} |
---|
| 99 | |
---|
| 100 | % \begin{cfa} |
---|
| 101 | % struct S { int i, j; }; |
---|
| 102 | % enum( S ) s { A = { 3, 4 }, B = { 7, 8 } }; |
---|
| 103 | % enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$' }; |
---|
| 104 | % enum( @double@ ) Planet { Venus = 4.87, Earth = 5.97, Mars = 0.642 }; // mass |
---|
| 105 | % enum( @char *@ ) Colour { Red = "red", Green = "green", Blue = "blue" }; |
---|
| 106 | % enum( @Currency@ ) Europe { Euro = '$\texteuro$', Pound = '$\textsterling$' }; // intersection |
---|
| 107 | % \end{cfa} |
---|
| 108 | |
---|
| 109 | \begin{figure} |
---|
| 110 | \begin{cfa} |
---|
| 111 | // integral |
---|
[7d9a805b] | 112 | enum( @char@ ) Currency { Dollar = '$\textdollar$', Cent = '$\textcent$', Yen = '$\textyen$', Pound = '$\textsterling$', Euro = 'E' }; |
---|
[956299b] | 113 | enum( @signed char@ ) srgb { Red = -1, Green = 0, Blue = 1 }; |
---|
| 114 | enum( @long long int@ ) BigNum { X = 123_456_789_012_345, Y = 345_012_789_456_123 }; |
---|
| 115 | // non-integral |
---|
| 116 | enum( @double@ ) Math { PI_2 = 1.570796, PI = 3.141597, E = 2.718282 }; |
---|
| 117 | enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i }; |
---|
| 118 | // pointer |
---|
[7d9a805b] | 119 | enum( @const char *@ ) Name { Fred = "FRED", Mary = "MARY", Jane = "JANE" }; |
---|
[956299b] | 120 | int i, j, k; |
---|
| 121 | enum( @int *@ ) ptr { I = &i, J = &j, K = &k }; |
---|
[10a99d87] | 122 | @***@enum( @int &@ ) ref { I = i, J = j, K = k }; |
---|
[956299b] | 123 | // tuple |
---|
[10a99d87] | 124 | @***@enum( @[int, int]@ ) { T = [ 1, 2 ] }; $\C{// new \CFA type}$ |
---|
[956299b] | 125 | // function |
---|
| 126 | void f() {...} void g() {...} |
---|
| 127 | enum( @void (*)()@ ) funs { F = f, G = g }; |
---|
| 128 | // aggregate |
---|
| 129 | struct Person { char * name; int age, height; }; |
---|
[7d9a805b] | 130 | @***@enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz, |
---|
[f632117] | 131 | Jon = { "JONATHAN", 35, 190 } }; |
---|
[956299b] | 132 | \end{cfa} |
---|
| 133 | \caption{Enumerator Typing} |
---|
| 134 | \label{f:EumeratorTyping} |
---|
| 135 | \end{figure} |
---|
| 136 | |
---|
[f632117] | 137 | An advantage of the typed enumerations is eliminating the \emph{harmonizing} problem between an enumeration and companion data \see{\VRef{s:Usage}}: |
---|
[956299b] | 138 | \begin{cfa} |
---|
| 139 | enum( char * ) integral_types { |
---|
| 140 | chr = "char", schar = "signed char", uschar = "unsigned char", |
---|
| 141 | sshort = "signed short int", ushort = "unsigned short int", |
---|
| 142 | sint = "signed int", usint = "unsigned int", |
---|
| 143 | ... |
---|
| 144 | }; |
---|
| 145 | \end{cfa} |
---|
| 146 | Note, 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. |
---|
| 147 | |
---|
[282061a] | 148 | While the enumeration type can be any C aggregate, the aggregate's \CFA constructors are not used to evaluate an enumerator's value. |
---|
| 149 | \CFA enumeration constants are compile-time values (static); |
---|
| 150 | calling constructors happens at runtime (dynamic). |
---|
| 151 | |
---|
[956299b] | 152 | |
---|
[10a99d87] | 153 | \section{Opaque Enumeration} |
---|
[dc1c430] | 154 | |
---|
[10a99d87] | 155 | \CFA provides a special opaque (pure) enumeration type with only assignment and equality operations, and no implicit conversion to any base-type. |
---|
[956299b] | 156 | \begin{cfa} |
---|
[10a99d87] | 157 | enum@()@ Mode { O_RDONLY, O_WRONLY, O_CREAT, O_TRUNC, O_APPEND }; |
---|
| 158 | Mode mode = O_RDONLY; |
---|
| 159 | if ( mode == O_CREAT ) ... |
---|
| 160 | bool b = mode == O_RDONLY || mode @<@ O_APPEND; $\C{// disallowed}$ |
---|
| 161 | int www @=@ mode; $\C{// disallowed}$ |
---|
[956299b] | 162 | \end{cfa} |
---|
[dc1c430] | 163 | |
---|
[10a99d87] | 164 | |
---|
| 165 | \section{Enumeration Operators} |
---|
| 166 | |
---|
| 167 | |
---|
| 168 | \subsection{Conversion} |
---|
| 169 | |
---|
| 170 | \CFA only proves an implicit safe conversion between an enumeration and its base type (like \CC), whereas C allows an unsafe conversion from base type to enumeration. |
---|
| 171 | \begin{cfa} |
---|
| 172 | enum(int) Colour { Red, Blue, Green }; |
---|
| 173 | int w = Red; $\C[1.5in]{// allowed}$ |
---|
| 174 | Colour color = 0; $\C{// disallowed}\CRT$ |
---|
| 175 | \end{cfa} |
---|
| 176 | Unfortunately, there must be one confusing case between C enumerations and \CFA enumeration for type @int@. |
---|
| 177 | \begin{cfa} |
---|
| 178 | enum Colour { Red = 42, Blue, Green }; |
---|
| 179 | enum(int) Colour2 { Red = 16, Blue, Green }; |
---|
| 180 | int w = Redy; $\C[1.5in]{// 42}\CRT$ |
---|
| 181 | \end{cfa} |
---|
| 182 | Programmer intuition is that the assignment to @w@ is ambiguous. |
---|
| 183 | However, converting from @color@ to @int@ is zero cost (no conversion), while from @Colour2@ to @int@ is a safe conversion, which is a higher cost. |
---|
| 184 | This semantics means fewer backwards-compatibility issues with overloaded C and \CFA enumerators. |
---|
| 185 | |
---|
| 186 | |
---|
| 187 | \subsection{Properties} |
---|
| 188 | |
---|
| 189 | \VRef{s:Terminology} introduced three fundamental enumeration properties: label, position, and value. |
---|
| 190 | \CFA provides direct access to these three properties via the functions: @label@, @posn@, and @value@. |
---|
| 191 | \begin{cfa} |
---|
| 192 | enum( const char * ) Name { Fred = "FRED", Mary = "MARY", Jane = "JANE" }; |
---|
| 193 | Name name = Fred; |
---|
| 194 | sout | name | label( name ) | posn( name ) | value( name ); |
---|
| 195 | FRED Fred 0 FRED |
---|
| 196 | \end{cfa} |
---|
| 197 | The default meaning for an enumeration variable in an expression is its value. |
---|
| 198 | |
---|
| 199 | |
---|
| 200 | \subsection{Range} |
---|
| 201 | |
---|
| 202 | The following helper function are used to access and control enumeration ranges (enumerating). |
---|
| 203 | |
---|
| 204 | The pseudo-function @countof@ (like @sizeof@) provides the size (range) of an enumeration or an enumeration instance. |
---|
| 205 | \begin{cfa} |
---|
| 206 | enum(int) Colour { Red, Blue, Green }; |
---|
| 207 | Colour c = Red |
---|
| 208 | sout | countof( Colour ) | countof( c ); |
---|
| 209 | 3 3 |
---|
| 210 | \end{cfa} |
---|
| 211 | @countof@ is a pseudo-function because it takes a type as an argument. |
---|
| 212 | The function @fromInt@ provides a safe subscript of the enumeration. |
---|
| 213 | \begin{cfa} |
---|
| 214 | Colour r = fromInt( prng( countof( Colour ) ) ); // select random colour |
---|
| 215 | \end{cfa} |
---|
| 216 | The functions @lowerBound@, @upperBound@, @succ@, and @pred@ are for enumerating. |
---|
| 217 | \begin{cfa} |
---|
| 218 | for ( Colour c = lowerBound();; ) { |
---|
| 219 | sout | c | nonl; |
---|
| 220 | if ( c == upperBound() ) break; |
---|
| 221 | c = succ( c ); |
---|
| 222 | } |
---|
| 223 | \end{cfa} |
---|
| 224 | Note, the mid-exit loop is necessary to prevent triggering a @succ@ bound check, as in: |
---|
| 225 | \begin{cfa} |
---|
| 226 | for ( Colour c = lowerBound(); c <= upperBound(); c = succ( c ) ) ... // generates error |
---|
| 227 | \end{cfa} |
---|
| 228 | When @c == upperBound()@, the loop control still invokes @succ( c )@, which causes an @enumBound@ exception. |
---|
| 229 | Finally, there is operational overlap between @countof@ and @upperBound@. |
---|
| 230 | |
---|
| 231 | |
---|
| 232 | \section{Enumeration Inheritance} |
---|
| 233 | |
---|
| 234 | \CFA Plan-9 inheritance may be used with enumerations, where Plan-9 inheritance is containment inheritance with implicit unscoping (like a nested unnamed @struct@/@union@ in C). |
---|
| 235 | \begin{cfa} |
---|
| 236 | enum( const char * ) Names { Fred = "FRED", Mary = "MARY", Jane = "JANE" }; |
---|
| 237 | enum( const char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" }; |
---|
| 238 | enum( const char * ) Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" }; |
---|
| 239 | \end{cfa} |
---|
[956299b] | 240 | Enumeration @Name2@ inherits all the enumerators and their values from enumeration @Names@ by containment, and a @Names@ enumeration is a subtype of enumeration @Name2@. |
---|
[09dd830] | 241 | Note, that enumerators must be unique in inheritance but enumerator values may be repeated. |
---|
[956299b] | 242 | |
---|
[dc1c430] | 243 | % The enumeration type for the inheriting type must be the same as the inherited type; |
---|
| 244 | % hence the enumeration type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for @Name3@. |
---|
[956299b] | 245 | % When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important. |
---|
| 246 | Specifically, the inheritance relationship for @Names@ is: |
---|
| 247 | \begin{cfa} |
---|
[10a99d87] | 248 | Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\C{// enum type of Names}$ |
---|
[dc1c430] | 249 | \end{cfa} |
---|
[10a99d87] | 250 | A subtype can be cast to its supertype, assigned to a supertype variable, or used as a function argument that expects the supertype. |
---|
[dc1c430] | 251 | \begin{cfa} |
---|
[10a99d87] | 252 | Names fred = Names.Fred; |
---|
| 253 | (Names2)fred; (Names3)fred; (Names3)Names2.Jack; $\C{// cast to super type}$ |
---|
| 254 | Names2 fred2 = fred; Names3 fred3 = fred2; $\C{// assign to super type}$ |
---|
| 255 | \end{cfa} |
---|
| 256 | As well, there is the implicit cast to an enumerator's base-type. |
---|
| 257 | \begin{cfa} |
---|
| 258 | const char * name = fred; |
---|
[956299b] | 259 | \end{cfa} |
---|
| 260 | For the given function prototypes, the following calls are valid. |
---|
| 261 | \begin{cquote} |
---|
| 262 | \begin{tabular}{ll} |
---|
| 263 | \begin{cfa} |
---|
| 264 | void f( Names ); |
---|
| 265 | void g( Names2 ); |
---|
| 266 | void h( Names3 ); |
---|
| 267 | void j( const char * ); |
---|
| 268 | \end{cfa} |
---|
| 269 | & |
---|
| 270 | \begin{cfa} |
---|
| 271 | f( Fred ); |
---|
| 272 | g( Fred ); g( Jill ); |
---|
| 273 | h( Fred ); h( Jill ); h( Sue ); |
---|
[dc1c430] | 274 | j( Fred ); j( Jill ); j( Sue ); j( "WILL" ); |
---|
[956299b] | 275 | \end{cfa} |
---|
| 276 | \end{tabular} |
---|
| 277 | \end{cquote} |
---|
| 278 | 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. |
---|
| 279 | |
---|
[10a99d87] | 280 | |
---|
[f632117] | 281 | \section{Enumerator Control Structures} |
---|
[956299b] | 282 | |
---|
| 283 | Enumerators can be used in multiple contexts. |
---|
| 284 | In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution). |
---|
| 285 | However, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect in some contexts. |
---|
[09dd830] | 286 | In these contexts, a programmer's initition assumes an implicit conversion to position. |
---|
[956299b] | 287 | |
---|
[09dd830] | 288 | 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] | 289 | (For this discussion, ignore the fact that @case@ requires a compile-time constant.) |
---|
| 290 | \begin{cfa}[belowskip=0pt] |
---|
[956299b] | 291 | enum Count { First, Second, Third, Fourth }; |
---|
| 292 | Count e; |
---|
| 293 | \end{cfa} |
---|
[10a99d87] | 294 | \begin{cquote} |
---|
| 295 | \setlength{\tabcolsep}{15pt} |
---|
| 296 | \noindent |
---|
| 297 | \begin{tabular}{@{}ll@{}} |
---|
| 298 | \begin{cfa}[aboveskip=0pt] |
---|
[956299b] | 299 | |
---|
| 300 | choose( e ) { |
---|
| 301 | case @First@: ...; |
---|
| 302 | case @Second@: ...; |
---|
| 303 | case @Third@: ...; |
---|
| 304 | case @Fourth@: ...; |
---|
| 305 | } |
---|
| 306 | \end{cfa} |
---|
| 307 | & |
---|
[10a99d87] | 308 | \begin{cfa}[aboveskip=0pt] |
---|
[956299b] | 309 | // rewrite |
---|
| 310 | choose( @value@( e ) ) { |
---|
| 311 | case @value@( First ): ...; |
---|
| 312 | case @value@( Second ): ...; |
---|
| 313 | case @value@( Third ): ...; |
---|
| 314 | case @value@( Fourth ): ...; |
---|
| 315 | } |
---|
| 316 | \end{cfa} |
---|
| 317 | \end{tabular} |
---|
| 318 | \end{cquote} |
---|
[de3a579] | 319 | 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] | 320 | However, this implementation is fragile, \eg if the enumeration is changed to: |
---|
[956299b] | 321 | \begin{cfa} |
---|
| 322 | enum Count { First, Second, Third @= First@, Fourth }; |
---|
| 323 | \end{cfa} |
---|
[10a99d87] | 324 | making @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicate @case@ clauses. |
---|
[ec20ab9] | 325 | To better match with programmer intuition, \CFA toggles between value and position semantics depending on the language context. |
---|
[09dd830] | 326 | For conditional clauses and switch statements, \CFA uses the robust position implementation. |
---|
[956299b] | 327 | \begin{cfa} |
---|
[10a99d87] | 328 | if ( @posn@( e ) < posn( Third ) ) ... |
---|
| 329 | choose( @posn@( e ) ) { |
---|
| 330 | case @posn@( First ): ...; |
---|
| 331 | case @posn@( Second ): ...; |
---|
| 332 | case @posn@( Third ): ...; |
---|
| 333 | case @posn@( Fourth ): ...; |
---|
[956299b] | 334 | } |
---|
| 335 | \end{cfa} |
---|
| 336 | |
---|
[10a99d87] | 337 | \CFA provides a special form of for-control for enumerating through an enumeration, where the range is a type. |
---|
[956299b] | 338 | \begin{cfa} |
---|
[10a99d87] | 339 | for ( cx; @Count@ ) { sout | cx | nonl; } sout | nl; |
---|
| 340 | for ( cx; +~= Count ) { sout | cx | nonl; } sout | nl; |
---|
| 341 | for ( cx; -~= Count ) { sout | cx | nonl; } sout | nl; |
---|
| 342 | First Second Third Fourth |
---|
| 343 | First Second Third Fourth |
---|
| 344 | Fourth Third Second First |
---|
[956299b] | 345 | \end{cfa} |
---|
[10a99d87] | 346 | 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. |
---|
| 347 | The prefix @+~=@ or @-~=@ iterate forward or backwards through the inclusive enumeration range, where no prefix defaults to @+~=@. |
---|
[7d9a805b] | 348 | |
---|
[10a99d87] | 349 | C has an idiom for @if@ and loop predicates of comparing the predicate result ``not equal to 0''. |
---|
[dc1c430] | 350 | \begin{cfa} |
---|
[10a99d87] | 351 | if ( x + y /* != 0 */ ) ... |
---|
| 352 | while ( p /* != 0 */ ) ... |
---|
[dc1c430] | 353 | \end{cfa} |
---|
[10a99d87] | 354 | This idiom extends to enumerations because there is a boolean conversion in terms of the enumeration value, if and only if such a conversion is available. |
---|
| 355 | For example, such a conversion exists for all numerical types (integral and floating-point). |
---|
| 356 | It is possible to explicitly extend this idiom to any typed enumeration by overloading the @!=@ operator. |
---|
[dc1c430] | 357 | \begin{cfa} |
---|
[10a99d87] | 358 | bool ?!=?( Name n, zero_t ) { return n != Fred; } |
---|
| 359 | Name n = Mary; |
---|
| 360 | if ( n ) ... // result is true |
---|
[dc1c430] | 361 | \end{cfa} |
---|
[10a99d87] | 362 | Specialize meanings are also possible. |
---|
[dc1c430] | 363 | \begin{cfa} |
---|
| 364 | enum(int) ErrorCode { Normal = 0, Slow = 1, Overheat = 1000, OutOfResource = 1001 }; |
---|
[10a99d87] | 365 | bool ?!=?( ErrorCode ec, zero_t ) { return ec >= Overheat; } |
---|
| 366 | ErrorCode code = ...; |
---|
| 367 | if ( code ) { problem(); } |
---|
[dc1c430] | 368 | \end{cfa} |
---|
[7d9a805b] | 369 | |
---|
[f632117] | 370 | |
---|
[10a99d87] | 371 | \section{Enumeration Dimension} |
---|
[f632117] | 372 | |
---|
[10a99d87] | 373 | \VRef{s:EnumeratorTyping} introduced the harmonizing problem between an enumeration and secondary information. |
---|
| 374 | When possible, using a typed enumeration for the secondary information is the best approach. |
---|
| 375 | However, there are times when combining these two types is not possible. |
---|
| 376 | For example, the secondary information might precede the enumeration and/or its type is needed directly to declare parameters of functions. |
---|
| 377 | In these cases, having secondary arrays of the enumeration size are necessary. |
---|
[f632117] | 378 | |
---|
[10a99d87] | 379 | 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. |
---|
[d69f7114] | 380 | \begin{cfa} |
---|
[10a99d87] | 381 | enum E { A, B, C, N }; // possibly predefined |
---|
| 382 | float H1[N] = { [A] : 3.4, [B] : 7.1, [C] : 0.01 }; // C |
---|
| 383 | float H2[@E@] = { [A] : 3.4, [B] : 7.1, [C] : 0.01 }; // CFA |
---|
[d69f7114] | 384 | \end{cfa} |
---|
[10a99d87] | 385 | (Note, C uses the symbol, @'='@ for designator initialization, but \CFA had to change to @':'@ because of problems with tuple syntax.) |
---|
| 386 | This approach is also necessary for a predefined typed enumeration (unchangeable), when additional secondary-information need to be added. |
---|
[d69f7114] | 387 | |
---|
[bc17be98] | 388 | |
---|
[6f47834] | 389 | \section{Enumeration I/O} |
---|
| 390 | |
---|
| 391 | As seen in multiple examples, enumerations can be printed and the default property printed is the enumerator's label, which is similar in other programming languages. |
---|
| 392 | However, very few programming languages provide a mechanism to read in enumerator values. |
---|
| 393 | Even the @boolean@ type in many languages does not have a mechanism for input using the enumerators @true@ or @false@. |
---|
| 394 | \VRef[Figure]{f:EnumerationI/O} show \CFA enumeration input based on the enumerator labels. |
---|
| 395 | When the enumerator labels are packed together in the input stream, the input algorithm scans for the longest matching string. |
---|
| 396 | For basic types in \CFA, the constants use to initialize a variable in a program are available to initialize a variable using input, where strings constants can be quoted or unquoted. |
---|
| 397 | |
---|
| 398 | \begin{figure} |
---|
| 399 | \begin{cquote} |
---|
| 400 | \setlength{\tabcolsep}{15pt} |
---|
| 401 | \begin{tabular}{@{}ll@{}} |
---|
| 402 | \begin{cfa} |
---|
| 403 | int main() { |
---|
| 404 | enum(int ) E { BBB = 3, AAA, AA, AB, B }; |
---|
| 405 | E e; |
---|
| 406 | |
---|
| 407 | for () { |
---|
| 408 | try { |
---|
| 409 | @sin | e@; |
---|
| 410 | } catch( missing_data * ) { |
---|
| 411 | sout | "missing data"; |
---|
| 412 | continue; // try again |
---|
| 413 | } |
---|
| 414 | if ( eof( sin ) ) break; |
---|
| 415 | sout | e | "= " | value( e ); |
---|
| 416 | } |
---|
| 417 | } |
---|
| 418 | \end{cfa} |
---|
| 419 | & |
---|
| 420 | \begin{cfa} |
---|
| 421 | $\rm input$ |
---|
| 422 | BBBABAAAAB |
---|
| 423 | BBB AAA AA AB B |
---|
| 424 | |
---|
| 425 | $\rm output$ |
---|
| 426 | BBB = 3 |
---|
| 427 | AB = 6 |
---|
| 428 | AAA = 4 |
---|
| 429 | AB = 6 |
---|
| 430 | BBB = 3 |
---|
| 431 | AAA = 4 |
---|
| 432 | AA = 5 |
---|
| 433 | AB = 6 |
---|
| 434 | B = 7 |
---|
| 435 | |
---|
| 436 | \end{cfa} |
---|
| 437 | \end{tabular} |
---|
| 438 | \end{cquote} |
---|
| 439 | \caption{Enumeration I/O} |
---|
| 440 | \label{f:EnumerationI/O} |
---|
| 441 | \end{figure} |
---|
| 442 | |
---|
| 443 | |
---|
| 444 | |
---|
[7d9a805b] | 445 | \section{Planet Example} |
---|
| 446 | |
---|
[f632117] | 447 | \VRef[Figure]{f:PlanetExample} shows an archetypal enumeration example illustrating most of the \CFA enumeration features. |
---|
[caaf424] | 448 | @Planet@ is an enumeration of type @MR@. |
---|
[09dd830] | 449 | Each planet enumerator is initialized to a specific mass/radius, @MR@, value. |
---|
[caaf424] | 450 | The unnamed enumeration provides the gravitational-constant enumerator @G@. |
---|
| 451 | Function @surfaceGravity@ uses the @with@ clause to remove @p@ qualification from fields @mass@ and @radius@. |
---|
[29092213] | 452 | 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@. |
---|
| 453 | The resulting random orbital-body is used in a @choose@ statement. |
---|
[09dd830] | 454 | The enumerators in the @case@ clause use the enumerator position for testing. |
---|
[29092213] | 455 | The prints use @label@ to print an enumerator's name. |
---|
| 456 | Finally, a loop enumerates through the planets computing the weight on each planet for a given earth mass. |
---|
| 457 | The print statement does an equality comparison with an enumeration variable and enumerator (@p == MOON@). |
---|
[7d9a805b] | 458 | |
---|
| 459 | \begin{figure} |
---|
[caaf424] | 460 | \small |
---|
[7d9a805b] | 461 | \begin{cfa} |
---|
[10a99d87] | 462 | struct MR { double mass, radius; }; $\C{// planet definition}$ |
---|
[29092213] | 463 | enum( @MR@ ) Planet { $\C{// typed enumeration}$ |
---|
[f632117] | 464 | // mass (kg) radius (km) |
---|
| 465 | MERCURY = { 0.330_E24, 2.4397_E6 }, |
---|
| 466 | VENUS = { 4.869_E24, 6.0518_E6 }, |
---|
[7d9a805b] | 467 | EARTH = { 5.976_E24, 6.3781_E6 }, |
---|
[29092213] | 468 | MOON = { 7.346_E22, 1.7380_E6 }, $\C{// not a planet}$ |
---|
[f632117] | 469 | MARS = { 0.642_E24, 3.3972_E6 }, |
---|
| 470 | JUPITER = { 1898._E24, 71.492_E6 }, |
---|
| 471 | SATURN = { 568.8_E24, 60.268_E6 }, |
---|
| 472 | URANUS = { 86.86_E24, 25.559_E6 }, |
---|
| 473 | NEPTUNE = { 102.4_E24, 24.746_E6 }, |
---|
[29092213] | 474 | PLUTO = { 1.303_E22, 1.1880_E6 }, $\C{// not a planet}$ |
---|
[7d9a805b] | 475 | }; |
---|
[29092213] | 476 | enum( double ) { G = 6.6743_E-11 }; $\C{// universal gravitational constant (m3 kg-1 s-2)}$ |
---|
[caaf424] | 477 | static double surfaceGravity( Planet p ) @with( p )@ { |
---|
[29092213] | 478 | return G * mass / ( radius @\@ 2 ); $\C{// no qualification, exponentiation}$ |
---|
[7d9a805b] | 479 | } |
---|
| 480 | static double surfaceWeight( Planet p, double otherMass ) { |
---|
| 481 | return otherMass * surfaceGravity( p ); |
---|
| 482 | } |
---|
| 483 | int main( int argc, char * argv[] ) { |
---|
[29092213] | 484 | if ( argc != 2 ) @exit@ | "Usage: " | argv[0] | "earth-weight"; // terminate program |
---|
[7d9a805b] | 485 | double earthWeight = convert( argv[1] ); |
---|
[d69f7114] | 486 | double earthMass = earthWeight / surfaceGravity( EARTH ); |
---|
[29092213] | 487 | Planet rp = @fromInt@( prng( @countof@( Planet ) ) ); $\C{// select random orbiting body}$ |
---|
| 488 | @choose( rp )@ { $\C{// implicit breaks}$ |
---|
[caaf424] | 489 | case MERCURY, VENUS, EARTH, MARS: |
---|
[62a38e7] | 490 | sout | @rp@ | "is a rocky planet"; |
---|
[29092213] | 491 | case JUPITER, SATURN, URANUS, NEPTUNE: |
---|
[62a38e7] | 492 | sout | rp | "is a gas-giant planet"; |
---|
[caaf424] | 493 | default: |
---|
[62a38e7] | 494 | sout | rp | "is not a planet"; |
---|
[caaf424] | 495 | } |
---|
[29092213] | 496 | for ( @p; Planet@ ) { $\C{// enumerate}$ |
---|
[62a38e7] | 497 | sout | "Your weight on" | ( @p == MOON@ ? "the" : " " ) | p |
---|
[29092213] | 498 | | "is" | wd( 1,1, surfaceWeight( p, earthMass ) ) | "kg"; |
---|
[7d9a805b] | 499 | } |
---|
| 500 | } |
---|
[f632117] | 501 | $\$$ planet 100 |
---|
[caaf424] | 502 | JUPITER is a gas-giant planet |
---|
[f632117] | 503 | Your weight on MERCURY is 37.7 kg |
---|
| 504 | Your weight on VENUS is 90.5 kg |
---|
| 505 | Your weight on EARTH is 100.0 kg |
---|
[caaf424] | 506 | Your weight on the MOON is 16.6 kg |
---|
[f632117] | 507 | Your weight on MARS is 37.9 kg |
---|
| 508 | Your weight on JUPITER is 252.8 kg |
---|
| 509 | Your weight on SATURN is 106.6 kg |
---|
| 510 | Your weight on URANUS is 90.5 kg |
---|
| 511 | Your weight on NEPTUNE is 113.8 kg |
---|
[29092213] | 512 | Your weight on PLUTO is 6.3 kg |
---|
[7d9a805b] | 513 | \end{cfa} |
---|
| 514 | \caption{Planet Example} |
---|
| 515 | \label{f:PlanetExample} |
---|
| 516 | \end{figure} |
---|