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

Last change on this file since d69f7114 was d69f7114, checked in by Peter A. Buhr <pabuhr@…>, 2 months ago

proofread section Enumeration Trait, and a few other wording changes

  • Property mode set to 100644
File size: 19.5 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{Enumerator Opaque Type}
158
159\CFA provides a special opaque enumeration type, where the internal representation is chosen by the compiler and only equality operations are available.
160\begin{cfa}
161enum@()@ Planets { MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE };
162\end{cfa}
163
164
165\section{Enumeration Inheritance}
166
167\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).
168\begin{cfa}
169enum( char * ) Names { /* as above */ };
170enum( char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" };
171@***@enum /* inferred */ Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" };
172\end{cfa}
173Enumeration @Name2@ inherits all the enumerators and their values from enumeration @Names@ by containment, and a @Names@ enumeration is a subtype of enumeration @Name2@.
174Note, enumerators must be unique in inheritance but enumerator values may be repeated.
175
176The enumeration type for the inheriting type must be the same as the inherited type;
177hence the enumeration type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for @Name3@.
178% When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important.
179Specifically, the inheritance relationship for @Names@ is:
180\begin{cfa}
181Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\(\subset\)$ const char * $\C{// enum type of Names}$
182\end{cfa}
183For the given function prototypes, the following calls are valid.
184\begin{cquote}
185\begin{tabular}{ll}
186\begin{cfa}
187void f( Names );
188void g( Names2 );
189void h( Names3 );
190void j( const char * );
191\end{cfa}
192&
193\begin{cfa}
194f( Fred );
195g( Fred );   g( Jill );
196h( Fred );   h( Jill );   h( Sue );
197 j( Fred );    j( Jill );    j( Sue );    j( "WILL" );
198\end{cfa}
199\end{tabular}
200\end{cquote}
201Note, 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.
202
203
204\section{Enumerator Control Structures}
205
206Enumerators can be used in multiple contexts.
207In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution).
208However, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect in some contexts.
209In these contexts, a programmer's initition assumes an implicit conversion to postion.
210
211For 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.
212\begin{cquote}
213\begin{cfa}
214enum Count { First, Second, Third, Fourth };
215Count e;
216\end{cfa}
217\begin{tabular}{ll}
218\begin{cfa}
219
220choose( e ) {
221        case @First@: ...;
222        case @Second@: ...;
223        case @Third@: ...;
224        case @Fourth@: ...;
225}
226\end{cfa}
227&
228\begin{cfa}
229// rewrite
230choose( @value@( e ) ) {
231        case @value@( First ): ...;
232        case @value@( Second ): ...;
233        case @value@( Third ): ...;
234        case @value@( Fourth ): ...;
235}
236\end{cfa}
237\end{tabular}
238\end{cquote}
239Here, 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.
240However, this implementation is fragile, \eg if the enumeration is changed to:
241\begin{cfa}
242enum Count { First, Second, Third @= First@, Fourth };
243\end{cfa}
244which make @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicase @case@ clauses.
245To better match with programmer intuition, \CFA toggles between value and position semantics depneding on the language context.
246For conditional clauses and switch statments, \CFA uses the robust position implementation.
247\begin{cfa}
248choose( @position@( e ) ) {
249        case @position@( First ): ...;
250        case @position@( Second ): ...;
251        case @position@( Third ): ...;
252        case @position@( Fourth ): ...;
253}
254\end{cfa}
255
256\begin{cfa}
257Count variable_a = First, variable_b = Second, variable_c = Third, variable_d = Fourth;
258p(variable_a); // 0
259p(variable_b); // 1
260p(variable_c); // "Third"
261p(variable_d); // 3
262\end{cfa}
263
264
265@if@ statement
266
267@switch@ statement
268
269looping statements
270
271
272\section{Enumeration Trait}
273
274The header file \lstinline[deletekeywords=enum]{<enum.hfa>} defines the set of traits containing operators and helper functions for @enum@.
275A \CFA enumeration satisfies all of these traits allowing it to interact with runtime features in \CFA.
276Each trait is discussed in detail.
277
278The trait @Bounded@:
279\begin{cfa}
280forall( E ) trait Bounded {
281        E first();
282        E last();
283};
284\end{cfa}
285defines the bounds of the enumeration, where @first()@ returns the first enumerator and @last()@ returns the last, \eg:
286\begin{cfa}
287Workday day = first();                                  $\C{// Mon}$
288Planet outermost = last();                              $\C{// NEPTUNE}$
289\end{cfa}
290@first()@ and @last()@ are overloaded with return types only, so in the example, the enumeration type is found on the left-hand side of the assignment.
291Calling either functions without a context results in a type ambiguity, except in the rare case where the type environment has only one enumeration.
292\begin{cfa}
293@first();@                                                              $\C{// ambiguous Workday and Planet implement Bounded}$
294sout | @last()@;
295Workday day = first();                                  $\C{// day provides type Workday}$
296void foo( Planet p );
297foo( last() );                                                  $\C{// parameter provides type Planet}$
298\end{cfa}
299
300The trait @Serial@:
301\begin{cfa}
302forall( E | Bounded( E ) ) trait Serial {
303        unsigned fromInstance( E e );
304        E fromInt( unsigned int posn );
305        E succ( E e );
306        E pred( E e );
307};
308\end{cfa}
309is a @Bounded@ trait, where elements can be mapped to an integer sequence.
310A type @T@ matching @Serial@ can project to an unsigned @int@ type, \ie an instance of type T has a corresponding integer value.
311%However, the inverse may not be possible, and possible requires a bound check.
312The mapping from a serial type to integer is defined by @fromInstance@, which returns the enumerator's position.
313The inverse operation is @fromInt@, which performs a bound check using @first()@ and @last()@ before casting the integer into an enumerator.
314Specifically, for enumerator @E@ declaring $N$ enumerators, @fromInt( i )@ returns the $i-1_{th}$ enumerator, if $0 \leq i < N$, or raises the exception @enumBound@.
315
316The @Serial@ trait also requires interface functions @succ( E e )@ and @pred( E e )@ be implemented for a serial type, which imply the enumeration positions are consecutive and ordinal.
317Specifically, if @e@ is the $i_{th}$ enumerator, @succ( e )@ returns the $i+1_{th}$ enumerator when $e \ne last()$, and @pred( e )@ returns the $i-1_{th}$ enumerator when $e \ne first()$.
318The exception @enumRange@ is raised if the result of either operation is outside the range of type @E@.
319
320The trait @TypedEnum@:
321\begin{cfa}
322forall( E, T ) trait TypedEnum {
323        T valueE( E e );
324        char * labelE( E e );
325        unsigned int posE( E e );
326};
327\end{cfa}
328captures three basic attributes of an enumeration type: value, label, and position.
329@TypedEnum@ asserts two types @E@ and @T@, with @T@ being the base type of the enumeration @E@, \eg @enum( T ) E { ... };@.
330Implementing general functions across all enumeration types is possible by asserting @TypeEnum( E, T )@, \eg:
331\begin{cfa}
332forall( E, T | TypeEnum( E, T ) )
333void printEnum( E e ) {
334        sout | "Enum "| labelE( e );
335}
336printEunm( MARS );
337\end{cfa}
338
339Finally, there is an associated trait defining comparison operators among enumerators.
340\begin{cfa}
341forall( E, T | TypedEnum( E, T ) ) {
342        // comparison
343        int ?==?( E l, E r );           $\C{// true if l and r are same enumerators}$
344        int ?!=?( E l, E r );           $\C{// true if l and r are different enumerators}$
345        int ?!=?( E l, zero_t );        $\C{// true if l is not the first enumerator}$
346        int ?<?( E l, E r );            $\C{// true if l is an enumerator before r}$
347        int ?<=?( E l, E r );           $\C{// true if l before or the same as r}$
348        int ?>?( E l, E r );            $\C{// true if l is an enumerator after r}$
349        int ?>=?( E l, E r );           $\C{// true if l after or the same as r}$         
350}
351\end{cfa}
352Note, the overloaded operators are defined only when the header @<enum.hfa>@ is included.
353If not, the compiler converts an enumerator to its value, and applies the operators defined for the value type @E@, \eg:
354\begin{cfa}
355// if not include <enum.hfa>
356enum( int ) Fruits { APPLE = 2, BANANA = 10, CHERRY = 2 };
357APPLE == CHERRY; // true because valueE( APPLE ) == valueE( CHERRY )
358
359#include <enum.hfa>
360APPLE == CHERRY; // false because posE( APPLE ) != posE( CHERRY )
361\end{cfa}
362An enumerator returns its @position@ by default.
363In particular, @printf( ... )@ from @<stdio.h>@ functions provides no context to its parameter type, so it prints @position@.
364On the other hand, the pipeline operator @?|?( ostream os, E enumType )@ provides type context for type @E@, and \CFA has overwritten this operator to print the enumeration @value@ over @position@.
365\begin{cfa}
366printf( "Position of BANANA is \%d", BANANA ); // Position of BANANA is 1
367sout | "Value of BANANA is " | BANANA; // Value of BANANA is 10
368\end{cfa}
369Programmers can overwrite this behaviour by overloading the pipeline operator themselves.
370\PAB{This needs discussing because including \lstinline{<enum.hfa>} can change the entire meaning of a program.}
371
372
373\section{Planet Example}
374
375\VRef[Figure]{f:PlanetExample} shows an archetypal enumeration example illustrating most of the \CFA enumeration features.
376@Planet@ is an enumeration of type @MR@.
377Each of the planet enumerators is initialized to a specific mass/radius, @MR@, value.
378The unnamed enumeration provides the gravitational-constant enumerator @G@.
379Function @surfaceGravity@ uses the @with@ clause to remove @p@ qualification from fields @mass@ and @radius@.
380The program main uses @SizeE@ to obtain the number of enumerators in @Planet@, and safely converts the random value into a @Planet@ enumerator.
381The resulting random orbital-body is used in a \CFA @choose@ statement.
382The enumerators in the @case@ clause use position for testing.
383The prints use @labelE@ to print an enumerator's label.
384Finally, a loop iterates through the planets computing the weight on each planet for a given earth mass.
385The print statement does an equality comparison with an enumeration variable and enumerator.
386
387\begin{figure}
388\small
389\begin{cfa}
390struct MR { double mass, radius; };
391enum( @MR@ ) Planet {
392        //                      mass (kg)   radius (km)
393        MERCURY = { 0.330_E24, 2.4397_E6 },
394        VENUS      = { 4.869_E24, 6.0518_E6 },
395        EARTH       = { 5.976_E24, 6.3781_E6 },
396        MOON        = { 7.346_E22, 1.7380_E6 }, $\C{// not a planet}$
397        MARS         = { 0.642_E24, 3.3972_E6 },
398        JUPITER    = { 1898._E24, 71.492_E6 },
399        SATURN     = { 568.8_E24, 60.268_E6 },
400        URANUS    = { 86.86_E24, 25.559_E6 },
401        NEPTUNE  = { 102.4_E24, 24.746_E6 },
402};
403enum( double ) { G = 6.6743_E-11 }; $\C{// universal gravitational constant (m3 kg-1 s-2)}$
404static double surfaceGravity( Planet p ) @with( p )@ {
405        return G * mass / ( radius \ 2 ); $\C{// exponentiation}$
406}
407static double surfaceWeight( Planet p, double otherMass ) {
408        return otherMass * surfaceGravity( p );
409}
410int main( int argc, char * argv[] ) {
411        if ( argc != 2 ) exit | "Usage: " | argv[0] | "earth-weight";
412        double earthWeight = convert( argv[1] );
413        double earthMass = earthWeight / surfaceGravity( EARTH );
414
415        Planet p = @fromInt@( prng( @SizeE@(Planet) ) ); $\C{// select a random orbiting body}$
416        @choose( p )@ {
417          case MERCURY, VENUS, EARTH, MARS:
418                sout | @labelE( p )@ | "is a rocky planet";
419          @case JUPITER, SATURN, URANUS, NEPTUNE:@
420                sout | labelE( p ) | "is a gas-giant planet";
421          default:
422                sout | labelE( p ) | "is not a planet";
423        }
424        for ( @p; Planet@ ) {
425                sout | "Your weight on" | (@p == MOON@ ? "the" : "") | labelE(p)
426                           | "is" | wd( 1,1, surfaceWeight( p, earthMass ) ) | "kg";
427        }
428}
429$\$$ planet 100
430JUPITER is a gas-giant planet
431Your weight on MERCURY is 37.7 kg
432Your weight on VENUS is 90.5 kg
433Your weight on EARTH is 100.0 kg
434Your weight on the MOON is 16.6 kg
435Your weight on MARS is 37.9 kg
436Your weight on JUPITER is 252.8 kg
437Your weight on SATURN is 106.6 kg
438Your weight on URANUS is 90.5 kg
439Your weight on NEPTUNE is 113.8 kg
440\end{cfa}
441\caption{Planet Example}
442\label{f:PlanetExample}
443\end{figure}
Note: See TracBrowser for help on using the repository browser.