source: doc/theses/jiada_liang_MMath/CFAenum.tex @ 39cf5cc

Last change on this file since 39cf5cc was 62a38e7, checked in by Peter A. Buhr <pabuhr@…>, 4 months ago

remove calls to label() from planet program

  • Property mode set to 100644
File size: 20.4 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 @int@.
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 Visibility}
24\label{s:EnumeratorVisibility}
25
26In C, unscoped enumerators present 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 if the conflict comes from system include files.
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 f() { return Third; }                                $\C{// overloaded functions, different return types}$
36E2 f() { return Fourth; }
37void foo() {
38        E1 e1 = First;   E2 e2 = First;         $\C{// initialization}$
39        e1 = Second;   e2 = Second;                     $\C{// assignment}$
40        e1 = f();   e2 = f();                           $\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 within a program or from external sources, like include files.
46Experience from \CFA developers is that the type system implicitly and correctly disambiguates the majority of overloaded names, \ie it is rare to get an incorrect selection or ambiguity, even among hundreds of overloaded variables and functions.
47Any ambiguity can be resolved using qualification or casting.
48
49
50\section{Enumerator Scoping}
51
52An enumeration can be scoped, using @'!'@, so the enumerator constants are not projected into the enclosing scope.
53\begin{cfa}
54enum Week @!@ { Mon, Tue, Wed, Thu = 10, Fri, Sat, Sun };
55enum RGB @!@ { Red, Green, Blue };
56\end{cfa}
57Now the enumerators \emph{must} be qualified with the associated enumeration type.
58\begin{cfa}
59Week week = @Week.@Mon;
60week = @Week.@Sat;
61RGB rgb = @RGB.@Red;
62rgb = @RGB.@Blue;
63\end{cfa}
64It 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}).
65\begin{cfa}
66with ( @Week@, @RGB@ ) {                                $\C{// type names}$
67         week = @Sun@;                                          $\C{// no qualification}$
68         rgb = @Green@;
69}
70\end{cfa}
71As in Section~\ref{s:EnumeratorVisibility}, opening multiple scoped enumerations in a @with@ can result in duplicate enumeration names, but \CFA implicit type resolution and explicit qualification/casting handle this localized scenario.
72
73
74\section{Enumeration Trait}
75
76The header file \lstinline[deletekeywords=enum]{<enum.hfa>} defines the set of traits containing operators and helper functions for @enum@.
77A \CFA enumeration satisfies all of these traits allowing it to interact with runtime features in \CFA.
78Each trait is discussed in detail.
79
80The trait @Bounded@:
81\begin{cfa}
82forall( E ) trait Bounded {
83        E first();
84        E last();
85};
86\end{cfa}
87defines the bounds of the enumeration, where @first()@ returns the first enumerator and @last()@ returns the last, \eg:
88\begin{cfa}
89Workday day = first();                                  $\C{// Mon}$
90Planet outermost = last();                              $\C{// NEPTUNE}$
91\end{cfa}
92@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.
93Calling either functions without a context results in a type ambiguity, except in the rare case where the type environment has only one enumeration.
94\begin{cfa}
95@first();@                                                              $\C{// ambiguous Workday and Planet implement Bounded}$
96sout | @last()@;
97Workday day = first();                                  $\C{// day provides type Workday}$
98void foo( Planet p );
99foo( last() );                                                  $\C{// parameter provides type Planet}$
100\end{cfa}
101
102The trait @Serial@:
103\begin{cfa}
104forall( E | Bounded( E ) ) trait Serial {
105        unsigned fromInstance( E e );
106        E fromInt( unsigned int posn );
107        E succ( E e );
108        E pred( E e );
109};
110\end{cfa}
111is a @Bounded@ trait, where elements can be mapped to an integer sequence.
112A type @T@ matching @Serial@ can project to an unsigned @int@ type, \ie an instance of type T has a corresponding integer value.
113%However, the inverse may not be possible, and possible requires a bound check.
114The mapping from a serial type to integer is defined by @fromInstance@, which returns the enumerator's position.
115The inverse operation is @fromInt@, which performs a bound check using @first()@ and @last()@ before casting the integer into an enumerator.
116Specifically, for enumerator @E@ declaring $N$ enumerators, @fromInt( i )@ returns the $i-1_{th}$ enumerator, if $0 \leq i < N$, or raises the exception @enumBound@.
117
118The @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.
119Specifically, 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()$.
120The exception @enumRange@ is raised if the result of either operation is outside the range of type @E@.
121
122The trait @TypedEnum@:
123\begin{cfa}
124forall( E, T ) trait TypedEnum {
125        T valueE( E e );
126        char * labelE( E e );
127        unsigned int posE( E e );
128};
129\end{cfa}
130captures three basic attributes of an enumeration type: value, label, and position.
131@TypedEnum@ asserts two types @E@ and @T@, with @T@ being the base type of the enumeration @E@, \eg @enum( T ) E { ... };@.
132Implementing general functions across all enumeration types is possible by asserting @TypeEnum( E, T )@, \eg:
133\begin{cfa}
134forall( E, T | TypeEnum( E, T ) )
135void printEnum( E e ) {
136        sout | "Enum "| labelE( e );
137}
138printEunm( MARS );
139\end{cfa}
140
141Finally, there is an associated trait defining comparison operators among enumerators.
142\begin{cfa}
143forall( E, T | TypedEnum( E, T ) ) {
144        // comparison
145        int ?==?( E l, E r );           $\C{// true if l and r are same enumerators}$
146        int ?!=?( E l, E r );           $\C{// true if l and r are different enumerators}$
147        int ?!=?( E l, zero_t );        $\C{// true if l is not the first enumerator}$
148        int ?<?( E l, E r );            $\C{// true if l is an enumerator before r}$
149        int ?<=?( E l, E r );           $\C{// true if l before or the same as r}$
150        int ?>?( E l, E r );            $\C{// true if l is an enumerator after r}$
151        int ?>=?( E l, E r );           $\C{// true if l after or the same as r}$         
152}
153\end{cfa}
154Note, the overloaded operators are defined only when the header @<enum.hfa>@ is included.
155If not, the compiler converts an enumerator to its value, and applies the operators defined for the value type @E@, \eg:
156\begin{cfa}
157// if not include <enum.hfa>
158enum( int ) Fruits { APPLE = 2, BANANA = 10, CHERRY = 2 };
159APPLE == CHERRY; // true because valueE( APPLE ) == valueE( CHERRY )
160
161#include <enum.hfa>
162APPLE == CHERRY; // false because posE( APPLE ) != posE( CHERRY )
163\end{cfa}
164An enumerator returns its @position@ by default.
165In particular, @printf( ... )@ from @<stdio.h>@ functions provides no context to its parameter type, so it prints @position@.
166On 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@.
167\begin{cfa}
168printf( "Position of BANANA is \%d", BANANA ); // Position of BANANA is 1
169sout | "Value of BANANA is " | BANANA; // Value of BANANA is 10
170\end{cfa}
171Programmers can overwrite this behaviour by overloading the pipeline operator themselves.
172\PAB{This needs discussing because including \lstinline{<enum.hfa>} can change the entire meaning of a program.}
173
174
175% \section{Enumeration Pseudo-functions}
176
177% Pseudo-functions are function-like operators that do not result in any run-time computations, \ie like @sizeof@, @alignof@, @typeof@.
178% A pseudo-function call is often substituted with information extracted from the compilation symbol-table, like storage size or alignment associated with the underlying architecture.
179
180% The attributes of an enumerator are accessed by pseudo-functions @posE@, @valueE@, and @labelE@.
181% \begin{cfa}
182% int jane_pos = @posE@( Names.Jane );   $\C{// 2}$
183% char * jane_value = @valueE@( Names.Jane ); $\C{// "JANE"}$
184% char * jane_label = @labelE@( Names.Jane ); $\C{// "Jane"}$
185% sout | posE( Names.Jane) | labelE( Names.Jane ) | valueE( Names.Jane );
186% \end{cfa}
187% Note the ability to print all of an enumerator's properties.
188
189
190\section{Enumerator Typing}
191\label{s:EnumeratorTyping}
192
193\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.
194Figure~\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.
195Note, the synonyms @Liz@ and @Beth@ in the last declaration.
196Because enumerators are constants, the enumeration type is implicitly @const@, so all the enumerator types in Figure~\ref{f:EumeratorTyping} are logically rewritten with @const@.
197
198C has an implicit type conversion from an enumerator to its base type @int@.
199Correspondingly, \CFA has an implicit (safe) conversion from a typed enumerator to its base type.
200\begin{cfa}
201char currency = Dollar;
202string fred = Fred;                                             $\C{// implicit conversion from char * to \CFA string type}$
203Person student = Beth;
204\end{cfa}
205
206% \begin{cfa}
207% struct S { int i, j; };
208% enum( S ) s { A = { 3,  4 }, B = { 7,  8 } };
209% enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$'  };
210% enum( @double@ ) Planet { Venus = 4.87, Earth = 5.97, Mars = 0.642  }; // mass
211% enum( @char *@ ) Colour { Red = "red", Green = "green", Blue = "blue"  };
212% enum( @Currency@ ) Europe { Euro = '$\texteuro$', Pound = '$\textsterling$' }; // intersection
213% \end{cfa}
214
215\begin{figure}
216\begin{cfa}
217// integral
218        enum( @char@ ) Currency { Dollar = '$\textdollar$', Cent = '$\textcent$', Yen = '$\textyen$', Pound = '$\textsterling$', Euro = 'E' };
219        enum( @signed char@ ) srgb { Red = -1, Green = 0, Blue = 1 };
220        enum( @long long int@ ) BigNum { X = 123_456_789_012_345,  Y = 345_012_789_456_123 };
221// non-integral
222        enum( @double@ ) Math { PI_2 = 1.570796, PI = 3.141597, E = 2.718282 };
223        enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i };
224// pointer
225        enum( @const char *@ ) Name { Fred = "FRED", Mary = "MARY", Jane = "JANE" };
226        int i, j, k;
227        enum( @int *@ ) ptr { I = &i,  J = &j,  K = &k };
228        enum( @int &@ ) ref { I = i,   J = j,   K = k };
229// tuple
230        enum( @[int, int]@ ) { T = [ 1, 2 ] }; $\C{// new \CFA type}$
231// function
232        void f() {...}   void g() {...}
233        enum( @void (*)()@ ) funs { F = f,  G = g };
234// aggregate
235        struct Person { char * name; int age, height; };
236@***@enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz,
237                                                                        Jon = { "JONATHAN", 35, 190 } };
238\end{cfa}
239\caption{Enumerator Typing}
240\label{f:EumeratorTyping}
241\end{figure}
242
243An advantage of the typed enumerations is eliminating the \emph{harmonizing} problem between an enumeration and companion data \see{\VRef{s:Usage}}:
244\begin{cfa}
245enum( char * ) integral_types {
246        chr = "char", schar = "signed char", uschar = "unsigned char",
247        sshort = "signed short int", ushort = "unsigned short int",
248        sint = "signed int", usint = "unsigned int",
249        ...
250};
251\end{cfa}
252Note, 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.
253
254While the enumeration type can be any C aggregate, the aggregate's \CFA constructors are not used to evaluate an enumerator's value.
255\CFA enumeration constants are compile-time values (static);
256calling constructors happens at runtime (dynamic).
257
258
259\section{Enumerator Opaque Type}
260
261\CFA provides a special opaque enumeration type, where the internal representation is chosen by the compiler and only equality operations are available.
262\begin{cfa}
263enum@()@ Planets { MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE };
264\end{cfa}
265
266
267\section{Enumeration Inheritance}
268
269\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).
270\begin{cfa}
271enum( char * ) Names { /* as above */ };
272enum( char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" };
273@***@enum /* inferred */ Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" };
274\end{cfa}
275Enumeration @Name2@ inherits all the enumerators and their values from enumeration @Names@ by containment, and a @Names@ enumeration is a subtype of enumeration @Name2@.
276Note, enumerators must be unique in inheritance but enumerator values may be repeated.
277
278The enumeration type for the inheriting type must be the same as the inherited type;
279hence the enumeration type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for @Name3@.
280% When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important.
281Specifically, the inheritance relationship for @Names@ is:
282\begin{cfa}
283Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\(\subset\)$ const char * $\C{// enum type of Names}$
284\end{cfa}
285For the given function prototypes, the following calls are valid.
286\begin{cquote}
287\begin{tabular}{ll}
288\begin{cfa}
289void f( Names );
290void g( Names2 );
291void h( Names3 );
292void j( const char * );
293\end{cfa}
294&
295\begin{cfa}
296f( Fred );
297g( Fred );   g( Jill );
298h( Fred );   h( Jill );   h( Sue );
299 j( Fred );    j( Jill );    j( Sue );    j( "WILL" );
300\end{cfa}
301\end{tabular}
302\end{cquote}
303Note, 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.
304
305
306\section{Enumerator Control Structures}
307
308Enumerators can be used in multiple contexts.
309In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution).
310However, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect in some contexts.
311In these contexts, a programmer's initition assumes an implicit conversion to postion.
312
313For 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.
314\begin{cquote}
315\begin{cfa}
316enum Count { First, Second, Third, Fourth };
317Count e;
318\end{cfa}
319\begin{tabular}{ll}
320\begin{cfa}
321
322choose( e ) {
323        case @First@: ...;
324        case @Second@: ...;
325        case @Third@: ...;
326        case @Fourth@: ...;
327}
328\end{cfa}
329&
330\begin{cfa}
331// rewrite
332choose( @value@( e ) ) {
333        case @value@( First ): ...;
334        case @value@( Second ): ...;
335        case @value@( Third ): ...;
336        case @value@( Fourth ): ...;
337}
338\end{cfa}
339\end{tabular}
340\end{cquote}
341Here, 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.
342However, this implementation is fragile, \eg if the enumeration is changed to:
343\begin{cfa}
344enum Count { First, Second, Third @= First@, Fourth };
345\end{cfa}
346which make @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicase @case@ clauses.
347To better match with programmer intuition, \CFA toggles between value and position semantics depending on the language context.
348For conditional clauses and switch statments, \CFA uses the robust position implementation.
349\begin{cfa}
350choose( @position@( e ) ) {
351        case @position@( First ): ...;
352        case @position@( Second ): ...;
353        case @position@( Third ): ...;
354        case @position@( Fourth ): ...;
355}
356\end{cfa}
357
358\begin{cfa}
359Count variable_a = First, variable_b = Second, variable_c = Third, variable_d = Fourth;
360p(variable_a); // 0
361p(variable_b); // 1
362p(variable_c); // "Third"
363p(variable_d); // 3
364\end{cfa}
365
366
367@if@ statement
368
369@switch@ statement
370
371looping statements
372
373
374\section{Enumerated Arrays}
375Enumerated array use an \CFA array as their index.
376\begin{cfa}
377enum() Colour {
378        Red, Orange, Yellow, Green, Blue, Indigo, Violet
379};
380
381string colourCode[Colour] = { "#e81416", "#ffa500", "#ffa500", "#ffa500", "#487de7", "#4b369d", "#70369d" };
382sout | "Colour Code of Orange is " | colourCode[Orange];
383\end{cfa}
384
385
386\section{Planet Example}
387
388\VRef[Figure]{f:PlanetExample} shows an archetypal enumeration example illustrating most of the \CFA enumeration features.
389@Planet@ is an enumeration of type @MR@.
390Each of the planet enumerators is initialized to a specific mass/radius, @MR@, value.
391The unnamed enumeration provides the gravitational-constant enumerator @G@.
392Function @surfaceGravity@ uses the @with@ clause to remove @p@ qualification from fields @mass@ and @radius@.
393The 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@.
394The resulting random orbital-body is used in a @choose@ statement.
395The enumerators in the @case@ clause use enumerator position for testing.
396The prints use @label@ to print an enumerator's name.
397Finally, a loop enumerates through the planets computing the weight on each planet for a given earth mass.
398The print statement does an equality comparison with an enumeration variable and enumerator (@p == MOON@).
399
400\begin{figure}
401\small
402\begin{cfa}
403struct MR { double mass, radius; };
404enum( @MR@ ) Planet {                                           $\C{// typed enumeration}$
405        //                      mass (kg)   radius (km)
406        MERCURY = { 0.330_E24, 2.4397_E6 },
407        VENUS      = { 4.869_E24, 6.0518_E6 },
408        EARTH       = { 5.976_E24, 6.3781_E6 },
409        MOON        = { 7.346_E22, 1.7380_E6 }, $\C{// not a planet}$
410        MARS         = { 0.642_E24, 3.3972_E6 },
411        JUPITER    = { 1898._E24, 71.492_E6 },
412        SATURN     = { 568.8_E24, 60.268_E6 },
413        URANUS    = { 86.86_E24, 25.559_E6 },
414        NEPTUNE  = { 102.4_E24, 24.746_E6 },
415        PLUTO       = { 1.303_E22, 1.1880_E6 }, $\C{// not a planet}$
416};
417enum( double ) { G = 6.6743_E-11 };                     $\C{// universal gravitational constant (m3 kg-1 s-2)}$
418static double surfaceGravity( Planet p ) @with( p )@ {
419        return G * mass / ( radius @\@ 2 );             $\C{// no qualification, exponentiation}$
420}
421static double surfaceWeight( Planet p, double otherMass ) {
422        return otherMass * surfaceGravity( p );
423}
424int main( int argc, char * argv[] ) {
425        if ( argc != 2 ) @exit@ | "Usage: " | argv[0] | "earth-weight";  // terminate program
426        double earthWeight = convert( argv[1] );
427        double earthMass = earthWeight / surfaceGravity( EARTH );
428        Planet rp = @fromInt@( prng( @countof@( Planet ) ) ); $\C{// select random orbiting body}$
429        @choose( rp )@ {                                                $\C{// implicit breaks}$
430          case MERCURY, VENUS, EARTH, MARS:
431                sout | @rp@ | "is a rocky planet";
432          case JUPITER, SATURN, URANUS, NEPTUNE:
433                sout | rp | "is a gas-giant planet";
434          default:
435                sout | rp | "is not a planet";
436        }
437        for ( @p; Planet@ ) {                                   $\C{// enumerate}$
438                sout | "Your weight on" | ( @p == MOON@ ? "the" : " " ) | p
439                           | "is" | wd( 1,1,  surfaceWeight( p, earthMass ) ) | "kg";
440        }
441}
442$\$$ planet 100
443JUPITER is a gas-giant planet
444Your weight on MERCURY is 37.7 kg
445Your weight on VENUS is 90.5 kg
446Your weight on EARTH is 100.0 kg
447Your weight on the MOON is 16.6 kg
448Your weight on MARS is 37.9 kg
449Your weight on JUPITER is 252.8 kg
450Your weight on SATURN is 106.6 kg
451Your weight on URANUS is 90.5 kg
452Your weight on NEPTUNE is 113.8 kg
453Your weight on PLUTO is 6.3 kg
454\end{cfa}
455\caption{Planet Example}
456\label{f:PlanetExample}
457\end{figure}
Note: See TracBrowser for help on using the repository browser.