source: doc/theses/jiada_liang_MMath/CFAenum.tex @ 2325b57

Last change on this file since 2325b57 was c329bca, checked in by JiadaL <j82liang@…>, 2 months ago

Add a sentence about linkonce

  • Property mode set to 100644
File size: 29.4 KB
Line 
1\chapter{\texorpdfstring{\CFA}{Cforall} Enumeration}
2
3\CFA extends C-Style enumeration by adding a number of new features that bring enumerations in line with other modern programming languages.
4Any enumeration extensions must be intuitive to C programmers in syntax and semantics.
5The following sections detail my new contributions to enumerations in \CFA.
6
7
8\section{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:CFAInheritance}} 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{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, \CFA introduces an additional enumeration pseudo-function @countof@ (like @sizeof@, @typeof@) that returns the number of enumerators in an enumeration.
46\begin{cfa}
47enum(int) E { A, B, C, D } e;
48countof( E )// 4, type argument
49countof( e )// 4, variable argument
50\end{cfa}
51This built-in function replaces the C idiom for automatically computing the number of enumerators \see{\VRef{s:Usage}}.
52\begin{cfa}
53enum E { A, B, C, D, @N@ };  // N == 4
54\end{cfa}
55
56\section{Opaque Enumeration}
57\label{s:OpaqueEnum}
58
59When an enumeration type is empty. it is an \newterm{opaque} enumeration.
60\begin{cfa}
61enum@()@ Mode { O_RDONLY, O_WRONLY, O_CREAT, O_TRUNC, O_APPEND };
62\end{cfa}
63Here, the compiler chooses the internal representation, which is hidden, so the enumerators cannot be initialized.
64Compared to the C enum, opaque enums are more restrictive regarding typing and cannot be implicitly converted to integers.
65\begin{cfa}
66Mode mode = O_RDONLY;
67int www @=@ mode;                                               $\C{// disallowed}$
68\end{cfa}
69Opaque enumerations have only two attribute properties, @label@ and @posn@.
70\begin{cfa}
71char * s = label( O_TRUNC );                    $\C{// "O\_TRUNC"}$
72int open = posn( O_WRONLY );                    $\C{// 1}$
73s = label( mode );                                              $\C{// "O\_RDONLY"}$
74int open = posn( mode );                                $\C{// 0}$
75\end{cfa}
76Equality and relational operations are available.
77\begin{cfa}
78if ( mode @==@ O_CREAT ) ...
79bool b = mode @<@ O_APPEND;
80\end{cfa}
81
82
83\section{Typed Enumeration}
84\label{s:EnumeratorTyping}
85
86When an enumeration type is specified, all enumerators have that type and can be initialized with constants of that type or compile-time convertible to that type.
87Figure~\ref{f:EumeratorTyping} shows a series of examples illustrating that all \CFA types can be used with an enumeration, and each type's values are used to set the enumerator constants.
88Note the use of the synonyms @Liz@ and @Beth@ in the last declaration.
89Because enumerators are constants, the enumeration type is implicitly @const@, so all the enumerator types in Figure~\ref{f:EumeratorTyping} are logically rewritten with @const@.
90
91\begin{figure}
92\begin{cfa}
93// integral
94        enum( @char@ ) Currency { Dollar = '$\textdollar$', Cent = '$\textcent$', Yen = '$\textyen$', Pound = '$\textsterling$', Euro = 'E' };
95        enum( @signed char@ ) srgb { Red = -1, Green = 0, Blue = 1 };
96        enum( @long long int@ ) BigNum { X = 123_456_789_012_345,  Y = 345_012_789_456_123 };
97// non-integral
98        enum( @double@ ) Math { PI_2 = 1.570796, PI = 3.141597, E = 2.718282 };
99        enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i };
100// pointer
101        enum( @char *@ ) Name { Fred = "FRED", Mary = "MARY", Jane = "JANE" };
102        int i, j, k;
103        enum( @int *@ ) ptr { I = &i,  J = &j,  K = &k };
104        enum( @int &@ ) ref { I = i,   J = j,   K = k };
105// tuple
106        enum( @[int, int]@ ) { T = [ 1, 2 ] }; $\C{// new \CFA type}$
107// function
108        void f() {...}   void g() {...}
109        enum( @void (*)()@ ) funs { F = f,  G = g };
110// aggregate
111        struct Person { char * name; int age, height; };
112        enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz,
113                                                                        Jon = { "JONATHAN", 35, 190 } };
114\end{cfa}
115% synonym feature unimplemented
116\caption{Enumerator Typing}
117\label{f:EumeratorTyping}
118\end{figure}
119
120An advantage of the typed enumerations is eliminating the \emph{harmonizing} problem between an enumeration and companion data \see{\VRef{s:Usage}}:
121\begin{cfa}
122enum( char * ) integral_types {
123        chr = "char", schar = "signed char", uschar = "unsigned char",
124        sshort = "signed short int", ushort = "unsigned short int",
125        sint = "signed int", usint = "unsigned int",
126        ...
127};
128\end{cfa}
129Note that 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.
130
131While the enumeration type can be any C aggregate, the aggregate's \CFA constructors are \emph{not} used to evaluate an enumerator's value.
132\CFA enumeration constants are compile-time values (static);
133calling constructors happens at runtime (dynamic).
134
135
136\section{Implementation}
137
138\CFA-cc is a transpiler translating \CFA code into C, which is compiled by a C compiler.
139During transpiling, \CFA-cc breaks a \CFA enumeration definition into a definition of a C enumeration with the same name and auxiliary arrays: a label and value array for a typed enumeration.
140For example:
141\begin{cfa}
142enum( T ) E { E1 = t1, E2 = t2, E3 = t3 };
143\end{cfa}
144is compiled into:
145\begin{cfa}
146enum E { E1, E2, E3 };
147const char * E_labels[3] = { "E1", "E2", "E3" };
148const T E_values[3] = { t1, t2, t3 };
149\end{cfa}
150The generated C enumeration has enumerator values that match \CFA enumerator positions because of C's auto-initialization.
151A \CFA enumeration variable definition is the same in \CFA as C, \eg:
152\begin{cfa}
153enum E e = E1;
154e = E2;
155\end{cfa}
156so these expressions remain unchanged by \CFA-cc.
157Therefore, a \CFA enumeration variable has the same underlying representation as its generated C enumeration.
158This semantics implies a \CFA enumeration variable uses the same storage as a C enumeration variable, that @posn@ can use as its underlying representation, and the label and value arrays take little storage.
159The arrays are annotated with @linkonce@, which are replaced later by gcc attribute @section(".gnu.linkonce.NAME")@, to prevent multiple definitions.
160It should be possible to eliminate the two arrays if unused, either by \CFA if local to a translation unit and unused, or by the linker if global but unreferenced.
161Also, the label and value arrays are declared @static@ and initialized with constants, so the arrays are allocated in the @.data@ section and initialized before program execution.
162Hence, there is no additional execution cost unless new enumeration features are used, and storage usage is minimal as the number of enumerations in a program is small as is the number of enumerators in an enumeration.
163
164Along with the enumeration definition, \CFA-cc generates definitions of the attribute functions, @posn@, @label@ and @value@, for each enumeration:
165\begin{cfa}
166inline int posn( E e ) { return (int) e; }
167inline const * label( E e ) { return E_labels[ (int) e ]; }
168inline const * E_value( E e ) { return E_values[ (int) e ]; }
169\end{cfa}
170where the function calls are normally inlined by the backend C compiler into a few instructions.
171These functions simplify the job of getting the enumerations types through the type system in the same way as normal functions and calls.
172Note, the cast to @int@ is actually an internal reinterpreted cast added before type resolution to stop further reduction on the expression by the type resolver \see{\VRef{s:ValueConversion}} and removed in code generation.
173Finally, to further mitigate \CFA enumeration costs, calls to @label@ and @value@ with an enumeration constant are unrolled into the appropriate constant expression, although this could be left to the backend C compiler.
174Hence, in space and time costs, \CFA enumerations follow the C philosophy of only paying for what is used, modulo some future work to convince the linker to remove un-accessed @label@ and @value@ arrays, possibly with @weak@ attributes.
175
176
177\section{Value Conversion}
178\label{s:ValueConversion}
179C has an implicit type conversion from an enumerator to its base type @int@.
180Correspondingly, \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
181For example, using type @Currency@ in \VRef[Figure]{f:EumeratorTyping}:
182\begin{cfa}
183char currency = Dollar;         $\C{// implicit conversion to base type}$
184void foo( char );
185foo( Dollar );                          $\C{// implicit conversion to base type}$
186\end{cfa}
187The 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.
188\begin{cfa}
189void baz( char ch );            $\C{// (1)}$
190void baz( Currency cu );        $\C{// (2)}$
191baz( Dollar );
192\end{cfa}
193While 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.
194Hence, \CFA chooses the exact match.
195Value 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)@.
196\begin{cfa}
197void bar( @int@ );
198Math x = PI;                            $\C{// (1)}$
199double x = 5.5;                         $\C{// (2)}$
200bar( x );                                       $\C{// costs (1, 0, 0, 0, 0, 0, 0, 0) or (0, 1, 0, 0, 0, 0, 0, 0)}$
201\end{cfa}
202Here, the candidate (1) has a @value@ conversion cost to convert to the base type, while the candidate (2) has an @unsafe@ conversion from @double@ to @int@,
203which is a more expensive conversion.
204Hence, @bar( x )@ resolves @x@ as type @Math@.
205
206% \begin{cfa}
207% forall(T | @CfaEnum(T)@) void bar(T);
208%
209% bar(a);                                       $\C{// (3), with cost (0, 0, 1, 0, 0, 0, 0, 0)}$
210% \end{cfa}
211% % @Value@ is designed to be less significant than @poly@ to allow function being generic over \CFA enumeration (see ~\ref{c:trait}).
212% 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}.
213% @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.
214
215
216\section{Initialization}
217\CFA extends C's auto-initialization scheme to \CFA enumeration. For an enumeration type with base type T, the initialization scheme is the following:
218\begin{enumerate}
219\item the first enumerator is initialized with @T@'s @zero_t@.
220\item Every other enumerator is initialized with its previous enumerator's value "+1", where "+1" is defined in terms of overloaded operator @?+?(T, one_t)@.
221\end{enumerate}
222
223\begin{cfa}
224struct S { int i; };
225S ?+?( S & s, one_t ) { return s.i++; }
226void ?{}( S & s, zero_t ) { s.i = 0; }
227enum(S) E { A, B, C, D };
228\end{cfa}
229
230The restriction on C's enumeration initializers being constant expression is relaxed on \CFA enumeration.
231Therefore, an enumerator initializer allows function calls like @?+?( S & s, one_t )@ and @?{}( S & s, zero_t )@.
232It is because the values of \CFA enumerators are not stored in the compiled enumeration body but in the @value@ array, which
233allows dynamic initialization.
234
235\section{Subset}
236
237An enumeration's type can be another enumeration.
238\begin{cfa}
239enum( char ) Letter { A = 'A', ..., Z = 'Z' };
240enum( @Letter@ ) Greek { Alph = @A@, Beta = @B@, Gamma = @G@, ..., Zeta = @Z@ }; // alphabet intersection
241\end{cfa}
242Enumeration @Greek@ may have more or less enumerators than @Letter@, but its enumerator values \emph{must} be from @Letter@.
243Therefore, the set of @Greek@ enumerator values in a subset of the @Letter@ enumerator values.
244@Letter@ is type compatible with enumeration @Letter@ because value conversions are inserted whenever @Letter@ is used in place of @Greek@.
245\begin{cfa}
246Letter l = A;                                           $\C{// allowed}$
247Greek g = Alph;                                         $\C{// allowed}$
248l = Alph;                                                       $\C{// allowed, conversion to base type}$
249g = A;                                                          $\C{// {\color{red}disallowed}}$
250void foo( Letter );
251foo( Beta );                                            $\C{// allowed, conversion to base type}$
252void bar( Greek );
253bar( A );                                                       $\C{// {\color{red}disallowed}}$
254\end{cfa}
255Hence, @Letter@ enumerators are not type-compatible with the @Greek@ enumeration, but the reverse is true.
256
257
258\section{Inheritance}
259\label{s:CFAInheritance}
260
261\CFA Plan-9 inheritance may be used with \CFA enumerations, where Plan-9 inheritance is containment inheritance with implicit un-scoping (like a nested unnamed @struct@/@union@ in C).
262Containment is nominative: an enumeration inherits all enumerators from another enumeration by declaring an @inline statement@ in its enumerator lists.
263\begin{cfa}
264enum( char * ) Names { /* $\see{\VRef[Figure]{f:EumeratorTyping}}$ */  };
265enum( char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" };
266enum( char * ) Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" };
267\end{cfa}
268In the preceding example, @Names2@ is defined with five enumerators, three of which are from @Name@ through containment, and two are self-declared.
269@Names3@ inherits all five members from @Names2@ and declares two additional enumerators.
270Hence, enumeration inheritance forms a subset relationship.
271Specifically, the inheritance relationship for the example above is:
272\begin{cfa}
273Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\C{// enum type of Names}$
274\end{cfa}
275
276Inheritance can be nested, and a \CFA enumeration can inline enumerators from more than one \CFA enumeration, forming a tree-like hierarchy.
277However, the uniqueness of the enumeration name applies to enumerators, including those from supertypes, meaning an enumeration cannot name an enumerator with the same label as its subtype's members or inherits
278from multiple enumeration that has overlapping enumerator labels. Consequently, a new type cannot inherit from an enumeration and its supertype or two enumerations with a
279common supertype (the diamond problem) since such would unavoidably introduce duplicate enumerator labels.
280
281The base type must be consistent between subtype and supertype.
282When an enumeration inherits enumerators from another enumeration, it copies the enumerators' @value@ and @label@, even if the @value@ is auto-initialized.
283However, the underlying representation's position is the enumerator's order in the new enumeration.
284\begin{cfa}
285enum() E1 { B };                                                                        $\C{// B}$
286enum() E2 { C, D };                                             $\C{// C D}$
287enum() E3 { inline E1, inline E2, E };  $\C{// {\color{red}[\(_{E1}\)} B {\color{red}]} {\color{red}[\(_{E2}\)} C D {\color{red}]} E}$
288enum() E4 { A, inline E3, F};                   $\C{// A {\color{blue}[\(_{E3}\)} {\color{red}[\(_{E1}\)} B {\color{red}]} {\color{red}[\(_{E2}\)} C D {\color{red}]} E {\color{blue}]} F}$
289\end{cfa}
290In this example, @B@ is at position 0 in @E1@ and @E3@, but position 1 in @E4@ as @A@ takes position 0 in @E4@.
291@C@ is at position 0 in @E2@, 1 in @E3@, and 2 in @E4@.
292@D@ is at position 1 in @E2@, 2 in @E3@, and 3 in @E4@.
293
294A subtype enumeration can be casted, or implicitly converted into its supertype, with a @safe@ cost, called \newterm{enumeration conversion}.
295\begin{cfa}
296enum E2 e2 = C;
297posn( e2 );                     $\C[1.75in]{// 0}$
298enum E3 e3 = e2;        $\C{// Assignment with enumeration conversion E2 to E3}$
299posn( e2 );                     $\C{// 1 cost}$
300void foo( E3 e );
301foo( e2 );                      $\C{// Type compatible with enumeration conversion E2 to E3}$
302posn( (E3)e2 );         $\C{// Explicit cast with enumeration conversion E2 to E3}$
303E3 e31 = B;                     $\C{// No conversion: E3.B}$
304posn( e31 );            $\C{// 0 cost}\CRT$
305\end{cfa}
306The last expression is unambiguous.
307While both @E2.B@ and @E3.B@ are valid candidates, @E2.B@ has an associated safe cost and @E3.B@ needs no conversion (@zero@ cost).
308\CFA selects the lowest cost candidate @E3.B@.
309
310For the given function prototypes, the following calls are valid.
311\begin{cquote}
312\begin{tabular}{ll}
313\begin{cfa}
314void f( Names );
315void g( Names2 );
316void h( Names3 );
317void j( const char * );
318\end{cfa}
319&
320\begin{cfa}
321f( Fred );
322g( Fred );   g( Jill );
323h( Fred );   h( Jill );   h( Sue );
324j( Fred );    j( Jill );    j( Sue );    j( "WILL" );
325\end{cfa}
326\end{tabular}
327\end{cquote}
328Note, 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.
329
330
331\subsection{Offset Calculation}
332
333As discussed in \VRef{s:OpaqueEnum}, \CFA chooses position as a representation of a \CFA enumeration variable.
334When a cast or implicit conversion moves an enumeration from subtype to supertype, the position can be unchanged or increased.
335\CFA determines the position offset with an \newterm{offset calculation} function.
336
337\begin{figure}
338\begin{cfa}
339struct Enumerator;
340struct CFAEnum { vector<variant<CFAEnum, Enumerator>> members; string name; };
341inline static bool operator==(CFAEnum& lhs, CFAEnum& rhs) { return lhs.name == rhs.name; }
342pair<bool, int> calculateEnumOffset(CFAEnum src, CFAEnum dst) {
343        int offset = 0;
344        if ( src == dst ) return make_pair(true, 0);
345        for ( auto v : dst.members ) {
346                if ( holds_alternative<Enumerator>(v) ) {
347                        offset++;
348                } else {
349                        auto m = get<CFAEnum>(v);
350                        if ( m == src ) @return@ make_pair( true, offset );
351                        auto dist = calculateEnumOffset( src, m );
352                        if ( dist.first ) {
353                                @return@ make_pair( true, offset + dist.second );
354                        } else {
355                                offset += dist.second;
356                        }
357                }
358        }
359        @return@ make_pair( false, offset );
360}
361\end{cfa}
362\caption{Compute Offset from Subtype Enumeration to a Supertype}
363\label{s:OffsetSubtypeSuperType}
364\end{figure}
365
366Figure~\ref{s:OffsetSubtypeSuperType} shows an outline of the offset calculation in \CC.
367Structure @CFAEnum@ represents the \CFA enumeration with a vector of variants of @CFAEnum@ or @Enumerator@.
368The algorithm takes two @CFAEnums@ parameters, @src@ and @dst@, with @src@ being the type of expression the conversion applies to, and @dst@ being the type the expression is cast to.
369The algorithm iterates over the members in @dst@ to find @src@.
370If a member is an enumerator of @dst@, the positions of all subsequent members are incremented by one.
371If the current member is @dst@, the function returns true, indicating \emph{found} and the accumulated offset.
372Otherwise, the algorithm recurses into the current @CFAEnum@ @m@ to check if its @src@ is convertible to @m@.
373If @src@ is convertible to the current member @m@, this means @src@ is a subtype-of-subtype of @dst@.
374The offset between @src@ and @dst@ is the sum of the offset of @m@ in @dst@ and the offset of @src@ in @m@.
375If @src@ is not a subtype of @m@, the loop continues but with the offset shifted by the size of @m@.
376If the loop ends, than @src@ is not convertible to @dst@, and false is returned.
377
378
379\section{Control Structures}
380
381Enumerators are used in various contexts.
382In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution).
383However, in some contexts, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect.
384A programmer's intuition assumes an implicit conversion to position in these contexts.
385
386For 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.
387(For this discussion, ignore the fact that @case@ requires a compile-time constant.)
388\begin{cfa}[belowskip=0pt]
389enum Count { First, Second, Third, Fourth };
390Count e;
391\end{cfa}
392\begin{cquote}
393\setlength{\tabcolsep}{15pt}
394\noindent
395\begin{tabular}{@{}ll@{}}
396\begin{cfa}[aboveskip=0pt]
397
398choose( e ) {
399        case @First@: ...;
400        case @Second@: ...;
401        case @Third@: ...;
402        case @Fourth@: ...;
403}
404\end{cfa}
405&
406\begin{cfa}[aboveskip=0pt]
407// rewrite
408choose( @value@( e ) ) {
409        case @value@( First ): ...;
410        case @value@( Second ): ...;
411        case @value@( Third ): ...;
412        case @value@( Fourth ): ...;
413}
414\end{cfa}
415\end{tabular}
416\end{cquote}
417Here, 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.
418However, this implementation is fragile, \eg if the enumeration is changed to:
419\begin{cfa}
420enum Count { First, Second, Third @= First@, Fourth };
421\end{cfa}
422making @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicate @case@ clauses.
423To better match with programmer intuition, \CFA toggles between value and position semantics depending on the language context.
424For conditional clauses and switch statements, \CFA uses the robust position implementation.
425\begin{cfa}
426if ( @posn@( e ) < posn( Third ) ) ...
427choose( @posn@( e ) ) {
428        case @posn@( First ): ...;
429        case @posn@( Second ): ...;
430        case @posn@( Third ): ...;
431        case @posn@( Fourth ): ...;
432}
433\end{cfa}
434
435\CFA provides a special form of for-control for enumerating through an enumeration, where the range is a type.
436\begin{cfa}
437for ( cx; @Count@ ) { sout | cx | nonl; } sout | nl;
438for ( cx; ~= Count ) { sout | cx | nonl; } sout | nl;
439for ( cx; -~= Count ) { sout | cx | nonl; } sout | nl;
440First Second Third Fourth
441First Second Third Fourth
442Fourth Third Second First
443\end{cfa}
444The 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.
445The prefix @+~=@ or @-~=@ iterate forward or backward through the inclusive enumeration range, where no prefix defaults to @+~=@.
446
447C has an idiom for @if@ and loop predicates of comparing the predicate result ``not equal to 0''.
448\begin{cfa}
449if ( x + y /* != 0 */  ) ...
450while ( p /* != 0 */  ) ...
451\end{cfa}
452This idiom extends to enumerations because there is a boolean conversion regarding the enumeration value if and only if such a conversion is available.
453For example, such a conversion exists for all numerical types (integral and floating-point).
454It is possible to explicitly extend this idiom to any typed enumeration by overloading the @!=@ operator.
455\begin{cfa}
456bool ?!=?( Name n, zero_t ) { return n != Fred; }
457Name n = Mary;
458if ( n ) ... // result is true
459\end{cfa}
460Specialize meanings are also possible.
461\begin{cfa}
462enum(int) ErrorCode { Normal = 0, Slow = 1, Overheat = 1000, OutOfResource = 1001 };
463bool ?!=?( ErrorCode ec, zero_t ) { return ec >= Overheat; }
464ErrorCode code = ...;
465if ( code ) { problem(); }
466\end{cfa}
467
468
469\section{Dimension}
470
471\VRef{s:EnumeratorTyping} introduces the harmonizing problem between an enumeration and secondary information.
472When possible, using a typed enumeration for the secondary information is the best approach.
473However, there are times when combining these two types is not possible.
474For example, the secondary information might precede the enumeration and/or its type is needed directly to declare parameters of functions.
475In these cases, having secondary arrays of the enumeration size are necessary.
476
477To support some level of harmonizing in these cases, an array dimension can be defined using an enumerator type, and the enumerators used as subscripts.
478\begin{cfa}
479enum E1 { A, B, C, N }; // possibly predefined
480enum(int) E2 { A, B, C };
481float H1[N] = { [A] :$\footnotemark$ 3.4, [B] : 7.1, [C] : 0.01 }; // C
482float H2[@E2@] = { [A] : 3.4, [B] : 7.1, [C] : 0.01 }; // CFA
483\end{cfa}
484\footnotetext{C uses symbol \lstinline{'='} for designator initialization, but \CFA changes it to \lstinline{':'} because of problems with tuple syntax.}
485This approach is also necessary for a predefined typed enumeration (unchangeable) when additional secondary information needs to be added.
486The 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.
487This behaviour can be reverted by explicit overloading:
488\begin{cfa}
489float ?[?]( float * arr, E2 index ) { return arr[ value( index ) ]; }
490\end{cfa}
491While enumerator labels @A@, @B@ and @C@ are being defined twice in different enumerations, they are unambiguous within the context.
492Designators in @H1@ are unambiguous becasue @E2@ has a @value@ cost to @int@, which is more expensive than @safe@ cost from C-Enum @E1@ to @int@.
493Designators in @H2@ are resolved as @E2@ because when a \CFA enumeration type is being used as an array dimension, \CFA adds the enumeration type to the initializer's resolution context.
494
495
496\section{I/O}
497
498As seen in multiple examples, \CFA enumerations can be printed and the default property printed is the enumerator's label, which is similar in other programming languages.
499However, very few programming languages provide a mechanism to read in enumerator values.
500Even the @boolean@ type in many languages does not have a mechanism for input using the enumerators @true@ or @false@.
501\VRef[Figure]{f:EnumerationI/O} show \CFA enumeration input based on the enumerator labels.
502When the enumerator labels are packed together in the input stream, the input algorithm scans for the longest matching string.
503For 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 string constants can be quoted or unquoted.
504
505\begin{figure}
506\begin{cquote}
507\setlength{\tabcolsep}{15pt}
508\begin{tabular}{@{}ll@{}}
509\begin{cfa}
510int main() {
511        enum(int ) E { BBB = 3, AAA, AA, AB, B };
512        E e;
513
514        try {
515                for () {
516                        try {
517                                @sin | e@;
518                        } catch( missing_data * ) {
519                                sout | "missing data";
520                                continue; // try again
521                        }
522                        sout | e | "= " | value( e );
523                }
524        } catch( end_of_file ) {}
525}
526\end{cfa}
527&
528\begin{cfa}
529$\rm input$
530BBBABAAAAB
531BBB AAA AA AB B
532
533$\rm output$
534BBB = 3
535AB = 6
536AAA = 4
537AB = 6
538BBB = 3
539AAA = 4
540AA = 5
541AB = 6
542B = 7
543
544\end{cfa}
545\end{tabular}
546\end{cquote}
547\caption{Enumeration I/O}
548\label{f:EnumerationI/O}
549\end{figure}
550
551
552\section{Planet Example}
553
554\VRef[Figure]{f:PlanetExample} shows an archetypal enumeration example illustrating most of the \CFA enumeration features.
555@Planet@ is an enumeration of type @MR@.
556Each planet enumerator is initialized to a specific mass/radius, @MR@, value.
557The unnamed enumeration provides the gravitational-constant enumerator @G@.
558Function @surfaceGravity@ uses the @with@ clause to remove @p@ qualification from fields @mass@ and @radius@.
559The 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@.
560The resulting random orbital-body is used in a @choose@ statement.
561The enumerators in the @case@ clause use the enumerator position for testing.
562The prints use @label@ to print an enumerator's name.
563Finally, a loop enumerates through the planets computing the weight on each planet for a given Earth mass.
564The print statement does an equality comparison with an enumeration variable and enumerator (@p == MOON@).
565
566\begin{figure}
567\small
568\begin{cfa}
569struct MR { double mass, radius; };                     $\C[3.5in]{// planet definition}$
570enum( @MR@ ) Planet {                                           $\C{// typed enumeration}$
571        //                      mass (kg)   radius (km)
572        MERCURY = { 0.330_E24, 2.4397_E6 },
573        VENUS      = { 4.869_E24, 6.0518_E6 },
574        EARTH       = { 5.976_E24, 6.3781_E6 },
575        MOON        = { 7.346_E22, 1.7380_E6 }, $\C{// not a planet}$
576        MARS         = { 0.642_E24, 3.3972_E6 },
577        JUPITER    = { 1898._E24, 71.492_E6 },
578        SATURN     = { 568.8_E24, 60.268_E6 },
579        URANUS    = { 86.86_E24, 25.559_E6 },
580        NEPTUNE  = { 102.4_E24, 24.746_E6 },
581        PLUTO       = { 1.303_E22, 1.1880_E6 }, $\C{// not a planet}$
582};
583enum( double ) { G = 6.6743_E-11 };                     $\C{// universal gravitational constant (m3 kg-1 s-2)}$
584static double surfaceGravity( Planet p ) @with( p )@ {
585        return G * mass / ( radius @\@ 2 );             $\C{// no qualification, exponentiation}$
586}
587static double surfaceWeight( Planet p, double otherMass ) {
588        return otherMass * surfaceGravity( p );
589}
590int main( int argc, char * argv[] ) {
591        if ( argc != 2 ) @exit@ | "Usage: " | argv[0] | "earth-weight";  // terminate program
592        double earthWeight = convert( argv[1] );
593        double earthMass = earthWeight / surfaceGravity( EARTH );
594        Planet rp = @fromInt@( prng( @countof@( Planet ) ) ); $\C{// select random orbiting body}$
595        @choose( rp )@ {                                                $\C{// implicit breaks}$
596          case MERCURY, VENUS, EARTH, MARS:
597                sout | @rp@ | "is a rocky planet";
598          case JUPITER, SATURN, URANUS, NEPTUNE:
599                sout | rp | "is a gas-giant planet";
600          default:
601                sout | rp | "is not a planet";
602        }
603        for ( @p; Planet@ ) {                                   $\C{// enumerate}\CRT$
604                sout | "Your weight on" | ( @p == MOON@ ? "the" : " " ) | p
605                           | "is" | wd( 1,1,  surfaceWeight( p, earthMass ) ) | "kg";
606        }
607}
608$\$$ planet 100
609JUPITER is a gas-giant planet
610Your weight on MERCURY is 37.7 kg
611Your weight on VENUS is 90.5 kg
612Your weight on EARTH is 100.0 kg
613Your weight on the MOON is 16.6 kg
614Your weight on MARS is 37.9 kg
615Your weight on JUPITER is 252.8 kg
616Your weight on SATURN is 106.6 kg
617Your weight on URANUS is 90.5 kg
618Your weight on NEPTUNE is 113.8 kg
619Your weight on PLUTO is 6.3 kg
620\end{cfa}
621\caption{Planet Example}
622\label{f:PlanetExample}
623\end{figure}
Note: See TracBrowser for help on using the repository browser.