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