source: doc/theses/jiada_liang_MMath/CFAenum.tex @ 09dd830

Last change on this file since 09dd830 was 09dd830, checked in by JiadaL <j82liang@…>, 4 weeks ago

grammar fixed by a dsoftware

  • Property mode set to 100644
File size: 22.3 KB
Line 
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.
6Any enumeration extensions must be intuitive to C programmers both in syntax and semantics.
7The following sections detail all of my new contributions to enumerations in \CFA.
8
9\begin{comment}
10        Not support.
11\end{comment}
12% \section{Aliasing}
13
14% 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).
15% Given the existence of this form, it is straightforward to extend it with types other than @int@.
16% \begin{cfa}
17% enum E { Size = 20u, PI = 3.14159L, Jack = L"John" };
18% \end{cfa}
19% which matches with @const@ aliasing in other programming languages.
20% Here, the type of the enumerator is the type of the initialization constant, \eg @typeof(20u)@ for @Size@ implies @unsigned int@.
21% Auto-initialization is restricted to the case where all constants are @int@, matching with C.
22% As seen in \VRef{s:EnumeratorTyping}, this feature is just a shorthand for multiple typed-enumeration declarations.
23
24
25\section{Enumerator Visibility}
26\label{s:EnumeratorVisibility}
27
28In C, unscoped enumerators present a \newterm{naming problem} when multiple enumeration types appear in the same scope with duplicate enumerator names.
29There 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.
30
31The \CFA type-system allows extensive overloading, including enumerators.
32Furthermore, \CFA uses the environment, such as the left-had of assignment and function parameter, to pinpoint the best overloaded name.
33% Furthermore, \CFA uses the left-hand of assignment in type resolution to pinpoint the best overloaded name.
34Finally, qualification and casting are provided to disambiguate any ambiguous situations.
35\begin{cfa}
36enum E1 { First, Second, Third, Fourth };
37enum E2 { @Fourth@, @Third@, @Second@, @First@ }; $\C{// same enumerator names}$
38E1 f() { return Third; }                                $\C{// overloaded functions, different return types}$
39E2 f() { return Fourth; }
40void g(E1 e);
41void h(E2 e);
42void foo() {
43        E1 e1 = First;   E2 e2 = First;         $\C{// initialization}$
44        e1 = Second;   e2 = Second;                     $\C{// assignment}$
45        e1 = f();   e2 = f();                           $\C{// function return}$
46        g(First); h(First);                                     $\C{// function parameter}$
47        int i = @E1.@First + @E2.@First;        $\C{// disambiguate with qualification}$
48        int j = @(E1)@First + @(E2)@First;      $\C{// disambiguate with cast}$
49}
50\end{cfa}
51\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.
52Experience 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.
53Any ambiguity can be resolved using qualification or casting.
54
55
56\section{Enumerator Scoping}
57
58An enumeration can be scoped, using @'!'@, so the enumerator constants are not projected into the enclosing scope.
59\begin{cfa}
60enum Week @!@ { Mon, Tue, Wed, Thu = 10, Fri, Sat, Sun };
61enum RGB @!@ { Red, Green, Blue };
62\end{cfa}
63Now the enumerators \emph{must} be qualified with the associated enumeration type.
64\begin{cfa}
65Week week = @Week.@Mon;
66week = @Week.@Sat;
67RGB rgb = @RGB.@Red;
68rgb = @RGB.@Blue;
69\end{cfa}
70It 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}).
71\begin{cfa}
72with ( @Week@, @RGB@ ) {                                $\C{// type names}$
73         week = @Sun@;                                          $\C{// no qualification}$
74         rgb = @Green@;
75}
76\end{cfa}
77As 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.
78
79
80\section{Enumeration Traits}
81
82\CFA defines the set of traits containing operators and helper functions for @enum@.
83A \CFA enumeration satisfies all of these traits allowing it to interact with runtime features in \CFA.
84Each trait is discussed in detail.
85
86The trait @CfaEnum@:
87\begin{cfa}
88forall( E ) trait CfaEnum {
89        char * label( E e );
90        unsigned int posn( E e );
91};
92\end{cfa}
93
94describes an enumeration as a named constant with position. And @TypeEnum@
95\begin{cfa}
96forall( E, V ) trait TypeEnum {
97        V value( E e );
98};     
99\end{cfa}
100asserts two types @E@ and @T@, with @T@ being the base type for the enumeration @E@.
101
102The declarative syntax
103\begin{cfa}
104enum(T) E { A = ..., B = ..., C = ... };
105\end{cfa}
106creates an enumerated type E with @label@, @posn@ and @value@ implemented automatically.
107
108\begin{cfa}
109void foo( T t ) { ... }
110void bar(E e) {
111        choose (e) {
112                case A: printf("\%d", posn(e));
113                case B: printf("\%s", label(e));
114                case C: foo(value(e));
115        } 
116}
117\end{cfa}
118
119Implementing general functions across all enumeration types is possible by asserting @CfaEnum( E, T )@, \eg:
120\begin{cfa}
121#include <string.hfa>
122forall( E, T | CfaEnum( E, T ) | {unsigned int toUnsigned(T)} )
123string formatEnum( E e ) {
124        unsigned int v = toUnsigned(value(e));
125        string out = label(e) + '(' + v +')';
126        return out;
127}
128printEunm( Week.Mon );
129printEnum( RGB.Green );
130\end{cfa}
131
132\CFA does not define attribute functions for C style enumeration. But it is possilbe for users to explicitly implement
133enumeration traits for C enum and any other types.
134
135\begin{cfa}
136enum Fruit { Apple, Bear, Cherry };                     $\C{// C enum}$
137char * label(Fruit f) {
138        switch(f) {
139                case Apple: "A"; break;
140                case Bear: "B"; break;
141                case Cherry: "C"; break;
142        }
143}
144unsigned posn(Fruit f) { return f; }
145char* value(Fruit f) { return ""; }             $\C{// value can return any non void type}$
146formatEnum( Apple );                                                    $\C{// Fruit is now a Cfa enum}$
147\end{cfa}
148
149A type that implements trait @CfaEnum@, \ie, a type has no @value@, is called an opaque enum.
150
151% \section{Enumerator Opaque Type}
152
153% \CFA provides a special opaque enumeration type, where the internal representation is chosen by the compiler and only equality operations are available.
154\begin{cfa}
155enum@()@ Planets { MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE };
156\end{cfa}
157
158
159In addition, \CFA implements @Bound@ and @Serial@ for \CFA Enums.
160\begin{cfa}
161forall( E ) trait Bounded {
162        E first();
163        E last();
164};
165\end{cfa}
166The function @first()@ and @last()@ of enumerated type E return the first and the last enumerator declared in E, respectively. \eg:
167\begin{cfa}
168Workday day = first();                                  $\C{// Mon}$
169Planet outermost = last();                              $\C{// NEPTUNE}$
170\end{cfa}
171@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.
172Calling either functions without a context results in a type ambiguity, except in the rare case where the type environment has only one enumeration.
173\begin{cfa}
174@first();@                                                              $\C{// ambiguous because both Workday and Planet implement Bounded}$
175sout | @last()@;
176Workday day = first();                                  $\C{// day provides type Workday}$
177void foo( Planet p );
178foo( last() );                                                  $\C{// parameter provides type Planet}$
179\end{cfa}
180
181The trait @Serial@:
182\begin{cfa}
183forall( E | Bounded( E ) ) trait Serial {
184        unsigned fromInstance( E e );
185        E fromInt( unsigned int posn );
186        E succ( E e );
187        E pred( E e );
188};
189\end{cfa}
190is a @Bounded@ trait, where elements can be mapped to an integer sequence.
191A type @T@ matching @Serial@ can project to an unsigned @int@ type, \ie an instance of type T has a corresponding integer value.
192%However, the inverse may not be possible, and possible requires a bound check.
193The mapping from a serial type to integer is defined by @fromInstance@, which returns the enumerator's position.
194The inverse operation is @fromInt@, which performs a bound check using @first()@ and @last()@ before casting the integer into an enumerator.
195Specifically, for enumerator @E@ declaring $N$ enumerators, @fromInt( i )@ returns the $i-1_{th}$ enumerator, if $0 \leq i < N$, or raises the exception @enumBound@.
196
197The @succ( E e )@ and @pred( E e )@ imply the enumeration positions are consecutive and ordinal.
198Specifically, 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()$.
199The exception @enumRange@ is raised if the result of either operation is outside the range of type @E@.
200
201Finally, there is an associated trait defining comparison operators among enumerators.
202\begin{cfa}
203forall( E, T | CfaEnum( E, T ) ) {
204        // comparison
205        int ?==?( E l, E r );           $\C{// true if l and r are same enumerators}$
206        int ?!=?( E l, E r );           $\C{// true if l and r are different enumerators}$
207        int ?!=?( E l, zero_t );        $\C{// true if l is not the first enumerator}$
208        int ?<?( E l, E r );            $\C{// true if l is an enumerator before r}$
209        int ?<=?( E l, E r );           $\C{// true if l before or the same as r}$
210        int ?>?( E l, E r );            $\C{// true if l is an enumerator after r}$
211        int ?>=?( E l, E r );           $\C{// true if l after or the same as r}$         
212}
213\end{cfa}
214
215\section{Typed Enum}
216\label{s:EnumeratorTyping}
217
218\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.
219Figure~\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.
220Note, the synonyms @Liz@ and @Beth@ in the last declaration.
221Because enumerators are constants, the enumeration type is implicitly @const@, so all the enumerator types in Figure~\ref{f:EumeratorTyping} are logically rewritten with @const@.
222
223C has an implicit type conversion from an enumerator to its base type @int@.
224Correspondingly, \CFA has an implicit (safe) conversion from a typed enumerator to its base type.
225\begin{cfa}
226char currency = Dollar;
227string fred = Fred;                                             $\C{// implicit conversion from char * to \CFA string type}$
228Person student = Beth;
229\end{cfa}
230
231% \begin{cfa}
232% struct S { int i, j; };
233% enum( S ) s { A = { 3,  4 }, B = { 7,  8 } };
234% enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$'  };
235% enum( @double@ ) Planet { Venus = 4.87, Earth = 5.97, Mars = 0.642  }; // mass
236% enum( @char *@ ) Colour { Red = "red", Green = "green", Blue = "blue"  };
237% enum( @Currency@ ) Europe { Euro = '$\texteuro$', Pound = '$\textsterling$' }; // intersection
238% \end{cfa}
239
240\begin{figure}
241\begin{cfa}
242// integral
243        enum( @char@ ) Currency { Dollar = '$\textdollar$', Cent = '$\textcent$', Yen = '$\textyen$', Pound = '$\textsterling$', Euro = 'E' };
244        enum( @signed char@ ) srgb { Red = -1, Green = 0, Blue = 1 };
245        enum( @long long int@ ) BigNum { X = 123_456_789_012_345,  Y = 345_012_789_456_123 };
246// non-integral
247        enum( @double@ ) Math { PI_2 = 1.570796, PI = 3.141597, E = 2.718282 };
248        enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i };
249// pointer
250        enum( @const char *@ ) Name { Fred = "FRED", Mary = "MARY", Jane = "JANE" };
251        int i, j, k;
252        enum( @int *@ ) ptr { I = &i,  J = &j,  K = &k };
253        enum( @int &@ ) ref { I = i,   J = j,   K = k };
254// tuple
255        enum( @[int, int]@ ) { T = [ 1, 2 ] }; $\C{// new \CFA type}$
256// function
257        void f() {...}   void g() {...}
258        enum( @void (*)()@ ) funs { F = f,  G = g };
259// aggregate
260        struct Person { char * name; int age, height; };
261@***@enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz,
262                                                                        Jon = { "JONATHAN", 35, 190 } };
263\end{cfa}
264\caption{Enumerator Typing}
265\label{f:EumeratorTyping}
266\end{figure}
267
268An advantage of the typed enumerations is eliminating the \emph{harmonizing} problem between an enumeration and companion data \see{\VRef{s:Usage}}:
269\begin{cfa}
270enum( char * ) integral_types {
271        chr = "char", schar = "signed char", uschar = "unsigned char",
272        sshort = "signed short int", ushort = "unsigned short int",
273        sint = "signed int", usint = "unsigned int",
274        ...
275};
276\end{cfa}
277Note, 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.
278
279While the enumeration type can be any C aggregate, the aggregate's \CFA constructors are not used to evaluate an enumerator's value.
280\CFA enumeration constants are compile-time values (static);
281calling constructors happens at runtime (dynamic).
282
283\section{Enumeration Inheritance}
284
285\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).
286
287\begin{cfa}
288enum( char * ) Names { /* as above */ };
289enum( char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" };
290enum( char * ) Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" };
291\end{cfa}
292
293Enumeration @Name2@ inherits all the enumerators and their values from enumeration @Names@ by containment, and a @Names@ enumeration is a subtype of enumeration @Name2@.
294Note, that enumerators must be unique in inheritance but enumerator values may be repeated.
295
296% The enumeration type for the inheriting type must be the same as the inherited type;
297% hence the enumeration type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for @Name3@.
298% When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important.
299Specifically, the inheritance relationship for @Names@ is:
300\begin{cfa}
301Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\C{// enum type of Names}$
302\end{cfa}
303A subtype can be cast to its supertype, assigned to a supertype variable, or be used as a function argument that expects the supertype.
304\begin{cfa}
305Names fred = Name.Fred;
306(Names2) fred; (Names3) fred; (Name3) Names.Jack;  $\C{// cast to super type}$
307Names2 fred2 = fred; Names3 fred3 = fred2; $\C{// assign to super type}$
308\end{cfa}
309For the given function prototypes, the following calls are valid.
310\begin{cquote}
311\begin{tabular}{ll}
312\begin{cfa}
313void f( Names );
314void g( Names2 );
315void h( Names3 );
316void j( const char * );
317\end{cfa}
318&
319\begin{cfa}
320f( Fred );
321g( Fred );   g( Jill );
322h( Fred );   h( Jill );   h( Sue );
323j( Fred );    j( Jill );    j( Sue );    j( "WILL" );
324\end{cfa}
325\end{tabular}
326\end{cquote}
327Note, 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.
328
329\section{Enumerator Control Structures}
330
331Enumerators can be used in multiple contexts.
332In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution).
333However, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect in some contexts.
334In these contexts, a programmer's initition assumes an implicit conversion to position.
335
336For 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.
337\begin{cquote}
338\begin{cfa}
339enum Count { First, Second, Third, Fourth };
340Count e;
341\end{cfa}
342\begin{tabular}{ll}
343\begin{cfa}
344
345choose( e ) {
346        case @First@: ...;
347        case @Second@: ...;
348        case @Third@: ...;
349        case @Fourth@: ...;
350}
351\end{cfa}
352&
353\begin{cfa}
354// rewrite
355choose( @value@( e ) ) {
356        case @value@( First ): ...;
357        case @value@( Second ): ...;
358        case @value@( Third ): ...;
359        case @value@( Fourth ): ...;
360}
361\end{cfa}
362\end{tabular}
363\end{cquote}
364Here, 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.
365However, this implementation is fragile, \eg if the enumeration is changed to:
366\begin{cfa}
367enum Count { First, Second, Third @= First@, Fourth };
368\end{cfa}
369which make @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicate @case@ clauses.
370To better match with programmer intuition, \CFA toggles between value and position semantics depending on the language context.
371For conditional clauses and switch statements, \CFA uses the robust position implementation.
372\begin{cfa}
373choose( @position@( e ) ) {
374        case @position@( First ): ...;
375        case @position@( Second ): ...;
376        case @position@( Third ): ...;
377        case @position@( Fourth ): ...;
378}
379\end{cfa}
380
381\begin{cfa}
382Count variable_a = First, variable_b = Second, variable_c = Third, variable_d = Fourth;
383p(variable_a); // 0
384p(variable_b); // 1
385p(variable_c); // "Third"
386p(variable_d); // 3
387\end{cfa}
388
389\begin{cfa}
390for (d; Workday) { sout | d; }
391for (p; +~=Planet) { sout | p; }
392for (c: -~=Alphabet ) { sout | c; }
393\end{cfa}
394The @range loop@ for enumeration is a syntax sugar that loops over all enumerators and assigns each enumeration to a variable in every iteration.
395The loop control of the range loop consists of two parts: a variable declaration and a @range expression@, with the type of the variable
396can be inferred from the range expression.
397
398The range expression is an enumeration type, optionally prefixed by @+~=@ or @-~=@. Without a prefix, or prefixed with @+~=@, the control
399loop over all enumerators from the first to the last. With a @-~=@ prefix, the control loops backward.
400
401On a side note, the loop syntax
402\begin{cfa}
403for ( typeof(Workday) d; d <= last(); d = succ(d) );
404\end{cfa}
405does not work. When d == last(), the loop control will still attempt to assign succ(d) to d, which causes an @enumBound@ exception.
406
407\CFA reduces conditionals to its "if case" if the predicate is not equal to ( @!=@ ) zero, and the "else case" otherwise.
408Overloading the @!=@ operator with an enumeration type against the zero defines a conceptual conversion from
409enum to boolean, which can be used as predicates.
410
411\begin{cfa}
412enum(int) ErrorCode { Normal = 0, Slow = 1, Overheat = 1000, OutOfResource = 1001 };
413bool ?!=?(ErrorCode lhs, zero_t) { return value(lhs) >= 1000; }
414ErrorCode code = /.../
415if (code) { scream(); }
416\end{cfa}
417
418Incidentally, \CFA does not define boolean conversion for enumeration. If no
419@?!=?(ErrorCode, zero_t)@
420overloading defined,
421\CFA looks for the boolean conversion in terms of its value and gives a compiler error if no such conversion is available.
422
423\begin{cfa}
424enum(int) Weekday { Mon, Tues, Wed, Thurs, Fri, Sat, Sun, };
425enum() Colour { Red, Green, Blue };
426enum(S) Fruit { Apple, Banana, Cherry }
427Weekday w = ...; Colour c = ...; Fruit f = ...;
428if (w) { ... } // w is true if and only if w != Mon, because value(Mon) == 0 (auto initialized)
429if (c) { ... } // error
430if (s) { ... } // depends on ?!=?(S lhs, zero_t ), and error if no such overloading available
431\end{cfa}
432
433As an alternative, users can define the boolean conversion for CfaEnum:
434
435\begin{cfa}
436forall(E | CfaEnum(E))
437bool ?!=?(E lhs, zero_t) {
438        return posn(lhs) != 0;
439}
440\end{cfa}
441which effectively turns the first enumeration as a logical zero and non-zero for others.
442
443\section{Enumerated Arrays}
444Enumerated arrays use an \CFA array as their index.
445\begin{cfa}
446enum() Colour {
447        Red, Orange, Yellow, Green, Blue, Indigo, Violet
448};
449
450string colourCode[Colour] = { "#e81416", "#ffa500", "#ffa500", "#ffa500", "#487de7", "#4b369d", "#70369d" };
451sout | "Colour Code of Orange is " | colourCode[Orange];
452\end{cfa}
453
454
455\section{Planet Example}
456
457\VRef[Figure]{f:PlanetExample} shows an archetypal enumeration example illustrating most of the \CFA enumeration features.
458@Planet@ is an enumeration of type @MR@.
459Each planet enumerator is initialized to a specific mass/radius, @MR@, value.
460The unnamed enumeration provides the gravitational-constant enumerator @G@.
461Function @surfaceGravity@ uses the @with@ clause to remove @p@ qualification from fields @mass@ and @radius@.
462The 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@.
463The resulting random orbital-body is used in a @choose@ statement.
464The enumerators in the @case@ clause use the enumerator position for testing.
465The prints use @label@ to print an enumerator's name.
466Finally, a loop enumerates through the planets computing the weight on each planet for a given earth mass.
467The print statement does an equality comparison with an enumeration variable and enumerator (@p == MOON@).
468
469\begin{figure}
470\small
471\begin{cfa}
472struct MR { double mass, radius; };
473enum( @MR@ ) Planet {                                           $\C{// typed enumeration}$
474        //                      mass (kg)   radius (km)
475        MERCURY = { 0.330_E24, 2.4397_E6 },
476        VENUS      = { 4.869_E24, 6.0518_E6 },
477        EARTH       = { 5.976_E24, 6.3781_E6 },
478        MOON        = { 7.346_E22, 1.7380_E6 }, $\C{// not a planet}$
479        MARS         = { 0.642_E24, 3.3972_E6 },
480        JUPITER    = { 1898._E24, 71.492_E6 },
481        SATURN     = { 568.8_E24, 60.268_E6 },
482        URANUS    = { 86.86_E24, 25.559_E6 },
483        NEPTUNE  = { 102.4_E24, 24.746_E6 },
484        PLUTO       = { 1.303_E22, 1.1880_E6 }, $\C{// not a planet}$
485};
486enum( double ) { G = 6.6743_E-11 };                     $\C{// universal gravitational constant (m3 kg-1 s-2)}$
487static double surfaceGravity( Planet p ) @with( p )@ {
488        return G * mass / ( radius @\@ 2 );             $\C{// no qualification, exponentiation}$
489}
490static double surfaceWeight( Planet p, double otherMass ) {
491        return otherMass * surfaceGravity( p );
492}
493int main( int argc, char * argv[] ) {
494        if ( argc != 2 ) @exit@ | "Usage: " | argv[0] | "earth-weight";  // terminate program
495        double earthWeight = convert( argv[1] );
496        double earthMass = earthWeight / surfaceGravity( EARTH );
497        Planet rp = @fromInt@( prng( @countof@( Planet ) ) ); $\C{// select random orbiting body}$
498        @choose( rp )@ {                                                $\C{// implicit breaks}$
499          case MERCURY, VENUS, EARTH, MARS:
500                sout | @rp@ | "is a rocky planet";
501          case JUPITER, SATURN, URANUS, NEPTUNE:
502                sout | rp | "is a gas-giant planet";
503          default:
504                sout | rp | "is not a planet";
505        }
506        for ( @p; Planet@ ) {                                   $\C{// enumerate}$
507                sout | "Your weight on" | ( @p == MOON@ ? "the" : " " ) | p
508                           | "is" | wd( 1,1,  surfaceWeight( p, earthMass ) ) | "kg";
509        }
510}
511$\$$ planet 100
512JUPITER is a gas-giant planet
513Your weight on MERCURY is 37.7 kg
514Your weight on VENUS is 90.5 kg
515Your weight on EARTH is 100.0 kg
516Your weight on the MOON is 16.6 kg
517Your weight on MARS is 37.9 kg
518Your weight on JUPITER is 252.8 kg
519Your weight on SATURN is 106.6 kg
520Your weight on URANUS is 90.5 kg
521Your weight on NEPTUNE is 113.8 kg
522Your weight on PLUTO is 6.3 kg
523\end{cfa}
524\caption{Planet Example}
525\label{f:PlanetExample}
526\end{figure}
Note: See TracBrowser for help on using the repository browser.