source: doc/theses/jiada_liang_MMath/CFAenum.tex @ 35897fb

Last change on this file since 35897fb was 35897fb, checked in by JiadaL <j82liang@…>, 4 weeks ago

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

  • Property mode set to 100644
File size: 17.0 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.
6Any enumeration extensions must be intuitive to C programmers both in syntax and semantics.
7The following sections detail all of my new contributions to enumerations in \CFA.
8
9
10\section{Aliasing}
11
12C already provides @const@-style aliasing using the unnamed enumerator \see{\VRef{s:TypeName}}, even if the name @enum@ is misleading (@const@ would be better).
13Given the existence of this form, it is straightforward to extend it with types other than integers.
14\begin{cfa}
15enum E { Size = 20u, PI = 3.14159L, Jack = L"John" };
16\end{cfa}
17which matches with @const@ aliasing in other programming languages.
18Here, the type of the enumerator is the type of the initialization constant, \eg @typeof(20u)@ for @Size@ implies @unsigned int@.
19Auto-initialization is restricted to the case where all constants are @int@, matching with C.
20As seen in \VRef{s:EnumeratorTyping}, this feature is just a shorthand for multiple typed-enumeration declarations.
21
22
23\section{Enumerator Unscoping}
24\label{s:EnumeratorUnscoping}
25
26In C, unscoped enumerators presents a \newterm{naming problem} when multiple enumeration types appear in the same scope with duplicate enumerator names.
27There is no mechanism in C to resolve these naming conflicts other than renaming one of the duplicates, which may be impossible.
28
29The \CFA type-system allows extensive overloading, including enumerators.
30Furthermore, \CFA uses the left-hand of assignment in type resolution to pinpoint the best overloaded name.
31Finally, qualification and casting are provided to disambiguate any ambiguous situations.
32\begin{cfa}
33enum E1 { First, Second, Third, Fourth };
34enum E2 { @Fourth@, @Third@, @Second@, @First@ }; $\C{// same enumerator names}$
35E1 p() { return Third; }                                $\C{// correctly resolved duplicate names}$
36E2 p() { return Fourth; }
37void foo() {
38        E1 e1 = First;   E2 e2 = First;         $\C{// initialization}$
39        e1 = Second;   e2 = Second;                     $\C{// assignment}$
40        e1 = p();   e2 = p();                           $\C{// function call}$
41        int i = @E1.@First + @E2.@First;        $\C{// disambiguate with qualification}$
42        int j = @(E1)@First + @(E2)@First;      $\C{// disambiguate with cast}$
43}
44\end{cfa}
45\CFA overloading allows programmers to use the most meaningful names without fear of name clashes from include files.
46In most cases, the type system implicitly disambiguates, otherwise the programmer explicitly disambiguates using qualification or casting.
47
48
49\section{Enumerator Scoping}
50
51An enumeration can be scoped, using @'!'@, so the enumerator constants are not projected into the enclosing scope.
52\begin{cfa}
53enum Week @!@ { Mon, Tue, Wed, Thu = 10, Fri, Sat, Sun };
54enum RGB @!@ { Red, Green, Blue };
55\end{cfa}
56Now the enumerators \emph{must} be qualified with the associated enumeration.
57\begin{cfa}
58Week week = @Week.@Mon;
59week = @Week.@Sat;
60RGB rgb = @RGB.@Red;
61rgb = @RGB.@Blue;
62\end{cfa}
63It 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}).
64\begin{cfa}
65with ( @Week@, @RGB@ ) {                        $\C{// type names}$
66         week = @Sun@;                                  $\C{// no qualification}$
67         rgb = @Green@;
68}
69\end{cfa}
70As in Section~\ref{s:EnumeratorUnscoping}, opening multiple scoped enumerations in a @with@ can result in duplicate enumeration names, but \CFA implicit type resolution and explicit qualification/casting handles ambiguities.
71
72
73\section{Enumeration Pseudo-functions}
74
75Pseudo-functions are function-like operators that do not result in any run-time computations, \ie like @sizeof@, @alignof@, @typeof@.
76A pseudo-function call is often substituted with information extracted from the compilation symbol-table, like storage size or alignment associated with the underlying architecture.
77
78The attributes of an enumerator are accessed by pseudo-functions @posE@, @valueE@, and @labelE@.
79\begin{cfa}
80int jane_pos = @posE@( Names.Jane );   $\C{// 2}$
81char * jane_value = @valueE@( Names.Jane ); $\C{// "JANE"}$
82char * jane_label = @labelE@( Names.Jane ); $\C{// "Jane"}$
83sout | posE( Names.Jane) | labelE( Names.Jane ) | valueE( Names.Jane );
84\end{cfa}
85Note the ability to print all of an enumerator's properties.
86
87
88\section{Enumerator Typing}
89\label{s:EnumeratorTyping}
90
91\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.
92Figure~\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.
93Note, the synonyms @Liz@ and @Beth@ in the last declaration.
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
96C has an implicit type conversion from an enumerator to its base type @int@.
97Correspondingly, \CFA has an implicit (safe) conversion from a typed enumerator to its base type.
98\begin{cfa}
99char currency = Dollar;
100string fred = Fred;                                             $\C{// implicit conversion from char * to \CFA string type}$
101Person student = Beth;
102\end{cfa}
103
104% \begin{cfa}
105% struct S { int i, j; };
106% enum( S ) s { A = { 3,  4 }, B = { 7,  8 } };
107% enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$'  };
108% enum( @double@ ) Planet { Venus = 4.87, Earth = 5.97, Mars = 0.642  }; // mass
109% enum( @char *@ ) Colour { Red = "red", Green = "green", Blue = "blue"  };
110% enum( @Currency@ ) Europe { Euro = '$\texteuro$', Pound = '$\textsterling$' }; // intersection
111% \end{cfa}
112
113\begin{figure}
114\begin{cfa}
115// integral
116        enum( @char@ ) Currency { Dollar = '$\textdollar$', Cent = '$\textcent$', Yen = '$\textyen$', Pound = '$\textsterling$', Euro = 'E' };
117        enum( @signed char@ ) srgb { Red = -1, Green = 0, Blue = 1 };
118        enum( @long long int@ ) BigNum { X = 123_456_789_012_345,  Y = 345_012_789_456_123 };
119// non-integral
120        enum( @double@ ) Math { PI_2 = 1.570796, PI = 3.141597, E = 2.718282 };
121        enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i };
122// pointer
123        enum( @const char *@ ) Name { Fred = "FRED", Mary = "MARY", Jane = "JANE" };
124        int i, j, k;
125        enum( @int *@ ) ptr { I = &i,  J = &j,  K = &k };
126        enum( @int &@ ) ref { I = i,   J = j,   K = k };
127// tuple
128        enum( @[int, int]@ ) { T = [ 1, 2 ] }; $\C{// new \CFA type}$
129// function
130        void f() {...}   void g() {...}
131        enum( @void (*)()@ ) funs { F = f,  G = g };
132// aggregate
133        struct Person { char * name; int age, height; };
134@***@enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz,
135                                                                        Jon = { "JONATHAN", 35, 190 } };
136\end{cfa}
137\caption{Enumerator Typing}
138\label{f:EumeratorTyping}
139\end{figure}
140
141An advantage of the typed enumerations is eliminating the \emph{harmonizing} problem between an enumeration and companion data \see{\VRef{s:Usage}}:
142\begin{cfa}
143enum( char * ) integral_types {
144        chr = "char", schar = "signed char", uschar = "unsigned char",
145        sshort = "signed short int", ushort = "unsigned short int",
146        sint = "signed int", usint = "unsigned int",
147        ...
148};
149\end{cfa}
150Note, 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.
151
152While the enumeration type can be any C aggregate, the aggregate's \CFA constructors are not used to evaluate an enumerator's value.
153\CFA enumeration constants are compile-time values (static);
154calling constructors happens at runtime (dynamic).
155
156
157\section{Enumeration Inheritance}
158
159\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).
160\begin{cfa}
161enum( char * ) Names { /* as above */ };
162enum( char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" };
163@***@enum /* inferred */ Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" };
164\end{cfa}
165Enumeration @Name2@ inherits all the enumerators and their values from enumeration @Names@ by containment, and a @Names@ enumeration is a subtype of enumeration @Name2@.
166Note, enumerators must be unique in inheritance but enumerator values may be repeated.
167
168The enumeration type for the inheriting type must be the same as the inherited type;
169hence the enumeration type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for @Name3@.
170% When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important.
171Specifically, the inheritance relationship for @Names@ is:
172\begin{cfa}
173Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\(\subset\)$ const char * $\C{// enum type of Names}$
174\end{cfa}
175For the given function prototypes, the following calls are valid.
176\begin{cquote}
177\begin{tabular}{ll}
178\begin{cfa}
179void f( Names );
180void g( Names2 );
181void h( Names3 );
182void j( const char * );
183\end{cfa}
184&
185\begin{cfa}
186f( Fred );
187g( Fred );   g( Jill );
188h( Fred );   h( Jill );   h( Sue );
189 j( Fred );    j( Jill );    j( Sue );    j( "WILL" );
190\end{cfa}
191\end{tabular}
192\end{cquote}
193Note, 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.
194
195
196\section{Enumerator Control Structures}
197
198Enumerators can be used in multiple contexts.
199In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution).
200However, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect in some contexts.
201In these contexts, a programmer's initition assumes an implicit conversion to postion.
202
203For 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.
204\begin{cquote}
205\begin{cfa}
206enum Count { First, Second, Third, Fourth };
207Count e;
208\end{cfa}
209\begin{tabular}{ll}
210\begin{cfa}
211
212choose( e ) {
213        case @First@: ...;
214        case @Second@: ...;
215        case @Third@: ...;
216        case @Fourth@: ...;
217}
218\end{cfa}
219&
220\begin{cfa}
221// rewrite
222choose( @value@( e ) ) {
223        case @value@( First ): ...;
224        case @value@( Second ): ...;
225        case @value@( Third ): ...;
226        case @value@( Fourth ): ...;
227}
228\end{cfa}
229\end{tabular}
230\end{cquote}
231Here, 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.
232However, this implementation is fragile, \eg if the enumeration is changed to:
233\begin{cfa}
234enum Count { First, Second, Third @= First@, Fourth };
235\end{cfa}
236which make @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicase @case@ clauses.
237To better match with programmer intuition, \CFA toggles between value and position semantics depneding on the language context.
238For conditional clauses and switch statments, \CFA uses the robust position implementation.
239\begin{cfa}
240choose( @position@( e ) ) {
241        case @position@( First ): ...;
242        case @position@( Second ): ...;
243        case @position@( Third ): ...;
244        case @position@( Fourth ): ...;
245}
246\end{cfa}
247
248\begin{cfa}
249Count variable_a = First, variable_b = Second, variable_c = Third, variable_d = Fourth;
250p(variable_a); // 0
251p(variable_b); // 1
252p(variable_c); // "Third"
253p(variable_d); // 3
254\end{cfa}
255
256
257@if@ statement
258
259@switch@ statement
260
261looping statements
262
263
264\section{Planet Example}
265
266\VRef[Figure]{f:PlanetExample} shows an archetypal enumeration example illustrating most of the \CFA enumeration features.
267@Planet@ is an enumeration of type @MR@.
268Each of the planet enumerators is initialized to a specific mass/radius, @MR@, value.
269The unnamed enumeration provides the gravitational-constant enumerator @G@.
270Function @surfaceGravity@ uses the @with@ clause to remove @p@ qualification from fields @mass@ and @radius@.
271The program main uses @SizeE@ to obtain the number of enumerators in @Planet@, and safely converts the random value into a @Planet@ enumerator.
272The resulting random orbital body is used in a @choose@ statement.
273The enumerators in the @case@ clause use position for testing.
274The prints use @labelE@ to print the enumerators label.
275Finally, a loop iterates through the planets computing the weight on each planet for a given earth weight.
276The print statement does an equality comparison with an enumeration variable and enumerator.
277
278\begin{figure}
279\small
280\begin{cfa}
281struct MR { double mass, radius; };
282enum( @MR@ ) Planet {
283        //                      mass (kg)   radius (km)
284        MERCURY = { 0.330_E24, 2.4397_E6 },
285        VENUS      = { 4.869_E24, 6.0518_E6 },
286        EARTH       = { 5.976_E24, 6.3781_E6 },
287        MOON        = { 7.346_E22, 1.7380_E6 }, $\C{// not a planet}$
288        MARS         = { 0.642_E24, 3.3972_E6 },
289        JUPITER    = { 1898._E24, 71.492_E6 },
290        SATURN     = { 568.8_E24, 60.268_E6 },
291        URANUS    = { 86.86_E24, 25.559_E6 },
292        NEPTUNE  = { 102.4_E24, 24.746_E6 },
293};
294enum( double ) { G = 6.6743_E-11 }; $\C{// universal gravitational constant (m3 kg-1 s-2)}$
295static double surfaceGravity( Planet p ) @with( p )@ {
296        return G * mass / ( radius \ 2u ); $\C{// exponentiation}$
297}
298static double surfaceWeight( Planet p, double otherMass ) {
299        return otherMass * surfaceGravity( p );
300}
301int main( int argc, char * argv[] ) {
302        if ( argc != 2 ) exit | "Usage: " | argv[0] | "earth-weight";
303        double earthWeight = convert( argv[1] );
304        double mass = earthWeight / surfaceGravity( EARTH );
305
306        Planet p = @fromInt@( prng( @SizeE@(Planet) ) ); $\C{// select a random orbiting body}$
307        @choose( p )@ {
308          case MERCURY, VENUS, EARTH, MARS:
309                sout | @labelE( p )@ | "is a rocky planet";
310          @case JUPITER, SATURN, URANUS, NEPTUNE:@
311                sout | labelE( p ) | "is a gas-giant planet";
312          default:
313                sout | labelE( p ) | "is not a planet";
314        }
315        for ( @p; Planet@ ) {
316                sout | "Your weight on" | (@p == MOON@ ? "the" : "") | labelE(p)
317                           | "is" | wd(1,1, surfaceWeight( p, mass )) | "kg";
318        }
319}
320$\$$ planet 100
321JUPITER is a gas-giant planet
322Your weight on MERCURY is 37.7 kg
323Your weight on VENUS is 90.5 kg
324Your weight on EARTH is 100.0 kg
325Your weight on the MOON is 16.6 kg
326Your weight on MARS is 37.9 kg
327Your weight on JUPITER is 252.8 kg
328Your weight on SATURN is 106.6 kg
329Your weight on URANUS is 90.5 kg
330Your weight on NEPTUNE is 113.8 kg
331\end{cfa}
332\caption{Planet Example}
333\label{f:PlanetExample}
334\end{figure}
335
336\section{Enum Trait}
337A typed enum comes with traits capture enumeration charastics and helper functions.
338
339\begin{cfa}
340forall(E) trait Bounded {
341        E lowerBound();
342        E upperBound();
343};
344\end{cfa}
345\CFA enums satisfy Bounded trait thanks to the compiler implementing lowerBound() and upperBound(), with
346lowerBound() returning the first enumerator and upperBound() return the last.
347
348\begin{cfa}
349Workday day1 = lowerBound(); // Monday
350Planet lastPlanet = upperBound(); // NEPTUNE
351\end{cfa}
352
353Because lowerBound() and upperBound() are overloaded with return types only, calling either functions
354in a null context cause type ambiguity if than one type implementing Bounded traits, including typed enumerations.
355\begin{cfa}
356Workday day1 = lowerBound(); // Okay because rhs hints lowerBound() to return a Workday
357void foo(Planet p);
358foo( upperBound() ); Okay because foo's parameter give type hint
359// lowerBound(); // Error because both Planet and Workday implements Bounded
360\end{cfa}
361
362\begin{cfa}
363forall(E | Bounded(E)) trait Serial {
364        unsigned fromInstance(E e);
365        E fromInt(unsigned i);
366        E succ(E e);
367        E pred(E e);
368};
369\end{cfa}
370A Serial type can be mapped to a sequnce of integer. For enum types, fromInstance(E e) is equivalent to
371posE(E e). Enumerations implement fromInt(), succ(), and pred() with bound() check.
372For an enum declares N enumerators, fromInt(i) returns the ith enumerator of type E if $0 \leq i < N$.
373If e is the i-th enumerator, succ(e) returns the i+1-th enumerator if $e != upperBound()$ and pred(e) 
374returns the i-1-th enumerator $e != lowerBound()$. \CFA compile gives an error if bound check fails.
375
376\begin{cfa}
377forall(E, T) trait TypedEnum {
378        T valueE(E e);
379        char * labelE(E e);
380        unsigned int posE(E e);
381};
382\end{cfa}
383
384The TypedEnum trait capture three basic attributes of type enums. TypedEnum asserts two types E and T, with T being the base type of enumeration E.
385With an assertion on TypedEnum, we can implement functions for all type enums.
386
387\begin{cfa}
388forall( E, T | TypeEnum(E, T))
389void printEnum(E e) {
390        sout | "Enum "| labelE(e);
391}
392printEunm(MARS);
393\end{cfa}
394
395@<enum.hfa>@ overwrites comparison operators for type enums.
396\begin{cfa}
397forall(E, T| TypedEnum(E, T)) {
398        // comparison
399        int ?==?(E l, E r);
400        int ?!=?(E l, E r);
401        int ?!=?(E l, zero_t);
402        int ?<?(E l, E r);
403        int ?<=?(E l, E r);
404        int ?>?(E l, E r);
405        int ?>=?(E l, E r);
406}
407\end{cfa}
408These overloaded operators are not defined if the file is not included.
409In this case, the compiler converts an enumerator to its value, and applies the operators
410if they are defined for the value type T.
411
412\begin{cfa}
413// if not include <enum.hfa>
414enum(int) Fruits {
415        APPLE = 2, BANANA=1, CHERRY=2
416};
417APPLE == CHERRY; // True because they have the same Value
418#include <enum.hfa>
419APPLE == CHERRY; // False because they are different enumerator
420\end{cfa}
Note: See TracBrowser for help on using the repository browser.