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

Last change on this file since acab1bd was acab1bd, checked in by JiadaL <j82liang@…>, 12 hours ago

rephrase enum initialization

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