source: doc/theses/jiada_liang_MMath/CFAenum.tex @ c588acb

Last change on this file since c588acb was c588acb, checked in by Peter A. Buhr <pabuhr@…>, 5 weeks ago

proofread CFA enumeration chapter

  • Property mode set to 100644
File size: 24.2 KB
Line 
1\chapter{\CFA Enumeration}
2
3\CFA extends C-Style enumeration by adding a number of new features that bring enumerations inline with other modern programming languages.
4Any enumeration extensions must be intuitive to C programmers both in syntax and semantics.
5The following sections detail all of my new contributions to enumerations in \CFA.
6
7
8\section{Enumeration Syntax}
9
10\CFA extends the C enumeration declaration \see{\VRef{s:CEnumeration}} by parameterizing with a type (like a generic type), and adding Plan-9 inheritance \see{\VRef{s:EnumerationInheritance}} using an @inline@ to another enumeration type.
11\begin{cfa}[identifierstyle=\linespread{0.9}\it]
12$\it enum$-specifier:
13        enum @(type-specifier$\(_{opt}\)$)@ identifier$\(_{opt}\)$ { cfa-enumerator-list }
14        enum @(type-specifier$\(_{opt}\)$)@ identifier$\(_{opt}\)$ { cfa-enumerator-list , }
15        enum @(type-specifier$\(_{opt}\)$)@ identifier
16cfa-enumerator-list:
17        cfa-enumerator
18        cfa-enumerator-list, cfa-enumerator
19cfa-enumerator:
20        enumeration-constant
21        @inline $\color{red}enum$-type-name@
22        enumeration-constant = constant-expression
23\end{cfa}
24
25
26\section{Enumeration Operations}
27
28\CFA enumerations have access to the three enumerations properties \see{\VRef{s:Terminology}}: label, order (position), and value via three overloaded functions @label@, @posn@, and @value@ \see{\VRef{c:trait} for details}.
29\CFA auto-generates these functions for every \CFA enumeration.
30\begin{cfa}
31enum(int) E { A = 3 } e = A;
32sout | A | @label@( A ) | @posn@( A ) | @value@( A );
33sout | e | @label@( e ) | @posn@( e ) | @value@( e );
34A A 0 3
35A A 0 3
36\end{cfa}
37For output, the default is to print the label.
38An alternate way to get an enumerator's position is to cast it to @int@.
39\begin{cfa}
40sout | A | label( A ) | @(int)A@ | value( A );
41sout | A | label( A ) | @(int)A@ | value( A );
42A A @0@ 3
43A A @0@ 3
44\end{cfa}
45Finally, there is an additional enumeration routine @countof@ (like @sizeof@, @typeof@) that returns the number of enumerators in an enumeration.
46\begin{cfa}
47enum(int) E { A, B, C, D };
48countof( E )// 4
49\end{cfa}
50This auto-generated function replaces the C idiom for automatically computing the number of enumerators \see{\VRef{s:Usage}}.
51\begin{cfa}
52enum E { A, B, C, D, @N@ };  // N == 4
53\end{cfa}
54
55The underlying representation of \CFA enumeration object is its position, saved as an integral type.
56Therefore, the size of a \CFA enumeration is consistent with a C enumeration.
57Attribute function @posn@ performs type substitution on an expression from \CFA type to integral type.
58The label and value of an enumerator is stored in a global data structure for each enumeration, where attribute functions @label@/@value@ map an \CFA enumeration object to the corresponding data.
59These operations do not apply to C Enums because backwards compatibility means the necessary backing data structures cannot be supplied.
60
61\section{Opaque Enumeration}
62\label{s:OpaqueEnum}
63
64When an enumeration type is empty is it an \newterm{opaque} enumeration.
65\begin{cfa}
66enum@()@ Mode { O_RDONLY, O_WRONLY, O_CREAT, O_TRUNC, O_APPEND };
67\end{cfa}
68Here, the internal representation is chosen by the compiler and hidden, so the enumerators cannot be initialized.
69Compared to the C enum, opaque enums are more restrictive in terms of typing and cannot be implicitly converted to integers.
70\begin{cfa}
71Mode mode = O_RDONLY;
72int www @=@ mode;                                               $\C{// disallowed}$
73\end{cfa}
74Opaque enumerations have only two attribute properties @label@ and @posn@.
75\begin{cfa}
76char * s = label( O_TRUNC );                    $\C{// "O\_TRUNC"}$
77int open = posn( O_WRONLY );                    $\C{// 1}$
78\end{cfa}
79The equality and relational operations are available.
80\begin{cfa}
81if ( mode @==@ O_CREAT ) ...
82bool b = mode @<@ O_APPEND;
83\end{cfa}
84
85
86\section{Typed Enumeration}
87\label{s:EnumeratorTyping}
88
89When an enumeration type is specified, all enumerators have that type and can be initialized with constants of that type or compile-time convertable to that type.
90Figure~\ref{f:EumeratorTyping} shows a series of examples illustrating that all \CFA types can be use with an enumeration and each type's values used to set the enumerator constants.
91Note, the use of the synonyms @Liz@ and @Beth@ in the last declaration.
92Because enumerators are constants, the enumeration type is implicitly @const@, so all the enumerator types in Figure~\ref{f:EumeratorTyping} are logically rewritten with @const@.
93
94\begin{figure}
95\begin{cfa}
96// integral
97        enum( @char@ ) Currency { Dollar = '$\textdollar$', Cent = '$\textcent$', Yen = '$\textyen$', Pound = '$\textsterling$', Euro = 'E' };
98        enum( @signed char@ ) srgb { Red = -1, Green = 0, Blue = 1 };
99        enum( @long long int@ ) BigNum { X = 123_456_789_012_345,  Y = 345_012_789_456_123 };
100// non-integral
101        enum( @double@ ) Math { PI_2 = 1.570796, PI = 3.141597, E = 2.718282 };
102        enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i };
103// pointer
104        enum( @char *@ ) Name { Fred = "FRED", Mary = "MARY", Jane = "JANE" };
105        int i, j, k;
106        enum( @int *@ ) ptr { I = &i,  J = &j,  K = &k };
107        enum( @int &@ ) ref { I = i,   J = j,   K = k };
108// tuple
109        enum( @[int, int]@ ) { T = [ 1, 2 ] }; $\C{// new \CFA type}$
110// function
111        void f() {...}   void g() {...}
112        enum( @void (*)()@ ) funs { F = f,  G = g };
113// aggregate
114        struct Person { char * name; int age, height; };
115        enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz,
116                                                                        Jon = { "JONATHAN", 35, 190 } };
117\end{cfa}
118% synonym feature unimplemented
119\caption{Enumerator Typing}
120\label{f:EumeratorTyping}
121\end{figure}
122
123An advantage of the typed enumerations is eliminating the \emph{harmonizing} problem between an enumeration and companion data \see{\VRef{s:Usage}}:
124\begin{cfa}
125enum( char * ) integral_types {
126        chr = "char", schar = "signed char", uschar = "unsigned char",
127        sshort = "signed short int", ushort = "unsigned short int",
128        sint = "signed int", usint = "unsigned int",
129        ...
130};
131\end{cfa}
132Note, 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.
133
134While the enumeration type can be any C aggregate, the aggregate's \CFA constructors are \emph{not} used to evaluate an enumerator's value.
135\CFA enumeration constants are compile-time values (static);
136calling constructors happens at runtime (dynamic).
137
138
139\section{Value Conversion}
140
141C has an implicit type conversion from an enumerator to its base type @int@.
142Correspondingly, \CFA has an implicit conversion from a typed enumerator to its base type, allowing typed enumeration to be seamlessly used as the value of its base type
143For example, using type @Currency@ in \VRef[Figure]{f:EumeratorTyping}:
144\begin{cfa}
145char currency = Dollar;         $\C{// implicit conversion to base type}$
146void foo( char );
147foo( Dollar );                          $\C{// implicit conversion to base type}$
148\end{cfa}
149The implicit conversion induces a \newterm{value cost}, which is a new category (8 tuple) in \CFA's conversion cost model \see{\VRef{s:ConversionCost}} to disambiguate function overloading over a \CFA enumeration and its base type.
150\begin{cfa}
151void baz( char ch );            $\C{// (1)}$
152void baz( Currency cu );        $\C{// (2)}$
153baz( Dollar );
154\end{cfa}
155While both @baz@ functions are applicable to the enumerator @Dollar@, @candidate (1)@ comes with a @value@ cost for the conversion to the enumeration's base type, while @candidate (2)@ has @zero@ cost.
156Hence, \CFA chooses the exact match.
157Value cost is defined to be a more significant factor than an @unsafe@ but less than the other conversion costs: @(unsafe,@ {\color{red}@value@}@, poly, safe, sign, vars, specialization,@ @reference)@.
158\begin{cfa}
159void bar( @int@ );
160Math x = PI;                            $\C{// (1)}$
161double x = 5.5;                         $\C{// (2)}$
162bar( x );                                       $\C{// costs (1, 0, 0, 0, 0, 0, 0, 0) or (0, 1, 0, 0, 0, 0, 0, 0)}$
163\end{cfa}
164Here, candidate (1) has a value conversion cost to convert to the base type, while candidate (2) has an unsafe conversion from @double@ to @int@.
165Hence, @bar( x )@ resolves @x@ as type @Math@.
166
167% \begin{cfa}
168% forall(T | @CfaEnum(T)@) void bar(T);
169%
170% bar(a);                                       $\C{// (3), with cost (0, 0, 1, 0, 0, 0, 0, 0)}$
171% \end{cfa}
172% % @Value@ is designed to be less significant than @poly@ to allow function being generic over \CFA enumeration (see ~\ref{c:trait}).
173% Being generic over @CfaEnum@ traits (a pre-defined interface for \CFA enums) is a practice in \CFA to implement functions over \CFA enumerations, as will see in chapter~\ref{c:trait}.
174% @Value@ is a being a more significant cost than @poly@ implies if a overloaeded function defined for @CfaEnum@ (and other generic type), \CFA always try to resolve it as a @CfaEnum@, rather to insert a @value@ conversion.
175
176
177\section{Auto Initialization}
178
179A partially implemented feature is auto-initialization, which works for the C integral type with constant expressions.
180\begin{cfa}
181enum Week { Mon, Tue, Wed, Thu@ = 10@, Fri, Sat, Sun }; // 0-2, 10-13
182\end{cfa}
183The complexity of the constant expression depends on the level of computation the compiler implements, \eg \CC \lstinline[language={[GNU]C++}]{constexpr} provides complex compile-time computation across multiple types, which blurs the compilation/runtime boundary.
184
185If \CFA had powerful compilation expression evaluation, auto initialization would be implemented as follows.
186\begin{cfa}
187enum E(T) { A, B, C };
188\end{cfa}
189\begin{enumerate}
190\item the first enumerator, @A@, is initialized with @T@'s @zero_t@.
191\item otherwise, the next enumerator is initialized with the previous enumerator's value using operator @?++@, where @?++( T )@ can be overloaded for any type @T@.
192\end{enumerate}
193
194Unfortunately, constant expressions in C are not powerful and \CFA is only a transpiler, relying on generated C code to perform the detail work.
195It is currently beyond the scope of the \CFA project to implement a complex runtime interpreter in the transpiler to evaluate complex expressions across multiple builtin and user-defined type.
196Nevertheless, the necessary language concepts exist to support this feature.
197
198
199\section{Enumeration Inheritance}
200\label{s:EnumerationInheritance}
201
202\CFA Plan-9 inheritance may be used with \CFA enumerations, where Plan-9 inheritance is containment inheritance with implicit unscoping (like a nested unnamed @struct@/@union@ in C).
203Containment is nominative: an enumeration inherits all enumerators from another enumeration by declaring an @inline statement@ in its enumerator lists.
204\begin{cfa}
205enum( char * ) Names { /* $\see{\VRef[Figure]{s:EnumerationInheritance}}$ */ };
206enum( char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" };
207enum( char * ) Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" };
208\end{cfa}
209In the preceding example, @Names2@ is defined with five enumerators, three of which are from @Name@ through containment, and two are self-declared.
210@Names3@ inherits all five members from @Names2@ and declares two additional enumerators.
211Hence, enumeration inheritance forms a subset relationship.
212Specifically, the inheritance relationship for the example above is:
213\begin{cfa}
214Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\C{// enum type of Names}$
215\end{cfa}
216
217Inheritance can be nested, and a \CFA enumeration can inline enumerators from more than one \CFA enumeration, forming a tree-like hierarchy.
218However, the uniqueness of enumeration name applies to enumerators, including those from supertypes, meaning an enumeration cannot name enumerator with the same label as its subtype's members, or inherits
219from multiple enumeration that has overlapping enumerator label. As a consequence, a new type cannot inherits from both an enumeration and its supertype, or two enumerations with a
220common supertype (the diamond problem), since such would unavoidably introduce duplicate enumerator labels.
221
222The base type must be consistent between subtype and supertype.
223When an enumeration inherits enumerators from another enumeration, it copies the enumerators' @value@ and @label@, even if the @value@ is auto initialized.
224However, the position of the underlying representation is the order of the enumerator in the new enumeration.
225\begin{cfa}
226enum() E1 { A };
227enum() E2 { B, C };
228enum() E3 { inline E1, inline E2, D };
229\end{cfa}
230Here, @A@ has position 0 in @E1@ and @E3@.
231@B@ has position 0 in @E2@ and 1 in @E3@.
232@C@ has position 1 in @E2@ and position 2 in @E3@.
233@D@ has position 3 in @E3@.
234
235A subtype enumeration can be casted, or implicitly converted into its supertype, with a @safe@ cost.
236\begin{cfa}
237enum E2 e2 = C;
238posn( e2 );                     $\C[1.75in]{// 1}$
239enum E3 e3 = e2;
240posn( e2 );                     $\C{// 2}$
241void foo( E3 e );
242foo( e2 );
243posn( (E3)e2 );         $\C{// 2}$
244E3 e31 = B;
245posn( e31 );            $\C{// 1}\CRT$
246\end{cfa}
247The last expression is unambiguous.
248While both @E2.B@ and @E3.B@ are valid candidate, @E2.B@ has an associated safe cost and \CFA selects the zero cost candidate @E3.B@.
249Hence, as discussed in \VRef{s:OpaqueEnum}, \CFA chooses position as a representation of the \CFA enum.
250Therefore, conversion involves both a change of type and possibly position.
251
252When converting a subtype to a supertype, its position can only be a larger value.
253The difference between the position in the subtype and in the supertype is its \newterm{offset}.
254\VRef[Figure]{s:OffsetSubtypeSuperType} show the algorithm to determine the offset for an subtype enumerator to its super type.
255\PAB{You need to explain the algorithm.}
256
257\begin{figure}
258\begin{cfa}
259struct Enumerator;
260struct CFAEnum {
261        vector<variant<CFAEnum, Enumerator>> members;
262};
263pair<bool, int> calculateEnumOffset( CFAEnum dst, Enumerator e ) {
264        int offset = 0;
265        for ( auto v: dst.members ) {
266                if ( v.holds_alternative<Enumerator>() ) {
267                        auto m = v.get<Enumerator>();
268                        if ( m == e ) return make_pair( true, 0 );
269                        offset++;
270                } else {
271                        auto p = calculateEnumOffset( v, e );
272                        if ( p.first ) return make_pair( true, offset + p.second );
273                        offset += p.second;
274                }
275        }
276        return make_pair( false, offset );
277}
278\end{cfa}
279\caption{Compute Offset from Subtype Enumerator to Super Type}
280\label{s:OffsetSubtypeSuperType}
281\end{figure}
282
283For the given function prototypes, the following calls are valid.
284\begin{cquote}
285\begin{tabular}{ll}
286\begin{cfa}
287void f( Names );
288void g( Names2 );
289void h( Names3 );
290void j( const char * );
291\end{cfa}
292&
293\begin{cfa}
294f( Fred );
295g( Fred );   g( Jill );
296h( Fred );   h( Jill );   h( Sue );
297j( Fred );    j( Jill );    j( Sue );    j( "WILL" );
298\end{cfa}
299\end{tabular}
300\end{cquote}
301Note, 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.
302
303
304\section{Enumerator Control Structures}
305
306Enumerators can be used in multiple contexts.
307In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution).
308However, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect in some contexts.
309In these contexts, a programmer's intuition assumes an implicit conversion to position.
310
311For 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.
312(For this discussion, ignore the fact that @case@ requires a compile-time constant.)
313\begin{cfa}[belowskip=0pt]
314enum Count { First, Second, Third, Fourth };
315Count e;
316\end{cfa}
317\begin{cquote}
318\setlength{\tabcolsep}{15pt}
319\noindent
320\begin{tabular}{@{}ll@{}}
321\begin{cfa}[aboveskip=0pt]
322
323choose( e ) {
324        case @First@: ...;
325        case @Second@: ...;
326        case @Third@: ...;
327        case @Fourth@: ...;
328}
329\end{cfa}
330&
331\begin{cfa}[aboveskip=0pt]
332// rewrite
333choose( @value@( e ) ) {
334        case @value@( First ): ...;
335        case @value@( Second ): ...;
336        case @value@( Third ): ...;
337        case @value@( Fourth ): ...;
338}
339\end{cfa}
340\end{tabular}
341\end{cquote}
342Here, 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.
343However, this implementation is fragile, \eg if the enumeration is changed to:
344\begin{cfa}
345enum Count { First, Second, Third @= First@, Fourth };
346\end{cfa}
347making @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicate @case@ clauses.
348To better match with programmer intuition, \CFA toggles between value and position semantics depending on the language context.
349For conditional clauses and switch statements, \CFA uses the robust position implementation.
350\begin{cfa}
351if ( @posn@( e ) < posn( Third ) ) ...
352choose( @posn@( e ) ) {
353        case @posn@( First ): ...;
354        case @posn@( Second ): ...;
355        case @posn@( Third ): ...;
356        case @posn@( Fourth ): ...;
357}
358\end{cfa}
359
360\CFA provides a special form of for-control for enumerating through an enumeration, where the range is a type.
361\begin{cfa}
362for ( cx; @Count@ ) { sout | cx | nonl; } sout | nl;
363for ( cx; ~= Count ) { sout | cx | nonl; } sout | nl;
364for ( cx; -~= Count ) { sout | cx | nonl; } sout | nl;
365First Second Third Fourth
366First Second Third Fourth
367Fourth Third Second First
368\end{cfa}
369The 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.
370The prefix @+~=@ or @-~=@ iterate forward or backwards through the inclusive enumeration range, where no prefix defaults to @+~=@.
371
372C has an idiom for @if@ and loop predicates of comparing the predicate result ``not equal to 0''.
373\begin{cfa}
374if ( x + y /* != 0 */  ) ...
375while ( p /* != 0 */  ) ...
376\end{cfa}
377This 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.
378For example, such a conversion exists for all numerical types (integral and floating-point).
379It is possible to explicitly extend this idiom to any typed enumeration by overloading the @!=@ operator.
380\begin{cfa}
381bool ?!=?( Name n, zero_t ) { return n != Fred; }
382Name n = Mary;
383if ( n ) ... // result is true
384\end{cfa}
385Specialize meanings are also possible.
386\begin{cfa}
387enum(int) ErrorCode { Normal = 0, Slow = 1, Overheat = 1000, OutOfResource = 1001 };
388bool ?!=?( ErrorCode ec, zero_t ) { return ec >= Overheat; }
389ErrorCode code = ...;
390if ( code ) { problem(); }
391\end{cfa}
392
393
394\section{Enumeration Dimension}
395
396\VRef{s:EnumeratorTyping} introduces the harmonizing problem between an enumeration and secondary information.
397When possible, using a typed enumeration for the secondary information is the best approach.
398However, there are times when combining these two types is not possible.
399For example, the secondary information might precede the enumeration and/or its type is needed directly to declare parameters of functions.
400In these cases, having secondary arrays of the enumeration size are necessary.
401
402To support some level of harmonizing in these cases, an array dimension can be defined using an enumerator type, and the enumerators used as subscripts.
403\begin{cfa}
404enum E1 { A, B, C, N }; // possibly predefined
405enum(int) E2 { A, B, C };
406float H1[N] = { [A] :$\footnotemark$ 3.4, [B] : 7.1, [C] : 0.01 }; // C
407float H2[@E2@] = { [A] : 3.4, [B] : 7.1, [C] : 0.01 }; // CFA
408\end{cfa}
409\footnotetext{C uses symbol \lstinline{'='} for designator initialization, but \CFA changes it to \lstinline{':'} because of problems with tuple syntax.}
410This approach is also necessary for a predefined typed enumeration (unchangeable), when additional secondary-information need to be added.
411
412The array subscript operator, namely @?[?]@, is overloaded so that when a \CFA enumerator is used as an array index, it implicitly converts to its position over value to sustain data harmonization.
413This behaviour can be reverted by explicit overloading:
414\begin{cfa}
415float ?[?]( float * arr, E2 index ) { return arr[ value( index ) ]; }
416\end{cfa}
417When an enumeration type is being used as an array dimension, \CFA adds the enumeration type to the initializer's context.
418As a result, @H2@'s array destinators @A@, @B@ and @C@ are resolved unambiguously to type @E2@.
419(@H1@'s destinators are also resolved unambiguously to @E1@ because @E2@ has a @value@ cost.)
420
421
422\section{Enumeration I/O}
423
424As 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.
425However, very few programming languages provide a mechanism to read in enumerator values.
426Even the @boolean@ type in many languages does not have a mechanism for input using the enumerators @true@ or @false@.
427\VRef[Figure]{f:EnumerationI/O} show \CFA enumeration input based on the enumerator labels.
428When the enumerator labels are packed together in the input stream, the input algorithm scans for the longest matching string.
429For basic types in \CFA, the rule is that the same constants used to initialize a variable in a program are available to initialize a variable using input, where strings constants can be quoted or unquoted.
430
431\begin{figure}
432\begin{cquote}
433\setlength{\tabcolsep}{15pt}
434\begin{tabular}{@{}ll@{}}
435\begin{cfa}
436int main() {
437        enum(int ) E { BBB = 3, AAA, AA, AB, B };
438        E e;
439
440        for () {
441                try {
442                        @sin | e@;
443                } catch( missing_data * ) {
444                        sout | "missing data";
445                        continue; // try again
446                }
447          if ( eof( sin ) ) break;
448                sout | e | "= " | value( e );
449        }
450}
451\end{cfa}
452&
453\begin{cfa}
454$\rm input$
455BBBABAAAAB
456BBB AAA AA AB B
457
458$\rm output$
459BBB = 3
460AB = 6
461AAA = 4
462AB = 6
463BBB = 3
464AAA = 4
465AA = 5
466AB = 6
467B = 7
468
469\end{cfa}
470\end{tabular}
471\end{cquote}
472\caption{Enumeration I/O}
473\label{f:EnumerationI/O}
474\end{figure}
475
476
477
478\section{Planet Example}
479
480\VRef[Figure]{f:PlanetExample} shows an archetypal enumeration example illustrating most of the \CFA enumeration features.
481@Planet@ is an enumeration of type @MR@.
482Each planet enumerator is initialized to a specific mass/radius, @MR@, value.
483The unnamed enumeration provides the gravitational-constant enumerator @G@.
484Function @surfaceGravity@ uses the @with@ clause to remove @p@ qualification from fields @mass@ and @radius@.
485The 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@.
486The resulting random orbital-body is used in a @choose@ statement.
487The enumerators in the @case@ clause use the enumerator position for testing.
488The prints use @label@ to print an enumerator's name.
489Finally, a loop enumerates through the planets computing the weight on each planet for a given earth mass.
490The print statement does an equality comparison with an enumeration variable and enumerator (@p == MOON@).
491
492\begin{figure}
493\small
494\begin{cfa}
495struct MR { double mass, radius; };                     $\C[3.5in]{// planet definition}$
496enum( @MR@ ) Planet {                                           $\C{// typed enumeration}$
497        //                      mass (kg)   radius (km)
498        MERCURY = { 0.330_E24, 2.4397_E6 },
499        VENUS      = { 4.869_E24, 6.0518_E6 },
500        EARTH       = { 5.976_E24, 6.3781_E6 },
501        MOON        = { 7.346_E22, 1.7380_E6 }, $\C{// not a planet}$
502        MARS         = { 0.642_E24, 3.3972_E6 },
503        JUPITER    = { 1898._E24, 71.492_E6 },
504        SATURN     = { 568.8_E24, 60.268_E6 },
505        URANUS    = { 86.86_E24, 25.559_E6 },
506        NEPTUNE  = { 102.4_E24, 24.746_E6 },
507        PLUTO       = { 1.303_E22, 1.1880_E6 }, $\C{// not a planet}$
508};
509enum( double ) { G = 6.6743_E-11 };                     $\C{// universal gravitational constant (m3 kg-1 s-2)}$
510static double surfaceGravity( Planet p ) @with( p )@ {
511        return G * mass / ( radius @\@ 2 );             $\C{// no qualification, exponentiation}$
512}
513static double surfaceWeight( Planet p, double otherMass ) {
514        return otherMass * surfaceGravity( p );
515}
516int main( int argc, char * argv[] ) {
517        if ( argc != 2 ) @exit@ | "Usage: " | argv[0] | "earth-weight";  // terminate program
518        double earthWeight = convert( argv[1] );
519        double earthMass = earthWeight / surfaceGravity( EARTH );
520        Planet rp = @fromInt@( prng( @countof@( Planet ) ) ); $\C{// select random orbiting body}$
521        @choose( rp )@ {                                                $\C{// implicit breaks}$
522          case MERCURY, VENUS, EARTH, MARS:
523                sout | @rp@ | "is a rocky planet";
524          case JUPITER, SATURN, URANUS, NEPTUNE:
525                sout | rp | "is a gas-giant planet";
526          default:
527                sout | rp | "is not a planet";
528        }
529        for ( @p; Planet@ ) {                                   $\C{// enumerate}\CRT$
530                sout | "Your weight on" | ( @p == MOON@ ? "the" : " " ) | p
531                           | "is" | wd( 1,1,  surfaceWeight( p, earthMass ) ) | "kg";
532        }
533}
534$\$$ planet 100
535JUPITER is a gas-giant planet
536Your weight on MERCURY is 37.7 kg
537Your weight on VENUS is 90.5 kg
538Your weight on EARTH is 100.0 kg
539Your weight on the MOON is 16.6 kg
540Your weight on MARS is 37.9 kg
541Your weight on JUPITER is 252.8 kg
542Your weight on SATURN is 106.6 kg
543Your weight on URANUS is 90.5 kg
544Your weight on NEPTUNE is 113.8 kg
545Your weight on PLUTO is 6.3 kg
546\end{cfa}
547\caption{Planet Example}
548\label{f:PlanetExample}
549\end{figure}
Note: See TracBrowser for help on using the repository browser.