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