| 1 | \chapter{\CFA Enumeration}
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 | \CFA supports C enumeration using the same syntax and semantics for backwards compatibility.
|
|---|
| 5 | \CFA also extends C-Style enumeration by adding a number of new features that bring enumerations inline with other modern programming languages.
|
|---|
| 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.
|
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 | \section{Aliasing}
|
|---|
| 11 |
|
|---|
| 12 | C already provides @const@-style aliasing using the unnamed enumerator \see{\VRef{s:TypeName}}, even if the name @enum@ is misleading (@const@ would be better).
|
|---|
| 13 | Given the existence of this form, it is straightforward to extend it with types other than @int@.
|
|---|
| 14 | \begin{cfa}
|
|---|
| 15 | enum E { Size = 20u, PI = 3.14159L, Jack = L"John" };
|
|---|
| 16 | \end{cfa}
|
|---|
| 17 | which matches with @const@ aliasing in other programming languages.
|
|---|
| 18 | Here, the type of the enumerator is the type of the initialization constant, \eg @typeof(20u)@ for @Size@ implies @unsigned int@.
|
|---|
| 19 | Auto-initialization is restricted to the case where all constants are @int@, matching with C.
|
|---|
| 20 | As seen in \VRef{s:EnumeratorTyping}, this feature is just a shorthand for multiple typed-enumeration declarations.
|
|---|
| 21 |
|
|---|
| 22 |
|
|---|
| 23 | \section{Enumerator Visibility}
|
|---|
| 24 | \label{s:EnumeratorVisibility}
|
|---|
| 25 |
|
|---|
| 26 | In C, unscoped enumerators present a \newterm{naming problem} when multiple enumeration types appear in the same scope with duplicate enumerator names.
|
|---|
| 27 | There is no mechanism in C to resolve these naming conflicts other than renaming one of the duplicates, which may be impossible.
|
|---|
| 28 |
|
|---|
| 29 | The \CFA type-system allows extensive overloading, including enumerators.
|
|---|
| 30 | Furthermore, \CFA uses the left-hand of assignment in type resolution to pinpoint the best overloaded name.
|
|---|
| 31 | Finally, qualification and casting are provided to disambiguate any ambiguous situations.
|
|---|
| 32 | \begin{cfa}
|
|---|
| 33 | enum E1 { First, Second, Third, Fourth };
|
|---|
| 34 | enum E2 { @Fourth@, @Third@, @Second@, @First@ }; $\C{// same enumerator names}$
|
|---|
| 35 | E1 p() { return Third; } $\C{// return}$
|
|---|
| 36 | E2 p() { return Fourth; }
|
|---|
| 37 | void foo() {
|
|---|
| 38 | E1 e1 = First; E2 e2 = First; $\C{// initialization}$
|
|---|
| 39 | e1 = Second; e2 = Second; $\C{// assignment}$
|
|---|
| 40 | e1 = p(); e2 = p(); $\C{// function call}$
|
|---|
| 41 | int i = @E1.@First + @E2.@First; $\C{// disambiguate with qualification}$
|
|---|
| 42 | int j = @(E1)@First + @(E2)@First; $\C{// disambiguate with cast}$
|
|---|
| 43 | }
|
|---|
| 44 | \end{cfa}
|
|---|
| 45 | \CFA overloading allows programmers to use the most meaningful names without fear of name clashes from include files.
|
|---|
| 46 | In most cases, the type system implicitly disambiguates, otherwise the programmer explicitly disambiguates using qualification or casting.
|
|---|
| 47 |
|
|---|
| 48 |
|
|---|
| 49 | \section{Enumerator Scoping}
|
|---|
| 50 |
|
|---|
| 51 | An enumeration can be scoped, using @'!'@, so the enumerator constants are not projected into the enclosing scope.
|
|---|
| 52 | \begin{cfa}
|
|---|
| 53 | enum Week @!@ { Mon, Tue, Wed, Thu = 10, Fri, Sat, Sun };
|
|---|
| 54 | enum RGB @!@ { Red, Green, Blue };
|
|---|
| 55 | \end{cfa}
|
|---|
| 56 | Now the enumerators \emph{must} be qualified with the associated enumeration type.
|
|---|
| 57 | \begin{cfa}
|
|---|
| 58 | Week week = @Week.@Mon;
|
|---|
| 59 | week = @Week.@Sat;
|
|---|
| 60 | RGB rgb = @RGB.@Red;
|
|---|
| 61 | rgb = @RGB.@Blue;
|
|---|
| 62 | \end{cfa}
|
|---|
| 63 | It is possible to toggle back to unscoping using the \CFA @with@ clause/statement (see also \CC \lstinline[language=c++]{using enum} in Section~\ref{s:C++RelatedWork}).
|
|---|
| 64 | \begin{cfa}
|
|---|
| 65 | with ( @Week@, @RGB@ ) { $\C{// type names}$
|
|---|
| 66 | week = @Sun@; $\C{// no qualification}$
|
|---|
| 67 | rgb = @Green@;
|
|---|
| 68 | }
|
|---|
| 69 | \end{cfa}
|
|---|
| 70 | 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 ambiguities.
|
|---|
| 71 |
|
|---|
| 72 | \section{Enumeration Trait}
|
|---|
| 73 |
|
|---|
| 74 | The header file \lstinline[deletekeywords=enum]{<enum.hfa>} defines the set of traits containing operators and helper functions for @enum@.
|
|---|
| 75 | A \CFA enumeration satisfies all of these traits allowing it to interact with runtime features in \CFA.
|
|---|
| 76 | Each trait is discussed in detail.
|
|---|
| 77 |
|
|---|
| 78 | The trait @Bounded@:
|
|---|
| 79 | \begin{cfa}
|
|---|
| 80 | forall( E ) trait Bounded {
|
|---|
| 81 | E first();
|
|---|
| 82 | E last();
|
|---|
| 83 | };
|
|---|
| 84 | \end{cfa}
|
|---|
| 85 | defines the bounds of the enumeration, where @first()@ returns the first enumerator and @last()@ returns the last, \eg:
|
|---|
| 86 | \begin{cfa}
|
|---|
| 87 | Workday day = first(); $\C{// Mon}$
|
|---|
| 88 | Planet outermost = last(); $\C{// NEPTUNE}$
|
|---|
| 89 | \end{cfa}
|
|---|
| 90 | @first()@ and @last()@ are overloaded with return types only, so in the example, the enumeration type is found on the left-hand side of the assignment.
|
|---|
| 91 | Calling either functions without a context results in a type ambiguity, except in the rare case where the type environment has only one enumeration.
|
|---|
| 92 | \begin{cfa}
|
|---|
| 93 | @first();@ $\C{// ambiguous Workday and Planet implement Bounded}$
|
|---|
| 94 | sout | @last()@;
|
|---|
| 95 | Workday day = first(); $\C{// day provides type Workday}$
|
|---|
| 96 | void foo( Planet p );
|
|---|
| 97 | foo( last() ); $\C{// parameter provides type Planet}$
|
|---|
| 98 | \end{cfa}
|
|---|
| 99 |
|
|---|
| 100 | The trait @Serial@:
|
|---|
| 101 | \begin{cfa}
|
|---|
| 102 | forall( E | Bounded( E ) ) trait Serial {
|
|---|
| 103 | unsigned fromInstance( E e );
|
|---|
| 104 | E fromInt( unsigned int posn );
|
|---|
| 105 | E succ( E e );
|
|---|
| 106 | E pred( E e );
|
|---|
| 107 | };
|
|---|
| 108 | \end{cfa}
|
|---|
| 109 | is a @Bounded@ trait, where elements can be mapped to an integer sequence.
|
|---|
| 110 | A type @T@ matching @Serial@ can project to an unsigned @int@ type, \ie an instance of type T has a corresponding integer value.
|
|---|
| 111 | %However, the inverse may not be possible, and possible requires a bound check.
|
|---|
| 112 | The mapping from a serial type to integer is defined by @fromInstance@, which returns the enumerator's position.
|
|---|
| 113 | The inverse operation is @fromInt@, which performs a bound check using @first()@ and @last()@ before casting the integer into an enumerator.
|
|---|
| 114 | Specifically, for enumerator @E@ declaring $N$ enumerators, @fromInt( i )@ returns the $i-1_{th}$ enumerator, if $0 \leq i < N$, or raises the exception @enumBound@.
|
|---|
| 115 |
|
|---|
| 116 | The @Serial@ trait also requires interface functions @succ( E e )@ and @pred( E e )@ be implemented for a serial type, which imply the enumeration positions are consecutive and ordinal.
|
|---|
| 117 | Specifically, if @e@ is the $i_{th}$ enumerator, @succ( e )@ returns the $i+1_{th}$ enumerator when $e \ne last()$, and @pred( e )@ returns the $i-1_{th}$ enumerator when $e \ne first()$.
|
|---|
| 118 | The exception @enumRange@ is raised if the result of either operation is outside the range of type @E@.
|
|---|
| 119 |
|
|---|
| 120 | The trait @TypedEnum@:
|
|---|
| 121 | \begin{cfa}
|
|---|
| 122 | forall( E, T ) trait TypedEnum {
|
|---|
| 123 | T valueE( E e );
|
|---|
| 124 | char * labelE( E e );
|
|---|
| 125 | unsigned int posE( E e );
|
|---|
| 126 | };
|
|---|
| 127 | \end{cfa}
|
|---|
| 128 | captures three basic attributes of an enumeration type: value, label, and position.
|
|---|
| 129 | @TypedEnum@ asserts two types @E@ and @T@, with @T@ being the base type of the enumeration @E@, \eg @enum( T ) E { ... };@.
|
|---|
| 130 | Implementing general functions across all enumeration types is possible by asserting @TypeEnum( E, T )@, \eg:
|
|---|
| 131 | \begin{cfa}
|
|---|
| 132 | forall( E, T | TypeEnum( E, T ) )
|
|---|
| 133 | void printEnum( E e ) {
|
|---|
| 134 | sout | "Enum "| labelE( e );
|
|---|
| 135 | }
|
|---|
| 136 | printEunm( MARS );
|
|---|
| 137 | \end{cfa}
|
|---|
| 138 |
|
|---|
| 139 | Finally, there is an associated trait defining comparison operators among enumerators.
|
|---|
| 140 | \begin{cfa}
|
|---|
| 141 | forall( E, T | TypedEnum( E, T ) ) {
|
|---|
| 142 | // comparison
|
|---|
| 143 | int ?==?( E l, E r ); $\C{// true if l and r are same enumerators}$
|
|---|
| 144 | int ?!=?( E l, E r ); $\C{// true if l and r are different enumerators}$
|
|---|
| 145 | int ?!=?( E l, zero_t ); $\C{// true if l is not the first enumerator}$
|
|---|
| 146 | int ?<?( E l, E r ); $\C{// true if l is an enumerator before r}$
|
|---|
| 147 | int ?<=?( E l, E r ); $\C{// true if l before or the same as r}$
|
|---|
| 148 | int ?>?( E l, E r ); $\C{// true if l is an enumerator after r}$
|
|---|
| 149 | int ?>=?( E l, E r ); $\C{// true if l after or the same as r}$
|
|---|
| 150 | }
|
|---|
| 151 | \end{cfa}
|
|---|
| 152 | Note, the overloaded operators are defined only when the header @<enum.hfa>@ is included.
|
|---|
| 153 | If not, the compiler converts an enumerator to its value, and applies the operators defined for the value type @E@, \eg:
|
|---|
| 154 | \begin{cfa}
|
|---|
| 155 | // if not include <enum.hfa>
|
|---|
| 156 | enum( int ) Fruits { APPLE = 2, BANANA = 10, CHERRY = 2 };
|
|---|
| 157 | APPLE == CHERRY; // true because valueE( APPLE ) == valueE( CHERRY )
|
|---|
| 158 |
|
|---|
| 159 | #include <enum.hfa>
|
|---|
| 160 | APPLE == CHERRY; // false because posE( APPLE ) != posE( CHERRY )
|
|---|
| 161 | \end{cfa}
|
|---|
| 162 | An enumerator returns its @position@ by default.
|
|---|
| 163 | In particular, @printf( ... )@ from @<stdio.h>@ functions provides no context to its parameter type, so it prints @position@.
|
|---|
| 164 | On the other hand, the pipeline operator @?|?( ostream os, E enumType )@ provides type context for type @E@, and \CFA has overwritten this operator to print the enumeration @value@ over @position@.
|
|---|
| 165 | \begin{cfa}
|
|---|
| 166 | printf( "Position of BANANA is \%d", BANANA ); // Position of BANANA is 1
|
|---|
| 167 | sout | "Value of BANANA is " | BANANA; // Value of BANANA is 10
|
|---|
| 168 | \end{cfa}
|
|---|
| 169 | Programmers can overwrite this behaviour by overloading the pipeline operator themselves.
|
|---|
| 170 | \PAB{This needs discussing because including \lstinline{<enum.hfa>} can change the entire meaning of a program.}
|
|---|
| 171 |
|
|---|
| 172 |
|
|---|
| 173 | % \section{Enumeration Pseudo-functions}
|
|---|
| 174 |
|
|---|
| 175 | % Pseudo-functions are function-like operators that do not result in any run-time computations, \ie like @sizeof@, @alignof@, @typeof@.
|
|---|
| 176 | % A pseudo-function call is often substituted with information extracted from the compilation symbol-table, like storage size or alignment associated with the underlying architecture.
|
|---|
| 177 |
|
|---|
| 178 | % The attributes of an enumerator are accessed by pseudo-functions @posE@, @valueE@, and @labelE@.
|
|---|
| 179 | % \begin{cfa}
|
|---|
| 180 | % int jane_pos = @posE@( Names.Jane ); $\C{// 2}$
|
|---|
| 181 | % char * jane_value = @valueE@( Names.Jane ); $\C{// "JANE"}$
|
|---|
| 182 | % char * jane_label = @labelE@( Names.Jane ); $\C{// "Jane"}$
|
|---|
| 183 | % sout | posE( Names.Jane) | labelE( Names.Jane ) | valueE( Names.Jane );
|
|---|
| 184 | % \end{cfa}
|
|---|
| 185 | % Note the ability to print all of an enumerator's properties.
|
|---|
| 186 |
|
|---|
| 187 |
|
|---|
| 188 |
|
|---|
| 189 | \section{Enumerator Typing}
|
|---|
| 190 | \label{s:EnumeratorTyping}
|
|---|
| 191 |
|
|---|
| 192 | \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.
|
|---|
| 193 | 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.
|
|---|
| 194 | Note, the synonyms @Liz@ and @Beth@ in the last declaration.
|
|---|
| 195 | 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@.
|
|---|
| 196 |
|
|---|
| 197 | C has an implicit type conversion from an enumerator to its base type @int@.
|
|---|
| 198 | Correspondingly, \CFA has an implicit (safe) conversion from a typed enumerator to its base type.
|
|---|
| 199 | \begin{cfa}
|
|---|
| 200 | char currency = Dollar;
|
|---|
| 201 | string fred = Fred; $\C{// implicit conversion from char * to \CFA string type}$
|
|---|
| 202 | Person student = Beth;
|
|---|
| 203 | \end{cfa}
|
|---|
| 204 |
|
|---|
| 205 | % \begin{cfa}
|
|---|
| 206 | % struct S { int i, j; };
|
|---|
| 207 | % enum( S ) s { A = { 3, 4 }, B = { 7, 8 } };
|
|---|
| 208 | % enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$' };
|
|---|
| 209 | % enum( @double@ ) Planet { Venus = 4.87, Earth = 5.97, Mars = 0.642 }; // mass
|
|---|
| 210 | % enum( @char *@ ) Colour { Red = "red", Green = "green", Blue = "blue" };
|
|---|
| 211 | % enum( @Currency@ ) Europe { Euro = '$\texteuro$', Pound = '$\textsterling$' }; // intersection
|
|---|
| 212 | % \end{cfa}
|
|---|
| 213 |
|
|---|
| 214 | \begin{figure}
|
|---|
| 215 | \begin{cfa}
|
|---|
| 216 | // integral
|
|---|
| 217 | enum( @char@ ) Currency { Dollar = '$\textdollar$', Cent = '$\textcent$', Yen = '$\textyen$', Pound = '$\textsterling$', Euro = 'E' };
|
|---|
| 218 | enum( @signed char@ ) srgb { Red = -1, Green = 0, Blue = 1 };
|
|---|
| 219 | enum( @long long int@ ) BigNum { X = 123_456_789_012_345, Y = 345_012_789_456_123 };
|
|---|
| 220 | // non-integral
|
|---|
| 221 | enum( @double@ ) Math { PI_2 = 1.570796, PI = 3.141597, E = 2.718282 };
|
|---|
| 222 | enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i };
|
|---|
| 223 | // pointer
|
|---|
| 224 | enum( @const char *@ ) Name { Fred = "FRED", Mary = "MARY", Jane = "JANE" };
|
|---|
| 225 | int i, j, k;
|
|---|
| 226 | enum( @int *@ ) ptr { I = &i, J = &j, K = &k };
|
|---|
| 227 | enum( @int &@ ) ref { I = i, J = j, K = k };
|
|---|
| 228 | // tuple
|
|---|
| 229 | enum( @[int, int]@ ) { T = [ 1, 2 ] }; $\C{// new \CFA type}$
|
|---|
| 230 | // function
|
|---|
| 231 | void f() {...} void g() {...}
|
|---|
| 232 | enum( @void (*)()@ ) funs { F = f, G = g };
|
|---|
| 233 | // aggregate
|
|---|
| 234 | struct Person { char * name; int age, height; };
|
|---|
| 235 | @***@enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz,
|
|---|
| 236 | Jon = { "JONATHAN", 35, 190 } };
|
|---|
| 237 | \end{cfa}
|
|---|
| 238 | \caption{Enumerator Typing}
|
|---|
| 239 | \label{f:EumeratorTyping}
|
|---|
| 240 | \end{figure}
|
|---|
| 241 |
|
|---|
| 242 | An advantage of the typed enumerations is eliminating the \emph{harmonizing} problem between an enumeration and companion data \see{\VRef{s:Usage}}:
|
|---|
| 243 | \begin{cfa}
|
|---|
| 244 | enum( char * ) integral_types {
|
|---|
| 245 | chr = "char", schar = "signed char", uschar = "unsigned char",
|
|---|
| 246 | sshort = "signed short int", ushort = "unsigned short int",
|
|---|
| 247 | sint = "signed int", usint = "unsigned int",
|
|---|
| 248 | ...
|
|---|
| 249 | };
|
|---|
| 250 | \end{cfa}
|
|---|
| 251 | 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.
|
|---|
| 252 |
|
|---|
| 253 | While the enumeration type can be any C aggregate, the aggregate's \CFA constructors are not used to evaluate an enumerator's value.
|
|---|
| 254 | \CFA enumeration constants are compile-time values (static);
|
|---|
| 255 | calling constructors happens at runtime (dynamic).
|
|---|
| 256 |
|
|---|
| 257 |
|
|---|
| 258 | \section{Enumerator Opaque Type}
|
|---|
| 259 |
|
|---|
| 260 | \CFA provides a special opaque enumeration type, where the internal representation is chosen by the compiler and only equality operations are available.
|
|---|
| 261 | \begin{cfa}
|
|---|
| 262 | enum@()@ Planets { MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE };
|
|---|
| 263 | \end{cfa}
|
|---|
| 264 |
|
|---|
| 265 |
|
|---|
| 266 | \section{Enumeration Inheritance}
|
|---|
| 267 |
|
|---|
| 268 | \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).
|
|---|
| 269 | \begin{cfa}
|
|---|
| 270 | enum( char * ) Names { /* as above */ };
|
|---|
| 271 | enum( char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" };
|
|---|
| 272 | @***@enum /* inferred */ Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" };
|
|---|
| 273 | \end{cfa}
|
|---|
| 274 | Enumeration @Name2@ inherits all the enumerators and their values from enumeration @Names@ by containment, and a @Names@ enumeration is a subtype of enumeration @Name2@.
|
|---|
| 275 | Note, enumerators must be unique in inheritance but enumerator values may be repeated.
|
|---|
| 276 |
|
|---|
| 277 | The enumeration type for the inheriting type must be the same as the inherited type;
|
|---|
| 278 | hence the enumeration type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for @Name3@.
|
|---|
| 279 | % When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important.
|
|---|
| 280 | Specifically, the inheritance relationship for @Names@ is:
|
|---|
| 281 | \begin{cfa}
|
|---|
| 282 | Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\(\subset\)$ const char * $\C{// enum type of Names}$
|
|---|
| 283 | \end{cfa}
|
|---|
| 284 | For the given function prototypes, the following calls are valid.
|
|---|
| 285 | \begin{cquote}
|
|---|
| 286 | \begin{tabular}{ll}
|
|---|
| 287 | \begin{cfa}
|
|---|
| 288 | void f( Names );
|
|---|
| 289 | void g( Names2 );
|
|---|
| 290 | void h( Names3 );
|
|---|
| 291 | void j( const char * );
|
|---|
| 292 | \end{cfa}
|
|---|
| 293 | &
|
|---|
| 294 | \begin{cfa}
|
|---|
| 295 | f( Fred );
|
|---|
| 296 | g( Fred ); g( Jill );
|
|---|
| 297 | h( Fred ); h( Jill ); h( Sue );
|
|---|
| 298 | j( Fred ); j( Jill ); j( Sue ); j( "WILL" );
|
|---|
| 299 | \end{cfa}
|
|---|
| 300 | \end{tabular}
|
|---|
| 301 | \end{cquote}
|
|---|
| 302 | 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.
|
|---|
| 303 |
|
|---|
| 304 |
|
|---|
| 305 | \section{Enumerator Control Structures}
|
|---|
| 306 |
|
|---|
| 307 | Enumerators can be used in multiple contexts.
|
|---|
| 308 | In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution).
|
|---|
| 309 | However, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect in some contexts.
|
|---|
| 310 | In these contexts, a programmer's initition assumes an implicit conversion to postion.
|
|---|
| 311 |
|
|---|
| 312 | For example, an intuitive use of enumerations is with the \CFA @switch@/@choose@ statement, where @choose@ performs an implict @break@ rather than a fall-through at the end of a @case@ clause.
|
|---|
| 313 | \begin{cquote}
|
|---|
| 314 | \begin{cfa}
|
|---|
| 315 | enum Count { First, Second, Third, Fourth };
|
|---|
| 316 | Count e;
|
|---|
| 317 | \end{cfa}
|
|---|
| 318 | \begin{tabular}{ll}
|
|---|
| 319 | \begin{cfa}
|
|---|
| 320 |
|
|---|
| 321 | choose( e ) {
|
|---|
| 322 | case @First@: ...;
|
|---|
| 323 | case @Second@: ...;
|
|---|
| 324 | case @Third@: ...;
|
|---|
| 325 | case @Fourth@: ...;
|
|---|
| 326 | }
|
|---|
| 327 | \end{cfa}
|
|---|
| 328 | &
|
|---|
| 329 | \begin{cfa}
|
|---|
| 330 | // rewrite
|
|---|
| 331 | choose( @value@( e ) ) {
|
|---|
| 332 | case @value@( First ): ...;
|
|---|
| 333 | case @value@( Second ): ...;
|
|---|
| 334 | case @value@( Third ): ...;
|
|---|
| 335 | case @value@( Fourth ): ...;
|
|---|
| 336 | }
|
|---|
| 337 | \end{cfa}
|
|---|
| 338 | \end{tabular}
|
|---|
| 339 | \end{cquote}
|
|---|
| 340 | 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.
|
|---|
| 341 | However, this implementation is fragile, \eg if the enumeration is changed to:
|
|---|
| 342 | \begin{cfa}
|
|---|
| 343 | enum Count { First, Second, Third @= First@, Fourth };
|
|---|
| 344 | \end{cfa}
|
|---|
| 345 | which make @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicase @case@ clauses.
|
|---|
| 346 | To better match with programmer intuition, \CFA toggles between value and position semantics depending on the language context.
|
|---|
| 347 | For conditional clauses and switch statments, \CFA uses the robust position implementation.
|
|---|
| 348 | \begin{cfa}
|
|---|
| 349 | choose( @position@( e ) ) {
|
|---|
| 350 | case @position@( First ): ...;
|
|---|
| 351 | case @position@( Second ): ...;
|
|---|
| 352 | case @position@( Third ): ...;
|
|---|
| 353 | case @position@( Fourth ): ...;
|
|---|
| 354 | }
|
|---|
| 355 | \end{cfa}
|
|---|
| 356 |
|
|---|
| 357 | \begin{cfa}
|
|---|
| 358 | Count variable_a = First, variable_b = Second, variable_c = Third, variable_d = Fourth;
|
|---|
| 359 | p(variable_a); // 0
|
|---|
| 360 | p(variable_b); // 1
|
|---|
| 361 | p(variable_c); // "Third"
|
|---|
| 362 | p(variable_d); // 3
|
|---|
| 363 | \end{cfa}
|
|---|
| 364 |
|
|---|
| 365 |
|
|---|
| 366 | @if@ statement
|
|---|
| 367 |
|
|---|
| 368 | @switch@ statement
|
|---|
| 369 |
|
|---|
| 370 | looping statements
|
|---|
| 371 |
|
|---|
| 372 |
|
|---|
| 373 |
|
|---|
| 374 | \section{Enumerated Arrays}
|
|---|
| 375 | Enumerated array use an \CFA array as their index.
|
|---|
| 376 | \begin{cfa}
|
|---|
| 377 | enum() Colour {
|
|---|
| 378 | Red, Orange, Yellow, Green, Blue, Indigo, Violet
|
|---|
| 379 | };
|
|---|
| 380 |
|
|---|
| 381 | string colourCode[Colour] = { "#e81416", "#ffa500", "#ffa500", "#ffa500", "#487de7", "#4b369d", "#70369d" };
|
|---|
| 382 | sout | "Colour Code of Orange is " | colourCode[Orange];
|
|---|
| 383 | \end{cfa}
|
|---|
| 384 |
|
|---|
| 385 | \section{Planet Example}
|
|---|
| 386 |
|
|---|
| 387 | \VRef[Figure]{f:PlanetExample} shows an archetypal enumeration example illustrating most of the \CFA enumeration features.
|
|---|
| 388 | @Planet@ is an enumeration of type @MR@.
|
|---|
| 389 | Each of the planet enumerators is initialized to a specific mass/radius, @MR@, value.
|
|---|
| 390 | The unnamed enumeration provides the gravitational-constant enumerator @G@.
|
|---|
| 391 | Function @surfaceGravity@ uses the @with@ clause to remove @p@ qualification from fields @mass@ and @radius@.
|
|---|
| 392 | The program main uses @SizeE@ to obtain the number of enumerators in @Planet@, and safely converts the random value into a @Planet@ enumerator.
|
|---|
| 393 | The resulting random orbital-body is used in a \CFA @choose@ statement.
|
|---|
| 394 | The enumerators in the @case@ clause use position for testing.
|
|---|
| 395 | The prints use @labelE@ to print an enumerator's label.
|
|---|
| 396 | Finally, a loop iterates through the planets computing the weight on each planet for a given earth mass.
|
|---|
| 397 | The print statement does an equality comparison with an enumeration variable and enumerator.
|
|---|
| 398 |
|
|---|
| 399 | \begin{figure}
|
|---|
| 400 | \small
|
|---|
| 401 | \begin{cfa}
|
|---|
| 402 | struct MR { double mass, radius; };
|
|---|
| 403 | enum( @MR@ ) Planet {
|
|---|
| 404 | // mass (kg) radius (km)
|
|---|
| 405 | MERCURY = { 0.330_E24, 2.4397_E6 },
|
|---|
| 406 | VENUS = { 4.869_E24, 6.0518_E6 },
|
|---|
| 407 | EARTH = { 5.976_E24, 6.3781_E6 },
|
|---|
| 408 | MOON = { 7.346_E22, 1.7380_E6 }, $\C{// not a planet}$
|
|---|
| 409 | MARS = { 0.642_E24, 3.3972_E6 },
|
|---|
| 410 | JUPITER = { 1898._E24, 71.492_E6 },
|
|---|
| 411 | SATURN = { 568.8_E24, 60.268_E6 },
|
|---|
| 412 | URANUS = { 86.86_E24, 25.559_E6 },
|
|---|
| 413 | NEPTUNE = { 102.4_E24, 24.746_E6 },
|
|---|
| 414 | };
|
|---|
| 415 | enum( double ) { G = 6.6743_E-11 }; $\C{// universal gravitational constant (m3 kg-1 s-2)}$
|
|---|
| 416 | static double surfaceGravity( Planet p ) @with( p )@ {
|
|---|
| 417 | return G * mass / ( radius \ 2 ); $\C{// exponentiation}$
|
|---|
| 418 | }
|
|---|
| 419 | static double surfaceWeight( Planet p, double otherMass ) {
|
|---|
| 420 | return otherMass * surfaceGravity( p );
|
|---|
| 421 | }
|
|---|
| 422 | int main( int argc, char * argv[] ) {
|
|---|
| 423 | if ( argc != 2 ) exit | "Usage: " | argv[0] | "earth-weight";
|
|---|
| 424 | double earthWeight = convert( argv[1] );
|
|---|
| 425 | double earthMass = earthWeight / surfaceGravity( EARTH );
|
|---|
| 426 |
|
|---|
| 427 | Planet p = @fromInt@( prng( @SizeE@(Planet) ) ); $\C{// select a random orbiting body}$
|
|---|
| 428 | @choose( p )@ {
|
|---|
| 429 | case MERCURY, VENUS, EARTH, MARS:
|
|---|
| 430 | sout | @labelE( p )@ | "is a rocky planet";
|
|---|
| 431 | @case JUPITER, SATURN, URANUS, NEPTUNE:@
|
|---|
| 432 | sout | labelE( p ) | "is a gas-giant planet";
|
|---|
| 433 | default:
|
|---|
| 434 | sout | labelE( p ) | "is not a planet";
|
|---|
| 435 | }
|
|---|
| 436 | for ( @p; Planet@ ) {
|
|---|
| 437 | sout | "Your weight on" | (@p == MOON@ ? "the" : "") | labelE(p)
|
|---|
| 438 | | "is" | wd( 1,1, surfaceWeight( p, earthMass ) ) | "kg";
|
|---|
| 439 | }
|
|---|
| 440 | }
|
|---|
| 441 | $\$$ planet 100
|
|---|
| 442 | JUPITER is a gas-giant planet
|
|---|
| 443 | Your weight on MERCURY is 37.7 kg
|
|---|
| 444 | Your weight on VENUS is 90.5 kg
|
|---|
| 445 | Your weight on EARTH is 100.0 kg
|
|---|
| 446 | Your weight on the MOON is 16.6 kg
|
|---|
| 447 | Your weight on MARS is 37.9 kg
|
|---|
| 448 | Your weight on JUPITER is 252.8 kg
|
|---|
| 449 | Your weight on SATURN is 106.6 kg
|
|---|
| 450 | Your weight on URANUS is 90.5 kg
|
|---|
| 451 | Your weight on NEPTUNE is 113.8 kg
|
|---|
| 452 | \end{cfa}
|
|---|
| 453 | \caption{Planet Example}
|
|---|
| 454 | \label{f:PlanetExample}
|
|---|
| 455 | \end{figure}
|
|---|