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

Last change on this file since c494b84 was d93b813, checked in by JiadaL <j82liang@…>, 5 weeks ago

Add separate compilation discussion

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