1 | \chapter{\CFA-Style Enum} |
---|
2 | |
---|
3 | |
---|
4 | \CFA supports C-Style 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 | |
---|
11 | In C, unscoping of enumerators presents a \Newterm{naming problem} when multiple enumeration types appear in the same scope with duplicate enumerator names. |
---|
12 | There is no mechanism in C to resolve these naming conflicts other than renaming of one of the duplicates, which may be impossible. |
---|
13 | |
---|
14 | The \CFA type-system allows extensive overloading, including enumerators. |
---|
15 | Furthermore, \CFA uses the left-hand of assignment in type resolution to pinpoint the best overloaded name. |
---|
16 | Finally, qualification is provided to disambiguate any ambiguous situations. |
---|
17 | \begin{cfa} |
---|
18 | enum C1 { First, Second, Third, Fourth }; |
---|
19 | enum C2 { @Fourth@, @Third@, @Second@, @First@ }; |
---|
20 | C1 p() { return Third; } $\C{// correctly resolved duplicate names}$ |
---|
21 | C2 p() { return Fourth; } |
---|
22 | void foo() { |
---|
23 | C1 e1 = First; C2 e2 = First; |
---|
24 | e1 = Second; e2 = Second; |
---|
25 | e1 = p(); e2 = p(); $\C{// correctly resolved function call}$ |
---|
26 | int i = @C1.@First + @C2.@First; $\C{// ambiguous without qualification}$ |
---|
27 | } |
---|
28 | \end{cfa} |
---|
29 | \CFA overloading allows programmers to use the most meaningful names without fear of unresolvable clashes from included files, which are correctable with qualification. |
---|
30 | |
---|
31 | |
---|
32 | \section{Enumerator Scoping} |
---|
33 | |
---|
34 | An enumeration can be scoped, so the enumerator constants are not projected into the enclosing scope, using @'!'@. |
---|
35 | \begin{cfa} |
---|
36 | enum Weekday @!@ { /* as above */ }; |
---|
37 | enum( char * ) Names @!@ { /* as above */ }; |
---|
38 | \end{cfa} |
---|
39 | Now the enumerators \emph{must} be qualified with the associated enumeration. |
---|
40 | \begin{cfa} |
---|
41 | Weekday weekday = @Weekday@.Monday; |
---|
42 | Names names = @Names.@Fred; |
---|
43 | names = @Names.@Jane; |
---|
44 | \end{cfa} |
---|
45 | It 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}). |
---|
46 | \begin{cfa} |
---|
47 | Weekday weekday; |
---|
48 | with ( @Weekday@, @Names@ ) { $\C{// type names}$ |
---|
49 | Names names = @Fred@; |
---|
50 | names = @Jane@; |
---|
51 | weekday = Saturday; |
---|
52 | } |
---|
53 | \end{cfa} |
---|
54 | As in Section~\ref{s:EnumeratorNameResolution}, opening multiple unscoped enumerations can result in duplicate enumeration names, but \CFA type resolution and falling back to explicit qualification handles name resolution. |
---|
55 | |
---|
56 | \section{Enumerator Typing} |
---|
57 | |
---|
58 | \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. |
---|
59 | Figure~\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. |
---|
60 | Note, the synonyms @Liz@ and @Beth@ in the last declaration. |
---|
61 | |
---|
62 | Because enumerators are constants, the enumeration type is implicitly @const@, so all the enumerator types in Figure~\ref{f:EumeratorTyping} are rewritten with @const@. |
---|
63 | A typed enumeration has an implicit (safe) conversion to its base type. |
---|
64 | \begin{cfa} |
---|
65 | char currency = Dollar; |
---|
66 | string fred = Fred; $\C{// implicit conversion from char * to \CFA string type}$ |
---|
67 | Person student = Beth; |
---|
68 | \end{cfa} |
---|
69 | |
---|
70 | % \begin{cfa} |
---|
71 | % struct S { int i, j; }; |
---|
72 | % enum( S ) s { A = { 3, 4 }, B = { 7, 8 } }; |
---|
73 | % enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$' }; |
---|
74 | % enum( @double@ ) Planet { Venus = 4.87, Earth = 5.97, Mars = 0.642 }; // mass |
---|
75 | % enum( @char *@ ) Colour { Red = "red", Green = "green", Blue = "blue" }; |
---|
76 | % enum( @Currency@ ) Europe { Euro = '$\texteuro$', Pound = '$\textsterling$' }; // intersection |
---|
77 | % \end{cfa} |
---|
78 | |
---|
79 | \begin{figure} |
---|
80 | \begin{cfa} |
---|
81 | // integral |
---|
82 | enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$' }; |
---|
83 | enum( @signed char@ ) srgb { Red = -1, Green = 0, Blue = 1 }; |
---|
84 | enum( @long long int@ ) BigNum { X = 123_456_789_012_345, Y = 345_012_789_456_123 }; |
---|
85 | // non-integral |
---|
86 | enum( @double@ ) Math { PI_2 = 1.570796, PI = 3.141597, E = 2.718282 }; |
---|
87 | enum( @_Complex@ ) Plane { X = 1.5+3.4i, Y = 7+3i, Z = 0+0.5i }; |
---|
88 | // pointer |
---|
89 | enum( @char *@ ) Names { Fred = "FRED", Mary = "MARY", Jane = "JANE" }; |
---|
90 | int i, j, k; |
---|
91 | enum( @int *@ ) ptr { I = &i, J = &j, K = &k }; |
---|
92 | enum( @int &@ ) ref { I = i, J = j, K = k }; |
---|
93 | // tuple |
---|
94 | enum( @[int, int]@ ) { T = [ 1, 2 ] }; $\C{// new \CFA type}$ |
---|
95 | // function |
---|
96 | void f() {...} void g() {...} |
---|
97 | enum( @void (*)()@ ) funs { F = f, G = g }; |
---|
98 | // aggregate |
---|
99 | struct Person { char * name; int age, height; }; |
---|
100 | @***@enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz, Jon = { "JONATHAN", 35, 190 } }; |
---|
101 | \end{cfa} |
---|
102 | \caption{Enumerator Typing} |
---|
103 | \label{f:EumeratorTyping} |
---|
104 | \end{figure} |
---|
105 | |
---|
106 | Typed enumerations deals with the \emph{harmonizing} problem between an enumeration and any companion data. |
---|
107 | The following example is from the \CFA compiler, written in \CC. |
---|
108 | \begin{cfa} |
---|
109 | enum integral_types { chr, schar, uschar, sshort, ushort, sint, usint, ..., NO_OF_ITYPES }; |
---|
110 | char * integral_names[NO_OF_ITYPES] = { |
---|
111 | "char", "signed char", "unsigned char", |
---|
112 | "signed short int", "unsigned short int", |
---|
113 | "signed int", "unsigned int", |
---|
114 | ... |
---|
115 | }; |
---|
116 | \end{cfa} |
---|
117 | The \emph{harmonizing} problem occurs because the enumeration declaration is in one header file and the names are declared in another translation unit. |
---|
118 | It 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). |
---|
119 | The typed enumeration largely solves this problem by combining and managing the two data types. |
---|
120 | \begin{cfa} |
---|
121 | enum( char * ) integral_types { |
---|
122 | chr = "char", schar = "signed char", uschar = "unsigned char", |
---|
123 | sshort = "signed short int", ushort = "unsigned short int", |
---|
124 | sint = "signed int", usint = "unsigned int", |
---|
125 | ... |
---|
126 | }; |
---|
127 | \end{cfa} |
---|
128 | Note, 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. |
---|
129 | |
---|
130 | |
---|
131 | \section{Pure Enumerators} |
---|
132 | |
---|
133 | An empty enumerator type, @enum()@, implies the enumerators are pure symbols without values but set properties; |
---|
134 | hence, there is no default conversion to @int@. |
---|
135 | |
---|
136 | \begin{cfa} |
---|
137 | enum() Mode { O_RDONLY, O_WRONLY, O_CREAT, O_TRUNC, O_APPEND }; |
---|
138 | @***@Mode iomode = O_RDONLY; |
---|
139 | bool b = iomode == O_RDONLY || iomode < O_APPEND; |
---|
140 | int i = iomode; $\C{\color{red}// disallowed}$ |
---|
141 | \end{cfa} |
---|
142 | |
---|
143 | \section{Enumerator Subset} |
---|
144 | |
---|
145 | If follows from enumerator typing that the enumerator type can be another enumerator. |
---|
146 | \begin{cfa} |
---|
147 | enum( @char@ ) Currency { Dollar = '$\textdollar$', Euro = '$\texteuro$', Pound = '$\textsterling$' }; |
---|
148 | enum( @Currency@ ) Europe { Euro = Currency.Euro, Pound = Currency.Pound }; // intersection |
---|
149 | enum( char ) Letter { A = 'A', B = 'B', C = 'C', ..., Z = 'Z' }; |
---|
150 | enum( @Letter@ ) Greek { Alph = A, Beta = B, ..., Zeta = Z }; // intersection |
---|
151 | \end{cfa} |
---|
152 | Subset enumerations may have more or less enumerators than their typed enumeration, but the enumerator values must be from the typed enumeration. |
---|
153 | For 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@. |
---|
154 | \begin{cfa} |
---|
155 | Letter letter = A; |
---|
156 | @***@Greak greek = Beta; |
---|
157 | letter = Beta; $\C{// allowed, letter == B}$ |
---|
158 | greek = A; $\C{\color{red}// disallowed}$ |
---|
159 | \end{cfa} |
---|
160 | |
---|
161 | |
---|
162 | \section{Enumeration Inheritance} |
---|
163 | |
---|
164 | \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). |
---|
165 | \begin{cfa} |
---|
166 | enum( char * ) Names { /* as above */ }; |
---|
167 | enum( char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" }; |
---|
168 | @***@enum /* inferred */ Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" }; |
---|
169 | \end{cfa} |
---|
170 | Enumeration @Name2@ inherits all the enumerators and their values from enumeration @Names@ by containment, and a @Names@ enumeration is a subtype of enumeration @Name2@. |
---|
171 | Note, enumerators must be unique in inheritance but enumerator values may be repeated. |
---|
172 | |
---|
173 | The enumeration type for the inheriting type must be the same as the inherited type; |
---|
174 | hence the enumeration type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for @Name3@. |
---|
175 | % When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important. |
---|
176 | Specifically, the inheritance relationship for @Names@ is: |
---|
177 | \begin{cfa} |
---|
178 | Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\(\subset\)$ const char * $\C{// enum type of Names}$ |
---|
179 | \end{cfa} |
---|
180 | For the given function prototypes, the following calls are valid. |
---|
181 | \begin{cquote} |
---|
182 | \begin{tabular}{ll} |
---|
183 | \begin{cfa} |
---|
184 | void f( Names ); |
---|
185 | void g( Names2 ); |
---|
186 | void h( Names3 ); |
---|
187 | void j( const char * ); |
---|
188 | \end{cfa} |
---|
189 | & |
---|
190 | \begin{cfa} |
---|
191 | f( Fred ); |
---|
192 | g( Fred ); g( Jill ); |
---|
193 | h( Fred ); h( Jill ); h( Sue ); |
---|
194 | j( Fred ); j( Jill ); j( Sue ); j( "WILL" ); |
---|
195 | \end{cfa} |
---|
196 | \end{tabular} |
---|
197 | \end{cquote} |
---|
198 | Note, 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. |
---|
199 | |
---|
200 | |
---|
201 | \section{Enumeration Pseudo-functions} |
---|
202 | |
---|
203 | Pseudo-functions are function-like operators that do not result in any run-time computations, i.e., like @sizeof@, @offsetof@, @typeof@. |
---|
204 | Often 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.. |
---|
205 | |
---|
206 | The attributes of an enumerator are accessed by pseudo-functions @position@, @value@, and @label@. |
---|
207 | \begin{cfa} |
---|
208 | @***@int jane_pos = @position@( Names.Jane ); $\C{// 2}$ |
---|
209 | @***@char * jane_value = @value@( Names.Jane ); $\C{// "JANE"}$ |
---|
210 | @***@char * jane_label = @label@( Names.Jane ); $\C{// "Jane"}$ |
---|
211 | sout | @label@( Names.Jane ) | @value@( Names.Jane ); |
---|
212 | \end{cfa} |
---|
213 | Note the ability to print both enumerator label and value. |
---|
214 | |
---|
215 | |
---|
216 | \section{Enumerator Position or Value} |
---|
217 | |
---|
218 | Enumerators can be used in multiple contexts. |
---|
219 | In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution). |
---|
220 | However, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect in some contexts. |
---|
221 | In these contexts, a programmer's initition assumes an implicit conversion to postion. |
---|
222 | |
---|
223 | For 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. |
---|
224 | \begin{cquote} |
---|
225 | \begin{cfa} |
---|
226 | enum Count { First, Second, Third, Fourth }; |
---|
227 | Count e; |
---|
228 | \end{cfa} |
---|
229 | \begin{tabular}{ll} |
---|
230 | \begin{cfa} |
---|
231 | |
---|
232 | choose( e ) { |
---|
233 | case @First@: ...; |
---|
234 | case @Second@: ...; |
---|
235 | case @Third@: ...; |
---|
236 | case @Fourth@: ...; |
---|
237 | } |
---|
238 | \end{cfa} |
---|
239 | & |
---|
240 | \begin{cfa} |
---|
241 | // rewrite |
---|
242 | choose( @value@( e ) ) { |
---|
243 | case @value@( First ): ...; |
---|
244 | case @value@( Second ): ...; |
---|
245 | case @value@( Third ): ...; |
---|
246 | case @value@( Fourth ): ...; |
---|
247 | } |
---|
248 | \end{cfa} |
---|
249 | \end{tabular} |
---|
250 | \end{cquote} |
---|
251 | Here, 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. |
---|
252 | However, this implementation is fragile, e.g., if the enumeration is changed to: |
---|
253 | \begin{cfa} |
---|
254 | enum Count { First, Second, Third @= First@, Fourth }; |
---|
255 | \end{cfa} |
---|
256 | which make @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicase @case@ clauses. |
---|
257 | To better match with programmer intuition, \CFA toggles between value and position semantics depneding on the language context. |
---|
258 | For conditional clauses and switch statments, \CFA uses the robust position implementation. |
---|
259 | \begin{cfa} |
---|
260 | choose( @position@( e ) ) { |
---|
261 | case @position@( First ): ...; |
---|
262 | case @position@( Second ): ...; |
---|
263 | case @position@( Third ): ...; |
---|
264 | case @position@( Fourth ): ...; |
---|
265 | } |
---|
266 | \end{cfa} |
---|
267 | |
---|
268 | \begin{cfa} |
---|
269 | Count variable_a = First, variable_b = Second, variable_c = Third, variable_d = Fourth; |
---|
270 | p(variable_a); // 0 |
---|
271 | p(variable_b); // 1 |
---|
272 | p(variable_c); // "Third" |
---|
273 | p(variable_d); // 3 |
---|
274 | \end{cfa} |
---|