| 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 | 
 | 
|---|
| 7 | 
 | 
|---|
| 8 | \section{Enumerator Name Resolution}
 | 
|---|
| 9 | \label{s:EnumeratorNameResolution}
 | 
|---|
| 10 | 
 | 
|---|
| 11 | In C, unscoping of enumerators presents a \Newterm{naming problem} when multiple enumeration types appear in the same scope with duplicate enumerator names.
 | 
|---|
| 12 | There is no mechanism in C to resolve these naming conflicts other than renaming of one of the duplicates, which may be impossible.
 | 
|---|
| 13 | 
 | 
|---|
| 14 | The \CFA type-system allows extensive overloading, including enumerators.
 | 
|---|
| 15 | Furthermore, \CFA uses the left-hand of assignment in type resolution to pinpoint the best overloaded name.
 | 
|---|
| 16 | Finally, qualification is provided to disambiguate any ambiguous situations.
 | 
|---|
| 17 | \begin{cfa}
 | 
|---|
| 18 | enum E1 { First, Second, Third, Fourth };
 | 
|---|
| 19 | enum E2 { @Fourth@, @Third@, @Second@, @First@ };
 | 
|---|
| 20 | E1 p() { return Third; }                                $\C{// correctly resolved duplicate names}$
 | 
|---|
| 21 | E2 p() { return Fourth; }
 | 
|---|
| 22 | void foo() {
 | 
|---|
| 23 |         E1 e1 = First;   E2 e2 = First;
 | 
|---|
| 24 |         e1 = Second;   e2 = Second;
 | 
|---|
| 25 |         e1 = p();   e2 = p();                           $\C{// correctly resolved function call}$
 | 
|---|
| 26 |         int i = @E1.@First + @E2.@First;        $\C{// disambiguate with qualification}$
 | 
|---|
| 27 |         int j = @(E1)@First + @(E2)@First;      $\C{// disambiguate with cast}$
 | 
|---|
| 28 | }
 | 
|---|
| 29 | \end{cfa}
 | 
|---|
| 30 | \CFA overloading allows programmers to use the most meaningful names without fear of name clashes from include files.
 | 
|---|
| 31 | Either the type system implicitly disambiguates or the programmer explicitly disambiguates using qualification or casting.
 | 
|---|
| 32 | 
 | 
|---|
| 33 | 
 | 
|---|
| 34 | \section{Enumerator Scoping}
 | 
|---|
| 35 | 
 | 
|---|
| 36 | An enumeration can be scoped, so the enumerator constants are not projected into the enclosing scope, using @'!'@.
 | 
|---|
| 37 | \begin{cfa}
 | 
|---|
| 38 | enum Weekday @!@ { Mon, Tue, Wed, Thu = 10, Fri, Sat, Sun };
 | 
|---|
| 39 | enum RGB @!@ { Red, Green, Blue };
 | 
|---|
| 40 | \end{cfa}
 | 
|---|
| 41 | Now the enumerators \emph{must} be qualified with the associated enumeration.
 | 
|---|
| 42 | \begin{cfa}
 | 
|---|
| 43 | Weekday weekday = @Weekday@.Mon;
 | 
|---|
| 44 | weekday = @Weekday@.Sat;
 | 
|---|
| 45 | RGB rgb = RGB.Red;
 | 
|---|
| 46 | rgb = RGB.Blue;
 | 
|---|
| 47 | \end{cfa}
 | 
|---|
| 48 | 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}).
 | 
|---|
| 49 | \begin{cfa}
 | 
|---|
| 50 | with ( @Weekday@, @RGB@ ) {                     $\C{// type names}$
 | 
|---|
| 51 |          weekday = @Sun@;                               $\C{// no qualification}$
 | 
|---|
| 52 |          rgb = @Green@;
 | 
|---|
| 53 | }
 | 
|---|
| 54 | \end{cfa}
 | 
|---|
| 55 | As in Section~\ref{s:EnumeratorNameResolution}, opening multiple unscoped enumerations can result in duplicate enumeration names, but \CFA implicit type resolution and explicit qualification/casting handles name resolution.
 | 
|---|
| 56 | 
 | 
|---|
| 57 | \section{Enumerator Typing}
 | 
|---|
| 58 | 
 | 
|---|
| 59 | \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.
 | 
|---|
| 60 | 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.
 | 
|---|
| 61 | Note, the synonyms @Liz@ and @Beth@ in the last declaration.
 | 
|---|
| 62 | 
 | 
|---|
| 63 | Because enumerators are constants, the enumeration type is implicitly @const@, so all the enumerator types in Figure~\ref{f:EumeratorTyping} are rewritten with @const@.
 | 
|---|
| 64 | A typed enumeration has an implicit (safe) conversion to its base type.
 | 
|---|
| 65 | \begin{cfa}
 | 
|---|
| 66 | char currency = Dollar;
 | 
|---|
| 67 | string fred = Fred;                                             $\C{// implicit conversion from char * to \CFA string type}$
 | 
|---|
| 68 | Person student = Beth;
 | 
|---|
| 69 | \end{cfa}
 | 
|---|
| 70 | 
 | 
|---|
| 71 | % \begin{cfa}
 | 
|---|
| 72 | % struct S { int i, j; };
 | 
|---|
| 73 | % enum( S ) s { A = { 3,  4 }, B = { 7,  8 } };
 | 
|---|
| 74 | % enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$'  };
 | 
|---|
| 75 | % enum( @double@ ) Planet { Venus = 4.87, Earth = 5.97, Mars = 0.642  }; // mass
 | 
|---|
| 76 | % enum( @char *@ ) Colour { Red = "red", Green = "green", Blue = "blue"  };
 | 
|---|
| 77 | % enum( @Currency@ ) Europe { Euro = '$\texteuro$', Pound = '$\textsterling$' }; // intersection
 | 
|---|
| 78 | % \end{cfa}
 | 
|---|
| 79 | 
 | 
|---|
| 80 | \begin{figure}
 | 
|---|
| 81 | \begin{cfa}
 | 
|---|
| 82 | // integral
 | 
|---|
| 83 |         enum( @char@ ) Currency { Dollar = '$\textdollar$', Cent = '$\textcent$', Yen = '$\textyen$', Pound = '$\textsterling$', Euro = 'E' };
 | 
|---|
| 84 |         enum( @signed char@ ) srgb { Red = -1, Green = 0, Blue = 1 };
 | 
|---|
| 85 |         enum( @long long int@ ) BigNum { X = 123_456_789_012_345,  Y = 345_012_789_456_123 };
 | 
|---|
| 86 | // non-integral
 | 
|---|
| 87 |         enum( @double@ ) Math { PI_2 = 1.570796, PI = 3.141597, E = 2.718282 };
 | 
|---|
| 88 |         enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i };
 | 
|---|
| 89 | // pointer
 | 
|---|
| 90 |         enum( @const char *@ ) Name { Fred = "FRED", Mary = "MARY", Jane = "JANE" };
 | 
|---|
| 91 |         int i, j, k;
 | 
|---|
| 92 |         enum( @int *@ ) ptr { I = &i,  J = &j,  K = &k };
 | 
|---|
| 93 |         enum( @int &@ ) ref { I = i,   J = j,   K = k };
 | 
|---|
| 94 | // tuple
 | 
|---|
| 95 |         enum( @[int, int]@ ) { T = [ 1, 2 ] }; $\C{// new \CFA type}$
 | 
|---|
| 96 | // function
 | 
|---|
| 97 |         void f() {...}   void g() {...}
 | 
|---|
| 98 |         enum( @void (*)()@ ) funs { F = f,  G = g };
 | 
|---|
| 99 | // aggregate
 | 
|---|
| 100 |         struct Person { char * name; int age, height; };
 | 
|---|
| 101 | @***@enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz,
 | 
|---|
| 102 |                                                                                         Jon = { "JONATHAN", 35, 190 } };
 | 
|---|
| 103 | \end{cfa}
 | 
|---|
| 104 | \caption{Enumerator Typing}
 | 
|---|
| 105 | \label{f:EumeratorTyping}
 | 
|---|
| 106 | \end{figure}
 | 
|---|
| 107 | 
 | 
|---|
| 108 | Typed enumerations deals with the \emph{harmonizing} problem between an enumeration and any companion data.
 | 
|---|
| 109 | The following example is from the \CFA compiler, written in \CC.
 | 
|---|
| 110 | \begin{cfa}
 | 
|---|
| 111 | enum integral_types { chr, schar, uschar, sshort, ushort, sint, usint, ..., NO_OF_ITYPES };
 | 
|---|
| 112 | char * integral_names[NO_OF_ITYPES] = {
 | 
|---|
| 113 |         "char", "signed char", "unsigned char",
 | 
|---|
| 114 |         "signed short int", "unsigned short int",
 | 
|---|
| 115 |         "signed int", "unsigned int",
 | 
|---|
| 116 |         ...
 | 
|---|
| 117 | };
 | 
|---|
| 118 | \end{cfa}
 | 
|---|
| 119 | The \emph{harmonizing} problem occurs because the enumeration declaration is in one header file and the names are declared in another translation unit.
 | 
|---|
| 120 | It is up to the programmer to ensure changes made in one location are harmonized with the other location (by identifying this requirement within a comment).
 | 
|---|
| 121 | The typed enumeration largely solves this problem by combining and managing the two data types.
 | 
|---|
| 122 | \begin{cfa}
 | 
|---|
| 123 | enum( char * ) integral_types {
 | 
|---|
| 124 |         chr = "char", schar = "signed char", uschar = "unsigned char",
 | 
|---|
| 125 |         sshort = "signed short int", ushort = "unsigned short int",
 | 
|---|
| 126 |         sint = "signed int", usint = "unsigned int",
 | 
|---|
| 127 |         ...
 | 
|---|
| 128 | };
 | 
|---|
| 129 | \end{cfa}
 | 
|---|
| 130 | 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.
 | 
|---|
| 131 | 
 | 
|---|
| 132 | While the enumeration type can be any C aggregate, the aggregate's \CFA constructors are not used to evaluate an enumerator's value.
 | 
|---|
| 133 | \CFA enumeration constants are compile-time values (static);
 | 
|---|
| 134 | calling constructors happens at runtime (dynamic).
 | 
|---|
| 135 | 
 | 
|---|
| 136 | 
 | 
|---|
| 137 | \section{Pure Enumerators}
 | 
|---|
| 138 | 
 | 
|---|
| 139 | An empty enumerator type, @enum()@, implies the enumerators are pure symbols without values but set properties;
 | 
|---|
| 140 | hence, there is no default conversion to @int@. 
 | 
|---|
| 141 | 
 | 
|---|
| 142 | \begin{cfa}
 | 
|---|
| 143 | enum() Mode { O_RDONLY, O_WRONLY, O_CREAT, O_TRUNC, O_APPEND };
 | 
|---|
| 144 | Mode iomode = O_RDONLY;
 | 
|---|
| 145 | bool b = iomode == O_RDONLY || iomode < O_APPEND; $\C{// ordering}$
 | 
|---|
| 146 | @***@@int i = iomode;@                                                  $\C{// disallow conversion to int}$
 | 
|---|
| 147 | \end{cfa}
 | 
|---|
| 148 | 
 | 
|---|
| 149 | \section{Enumerator Subset}
 | 
|---|
| 150 | 
 | 
|---|
| 151 | If follows from enumerator typing that the enumerator type can be another enumerator.
 | 
|---|
| 152 | \begin{cfa}
 | 
|---|
| 153 | enum( @char@ ) Currency { Dollar = '$\textdollar$', Cent = '$\textcent$', Yen = '$\textyen$', Pound = '$\textsterling$', Euro = 'E' };
 | 
|---|
| 154 | enum( Currency ) Europe { Euro = Currency.Euro, Pound = Currency.Pound };
 | 
|---|
| 155 | enum( char ) Letter { A = 'A',  B = 'B', C = 'C', ..., Z = 'Z' };
 | 
|---|
| 156 | enum( @Letter@ ) Greek { Alph = A, Beta = B, ..., Zeta = Z }; // intersection
 | 
|---|
| 157 | \end{cfa}
 | 
|---|
| 158 | Subset enumerations may have more or less enumerators than their typed enumeration, but the enumerator values must be from the typed enumeration.
 | 
|---|
| 159 | For example, @Greek@ enumerators are a subset of type @Letter@ and are type compatible with enumeration @Letter@, but @Letter@ enumerators are not type compatible with enumeration @Greek@. 
 | 
|---|
| 160 | \begin{cfa}
 | 
|---|
| 161 | Letter letter = A;
 | 
|---|
| 162 | Greak greek = Beta;
 | 
|---|
| 163 | letter = Beta;                                                  $\C{// allowed, greek == B}$
 | 
|---|
| 164 | @greek = A;@                                                    $\C{// disallowed}$
 | 
|---|
| 165 | \end{cfa}
 | 
|---|
| 166 | 
 | 
|---|
| 167 | 
 | 
|---|
| 168 | \section{Enumeration Inheritance}
 | 
|---|
| 169 | 
 | 
|---|
| 170 | \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).
 | 
|---|
| 171 | \begin{cfa}
 | 
|---|
| 172 | enum( char * ) Names { /* as above */ };
 | 
|---|
| 173 | enum( char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" };
 | 
|---|
| 174 | @***@enum /* inferred */ Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" };
 | 
|---|
| 175 | \end{cfa}
 | 
|---|
| 176 | Enumeration @Name2@ inherits all the enumerators and their values from enumeration @Names@ by containment, and a @Names@ enumeration is a subtype of enumeration @Name2@.
 | 
|---|
| 177 | Note, enumerators must be unique in inheritance but enumerator values may be repeated.
 | 
|---|
| 178 | 
 | 
|---|
| 179 | The enumeration type for the inheriting type must be the same as the inherited type;
 | 
|---|
| 180 | hence the enumeration type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for @Name3@.
 | 
|---|
| 181 | % When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important.
 | 
|---|
| 182 | Specifically, the inheritance relationship for @Names@ is:
 | 
|---|
| 183 | \begin{cfa}
 | 
|---|
| 184 | Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\(\subset\)$ const char * $\C{// enum type of Names}$
 | 
|---|
| 185 | \end{cfa}
 | 
|---|
| 186 | For the given function prototypes, the following calls are valid.
 | 
|---|
| 187 | \begin{cquote}
 | 
|---|
| 188 | \begin{tabular}{ll}
 | 
|---|
| 189 | \begin{cfa}
 | 
|---|
| 190 | void f( Names );
 | 
|---|
| 191 | void g( Names2 );
 | 
|---|
| 192 | void h( Names3 );
 | 
|---|
| 193 | void j( const char * );
 | 
|---|
| 194 | \end{cfa}
 | 
|---|
| 195 | &
 | 
|---|
| 196 | \begin{cfa}
 | 
|---|
| 197 | f( Fred );
 | 
|---|
| 198 | g( Fred );   g( Jill );
 | 
|---|
| 199 | h( Fred );   h( Jill );   h( Sue );
 | 
|---|
| 200 | j( Fred );   j( Jill );   j( Sue );   j( "WILL" );
 | 
|---|
| 201 | \end{cfa}
 | 
|---|
| 202 | \end{tabular}
 | 
|---|
| 203 | \end{cquote}
 | 
|---|
| 204 | 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.
 | 
|---|
| 205 | 
 | 
|---|
| 206 | 
 | 
|---|
| 207 | \section{Enumeration Pseudo-functions}
 | 
|---|
| 208 | 
 | 
|---|
| 209 | Pseudo-functions are function-like operators that do not result in any run-time computations, \ie like @sizeof@, @offsetof@, @typeof@.
 | 
|---|
| 210 | Often a call to a pseudo-function is substituted with information extracted from the symbol table at compilation time, like storage size or alignment associated with the underlying architecture..
 | 
|---|
| 211 | 
 | 
|---|
| 212 | The attributes of an enumerator are accessed by pseudo-functions @position@, @value@, and @label@.
 | 
|---|
| 213 | \begin{cfa}
 | 
|---|
| 214 | @***@int jane_pos = @position@( Names.Jane );   $\C{// 2}$
 | 
|---|
| 215 | @***@char * jane_value = @value@( Names.Jane ); $\C{// "JANE"}$
 | 
|---|
| 216 | @***@char * jane_label = @label@( Names.Jane ); $\C{// "Jane"}$
 | 
|---|
| 217 | sout | @label@( Names.Jane ) | @value@( Names.Jane );
 | 
|---|
| 218 | \end{cfa}
 | 
|---|
| 219 | Note the ability to print both enumerator label and value.
 | 
|---|
| 220 | 
 | 
|---|
| 221 | 
 | 
|---|
| 222 | \section{Enumerator Position or Value}
 | 
|---|
| 223 | 
 | 
|---|
| 224 | Enumerators can be used in multiple contexts.
 | 
|---|
| 225 | In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution).
 | 
|---|
| 226 | However, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect in some contexts.
 | 
|---|
| 227 | In these contexts, a programmer's initition assumes an implicit conversion to postion.
 | 
|---|
| 228 | 
 | 
|---|
| 229 | 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.
 | 
|---|
| 230 | \begin{cquote}
 | 
|---|
| 231 | \begin{cfa}
 | 
|---|
| 232 | enum Count { First, Second, Third, Fourth };
 | 
|---|
| 233 | Count e;
 | 
|---|
| 234 | \end{cfa}
 | 
|---|
| 235 | \begin{tabular}{ll}
 | 
|---|
| 236 | \begin{cfa}
 | 
|---|
| 237 | 
 | 
|---|
| 238 | choose( e ) {
 | 
|---|
| 239 |         case @First@: ...;
 | 
|---|
| 240 |         case @Second@: ...;
 | 
|---|
| 241 |         case @Third@: ...;
 | 
|---|
| 242 |         case @Fourth@: ...;
 | 
|---|
| 243 | }
 | 
|---|
| 244 | \end{cfa}
 | 
|---|
| 245 | &
 | 
|---|
| 246 | \begin{cfa}
 | 
|---|
| 247 | // rewrite
 | 
|---|
| 248 | choose( @value@( e ) ) {
 | 
|---|
| 249 |         case @value@( First ): ...;
 | 
|---|
| 250 |         case @value@( Second ): ...;
 | 
|---|
| 251 |         case @value@( Third ): ...;
 | 
|---|
| 252 |         case @value@( Fourth ): ...;
 | 
|---|
| 253 | }
 | 
|---|
| 254 | \end{cfa}
 | 
|---|
| 255 | \end{tabular}
 | 
|---|
| 256 | \end{cquote}
 | 
|---|
| 257 | Here, the intuitive code on the left is implicitly transformed into the statndard implementation on the right, using the value of the enumeration variable and enumerators.
 | 
|---|
| 258 | However, this implementation is fragile, \eg if the enumeration is changed to:
 | 
|---|
| 259 | \begin{cfa}
 | 
|---|
| 260 | enum Count { First, Second, Third @= First@, Fourth };
 | 
|---|
| 261 | \end{cfa}
 | 
|---|
| 262 | which make @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicase @case@ clauses.
 | 
|---|
| 263 | To better match with programmer intuition, \CFA toggles between value and position semantics depneding on the language context.
 | 
|---|
| 264 | For conditional clauses and switch statments, \CFA uses the robust position implementation.
 | 
|---|
| 265 | \begin{cfa}
 | 
|---|
| 266 | choose( @position@( e ) ) {
 | 
|---|
| 267 |         case @position@( First ): ...;
 | 
|---|
| 268 |         case @position@( Second ): ...;
 | 
|---|
| 269 |         case @position@( Third ): ...;
 | 
|---|
| 270 |         case @position@( Fourth ): ...;
 | 
|---|
| 271 | }
 | 
|---|
| 272 | \end{cfa}
 | 
|---|
| 273 | 
 | 
|---|
| 274 | \begin{cfa}
 | 
|---|
| 275 | Count variable_a = First, variable_b = Second, variable_c = Third, variable_d = Fourth;
 | 
|---|
| 276 | p(variable_a); // 0
 | 
|---|
| 277 | p(variable_b); // 1
 | 
|---|
| 278 | p(variable_c); // "Third"
 | 
|---|
| 279 | p(variable_d); // 3
 | 
|---|
| 280 | \end{cfa}
 | 
|---|
| 281 | 
 | 
|---|
| 282 | 
 | 
|---|
| 283 | \section{Planet Example}
 | 
|---|
| 284 | 
 | 
|---|
| 285 | \VRef[Figure]{f:PlanetExample} shows an archetypal enumeration example illustrating all of the \CFA enumeration features.
 | 
|---|
| 286 | Enumeration @Planet@ is a typed enumeration of type @MR@.
 | 
|---|
| 287 | Each of the planet enumerators is initialized to a specific mass/radius, @MR@, value.
 | 
|---|
| 288 | The unnamed enumeration projects the gravitational-constant enumerator @G@.
 | 
|---|
| 289 | The program main iterates through the planets computing the weight on each planet for a given earth weight.
 | 
|---|
| 290 | 
 | 
|---|
| 291 | \begin{figure}
 | 
|---|
| 292 | \begin{cfa}
 | 
|---|
| 293 | struct MR { double mass, radius; };
 | 
|---|
| 294 | enum( MR ) Planet {
 | 
|---|
| 295 |         //                           mass          radius
 | 
|---|
| 296 |         MERCURY = { 3.303_E23, 2.4397_E6 },
 | 
|---|
| 297 |         VENUS       = { 4.869_E24, 6.0518_E6 },
 | 
|---|
| 298 |         EARTH       = { 5.976_E24, 6.3781_E6 },
 | 
|---|
| 299 |         MARS         = { 6.421_E23, 3.3972_E6 },
 | 
|---|
| 300 |         JUPITER    = { 1.898_E27, 7.1492_E7 },
 | 
|---|
| 301 |         SATURN     = { 5.688_E26, 6.0268_E7 },
 | 
|---|
| 302 |         URANUS    = { 8.686_E25, 2.5559_E7 },
 | 
|---|
| 303 |         NEPTUNE  = { 1.024_E26, 2.4746_E7 },
 | 
|---|
| 304 | };
 | 
|---|
| 305 | enum( double ) { G = 6.6743E-11 }; // universal gravitational constant (m3 kg-1 s-2)
 | 
|---|
| 306 | 
 | 
|---|
| 307 | static double surfaceGravity( Planet p ) with( p ) {
 | 
|---|
| 308 |         return G * mass / ( radius * radius );
 | 
|---|
| 309 | }
 | 
|---|
| 310 | static double surfaceWeight( Planet p, double otherMass ) {
 | 
|---|
| 311 |         return otherMass * surfaceGravity( p );
 | 
|---|
| 312 | }
 | 
|---|
| 313 | int main( int argc, char * argv[] ) {
 | 
|---|
| 314 |         if ( argc != 2 ) exit | "Usage: " | argv[0] | "earth-weight";
 | 
|---|
| 315 |         double earthWeight = convert( argv[1] );
 | 
|---|
| 316 |         double mass = earthWeight / surfaceGravity( EARTH );
 | 
|---|
| 317 |         for ( p; Planet ) {
 | 
|---|
| 318 |                 sout | "Your weight on" | labelE(p) | "is" | surfaceWeight( p, mass );
 | 
|---|
| 319 |         }
 | 
|---|
| 320 | }
 | 
|---|
| 321 | \end{cfa}
 | 
|---|
| 322 | \caption{Planet Example}
 | 
|---|
| 323 | \label{f:PlanetExample}
 | 
|---|
| 324 | \end{figure}
 | 
|---|