source: doc/theses/jiada_liang_MMath/CFAenum.tex @ 4da9142

Last change on this file since 4da9142 was 4da9142, checked in by Peter A. Buhr <pabuhr@…>, 4 weeks ago

more proofreading on enumerations

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