[7d9a805b] | 1 | \chapter{\CFA Enumeration} |
---|
[956299b] | 2 | |
---|
| 3 | |
---|
[7d9a805b] | 4 | \CFA supports C enumeration using the same syntax and semantics for backwards compatibility. |
---|
[956299b] | 5 | \CFA also extends C-Style enumeration by adding a number of new features that bring enumerations inline with other modern programming languages. |
---|
[f632117] | 6 | Any enumeration extensions must be intuitive to C programmers both in syntax and semantics. |
---|
| 7 | The following sections detail all of my new contributions to enumerations in \CFA. |
---|
[956299b] | 8 | |
---|
| 9 | |
---|
[f632117] | 10 | \section{Aliasing} |
---|
| 11 | |
---|
| 12 | C already provides @const@-style aliasing using the unnamed enumerator \see{\VRef{s:TypeName}}, even if the name @enum@ is misleading (@const@ would be better). |
---|
| 13 | Given the existence of this form, it is straightforward to extend it with types other than integers. |
---|
| 14 | \begin{cfa} |
---|
| 15 | enum E { Size = 20u, PI = 3.14159L, Jack = L"John" }; |
---|
| 16 | \end{cfa} |
---|
| 17 | which matches with @const@ aliasing in other programming languages. |
---|
| 18 | Here, the type of the enumerator is the type of the initialization constant, \eg @typeof(20u)@ for @Size@ implies @unsigned int@. |
---|
| 19 | Auto-initialization is restricted to the case where all constants are @int@, matching with C. |
---|
| 20 | As seen in \VRef{s:EnumeratorTyping}, this feature is just a shorthand for multiple typed-enumeration declarations. |
---|
[956299b] | 21 | |
---|
[f632117] | 22 | |
---|
| 23 | \section{Enumerator Unscoping} |
---|
| 24 | \label{s:EnumeratorUnscoping} |
---|
| 25 | |
---|
[caaf424] | 26 | In C, unscoped enumerators presents a \newterm{naming problem} when multiple enumeration types appear in the same scope with duplicate enumerator names. |
---|
[f632117] | 27 | There is no mechanism in C to resolve these naming conflicts other than renaming one of the duplicates, which may be impossible. |
---|
[956299b] | 28 | |
---|
| 29 | The \CFA type-system allows extensive overloading, including enumerators. |
---|
| 30 | Furthermore, \CFA uses the left-hand of assignment in type resolution to pinpoint the best overloaded name. |
---|
[f632117] | 31 | Finally, qualification and casting are provided to disambiguate any ambiguous situations. |
---|
[956299b] | 32 | \begin{cfa} |
---|
[7d9a805b] | 33 | enum E1 { First, Second, Third, Fourth }; |
---|
[f632117] | 34 | enum E2 { @Fourth@, @Third@, @Second@, @First@ }; $\C{// same enumerator names}$ |
---|
[7d9a805b] | 35 | E1 p() { return Third; } $\C{// correctly resolved duplicate names}$ |
---|
| 36 | E2 p() { return Fourth; } |
---|
[956299b] | 37 | void foo() { |
---|
[f632117] | 38 | E1 e1 = First; E2 e2 = First; $\C{// initialization}$ |
---|
| 39 | e1 = Second; e2 = Second; $\C{// assignment}$ |
---|
| 40 | e1 = p(); e2 = p(); $\C{// function call}$ |
---|
[7d9a805b] | 41 | int i = @E1.@First + @E2.@First; $\C{// disambiguate with qualification}$ |
---|
| 42 | int j = @(E1)@First + @(E2)@First; $\C{// disambiguate with cast}$ |
---|
[956299b] | 43 | } |
---|
| 44 | \end{cfa} |
---|
[7d9a805b] | 45 | \CFA overloading allows programmers to use the most meaningful names without fear of name clashes from include files. |
---|
[f632117] | 46 | In most cases, the type system implicitly disambiguates, otherwise the programmer explicitly disambiguates using qualification or casting. |
---|
[956299b] | 47 | |
---|
| 48 | |
---|
| 49 | \section{Enumerator Scoping} |
---|
| 50 | |
---|
[f632117] | 51 | An enumeration can be scoped, using @'!'@, so the enumerator constants are not projected into the enclosing scope. |
---|
[956299b] | 52 | \begin{cfa} |
---|
[f632117] | 53 | enum Week @!@ { Mon, Tue, Wed, Thu = 10, Fri, Sat, Sun }; |
---|
[7d9a805b] | 54 | enum RGB @!@ { Red, Green, Blue }; |
---|
[956299b] | 55 | \end{cfa} |
---|
| 56 | Now the enumerators \emph{must} be qualified with the associated enumeration. |
---|
| 57 | \begin{cfa} |
---|
[f632117] | 58 | Week week = @Week.@Mon; |
---|
| 59 | week = @Week.@Sat; |
---|
| 60 | RGB rgb = @RGB.@Red; |
---|
| 61 | rgb = @RGB.@Blue; |
---|
[956299b] | 62 | \end{cfa} |
---|
| 63 | 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}). |
---|
| 64 | \begin{cfa} |
---|
[f632117] | 65 | with ( @Week@, @RGB@ ) { $\C{// type names}$ |
---|
| 66 | week = @Sun@; $\C{// no qualification}$ |
---|
[7d9a805b] | 67 | rgb = @Green@; |
---|
[956299b] | 68 | } |
---|
| 69 | \end{cfa} |
---|
[f632117] | 70 | As 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 | |
---|
| 75 | Pseudo-functions are function-like operators that do not result in any run-time computations, \ie like @sizeof@, @alignof@, @typeof@. |
---|
| 76 | 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. |
---|
| 77 | |
---|
| 78 | The attributes of an enumerator are accessed by pseudo-functions @posE@, @valueE@, and @labelE@. |
---|
| 79 | \begin{cfa} |
---|
| 80 | int jane_pos = @posE@( Names.Jane ); $\C{// 2}$ |
---|
| 81 | char * jane_value = @valueE@( Names.Jane ); $\C{// "JANE"}$ |
---|
| 82 | char * jane_label = @labelE@( Names.Jane ); $\C{// "Jane"}$ |
---|
| 83 | sout | posE( Names.Jane) | labelE( Names.Jane ) | valueE( Names.Jane ); |
---|
| 84 | \end{cfa} |
---|
| 85 | Note the ability to print all of an enumerator's properties. |
---|
| 86 | |
---|
[956299b] | 87 | |
---|
| 88 | \section{Enumerator Typing} |
---|
[f632117] | 89 | \label{s:EnumeratorTyping} |
---|
[956299b] | 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. |
---|
| 92 | 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. |
---|
| 93 | Note, the synonyms @Liz@ and @Beth@ in the last declaration. |
---|
[f632117] | 94 | Because enumerators are constants, the enumeration type is implicitly @const@, so all the enumerator types in Figure~\ref{f:EumeratorTyping} are logically rewritten with @const@. |
---|
[956299b] | 95 | |
---|
[f632117] | 96 | C has an implicit type conversion from an enumerator to its base type @int@. |
---|
| 97 | Correspondingly, \CFA has an implicit (safe) conversion from a typed enumerator to its base type. |
---|
[956299b] | 98 | \begin{cfa} |
---|
| 99 | char currency = Dollar; |
---|
| 100 | string fred = Fred; $\C{// implicit conversion from char * to \CFA string type}$ |
---|
| 101 | Person 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 |
---|
[7d9a805b] | 116 | enum( @char@ ) Currency { Dollar = '$\textdollar$', Cent = '$\textcent$', Yen = '$\textyen$', Pound = '$\textsterling$', Euro = 'E' }; |
---|
[956299b] | 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 |
---|
[7d9a805b] | 123 | enum( @const char *@ ) Name { Fred = "FRED", Mary = "MARY", Jane = "JANE" }; |
---|
[956299b] | 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; }; |
---|
[7d9a805b] | 134 | @***@enum( @Person@ ) friends { @Liz@ = { "ELIZABETH", 22, 170 }, @Beth@ = Liz, |
---|
[f632117] | 135 | Jon = { "JONATHAN", 35, 190 } }; |
---|
[956299b] | 136 | \end{cfa} |
---|
| 137 | \caption{Enumerator Typing} |
---|
| 138 | \label{f:EumeratorTyping} |
---|
| 139 | \end{figure} |
---|
| 140 | |
---|
[f632117] | 141 | An advantage of the typed enumerations is eliminating the \emph{harmonizing} problem between an enumeration and companion data \see{\VRef{s:Usage}}: |
---|
[956299b] | 142 | \begin{cfa} |
---|
| 143 | enum( 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} |
---|
| 150 | 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. |
---|
| 151 | |
---|
[282061a] | 152 | While 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); |
---|
| 154 | calling constructors happens at runtime (dynamic). |
---|
| 155 | |
---|
[956299b] | 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} |
---|
| 161 | enum( char * ) Names { /* as above */ }; |
---|
| 162 | enum( char * ) Names2 { @inline Names@, Jack = "JACK", Jill = "JILL" }; |
---|
| 163 | @***@enum /* inferred */ Names3 { @inline Names2@, Sue = "SUE", Tom = "TOM" }; |
---|
| 164 | \end{cfa} |
---|
| 165 | Enumeration @Name2@ inherits all the enumerators and their values from enumeration @Names@ by containment, and a @Names@ enumeration is a subtype of enumeration @Name2@. |
---|
| 166 | Note, enumerators must be unique in inheritance but enumerator values may be repeated. |
---|
| 167 | |
---|
| 168 | The enumeration type for the inheriting type must be the same as the inherited type; |
---|
| 169 | hence 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. |
---|
| 171 | Specifically, the inheritance relationship for @Names@ is: |
---|
| 172 | \begin{cfa} |
---|
| 173 | Names $\(\subset\)$ Names2 $\(\subset\)$ Names3 $\(\subset\)$ const char * $\C{// enum type of Names}$ |
---|
| 174 | \end{cfa} |
---|
| 175 | For the given function prototypes, the following calls are valid. |
---|
| 176 | \begin{cquote} |
---|
| 177 | \begin{tabular}{ll} |
---|
| 178 | \begin{cfa} |
---|
| 179 | void f( Names ); |
---|
| 180 | void g( Names2 ); |
---|
| 181 | void h( Names3 ); |
---|
| 182 | void j( const char * ); |
---|
| 183 | \end{cfa} |
---|
| 184 | & |
---|
| 185 | \begin{cfa} |
---|
| 186 | f( Fred ); |
---|
| 187 | g( Fred ); g( Jill ); |
---|
| 188 | h( Fred ); h( Jill ); h( Sue ); |
---|
[f632117] | 189 | j( Fred ); j( Jill ); j( Sue ); j( "WILL" ); |
---|
[956299b] | 190 | \end{cfa} |
---|
| 191 | \end{tabular} |
---|
| 192 | \end{cquote} |
---|
| 193 | 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. |
---|
| 194 | |
---|
| 195 | |
---|
[f632117] | 196 | \section{Enumerator Control Structures} |
---|
[956299b] | 197 | |
---|
| 198 | Enumerators can be used in multiple contexts. |
---|
| 199 | In most programming languages, an enumerator is implicitly converted to its value (like a typed macro substitution). |
---|
| 200 | However, enumerator synonyms and typed enumerations make this implicit conversion to value incorrect in some contexts. |
---|
| 201 | In these contexts, a programmer's initition assumes an implicit conversion to postion. |
---|
| 202 | |
---|
| 203 | 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. |
---|
| 204 | \begin{cquote} |
---|
| 205 | \begin{cfa} |
---|
| 206 | enum Count { First, Second, Third, Fourth }; |
---|
| 207 | Count e; |
---|
| 208 | \end{cfa} |
---|
| 209 | \begin{tabular}{ll} |
---|
| 210 | \begin{cfa} |
---|
| 211 | |
---|
| 212 | choose( e ) { |
---|
| 213 | case @First@: ...; |
---|
| 214 | case @Second@: ...; |
---|
| 215 | case @Third@: ...; |
---|
| 216 | case @Fourth@: ...; |
---|
| 217 | } |
---|
| 218 | \end{cfa} |
---|
| 219 | & |
---|
| 220 | \begin{cfa} |
---|
| 221 | // rewrite |
---|
| 222 | choose( @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} |
---|
[de3a579] | 231 | Here, 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. |
---|
[f9da761] | 232 | However, this implementation is fragile, \eg if the enumeration is changed to: |
---|
[956299b] | 233 | \begin{cfa} |
---|
| 234 | enum Count { First, Second, Third @= First@, Fourth }; |
---|
| 235 | \end{cfa} |
---|
| 236 | which make @Third == First@ and @Fourth == Second@, causing a compilation error because of duplicase @case@ clauses. |
---|
| 237 | To better match with programmer intuition, \CFA toggles between value and position semantics depneding on the language context. |
---|
| 238 | For conditional clauses and switch statments, \CFA uses the robust position implementation. |
---|
| 239 | \begin{cfa} |
---|
| 240 | choose( @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} |
---|
| 249 | Count variable_a = First, variable_b = Second, variable_c = Third, variable_d = Fourth; |
---|
| 250 | p(variable_a); // 0 |
---|
| 251 | p(variable_b); // 1 |
---|
| 252 | p(variable_c); // "Third" |
---|
| 253 | p(variable_d); // 3 |
---|
| 254 | \end{cfa} |
---|
[7d9a805b] | 255 | |
---|
| 256 | |
---|
[f632117] | 257 | @if@ statement |
---|
| 258 | |
---|
| 259 | @switch@ statement |
---|
| 260 | |
---|
| 261 | looping statements |
---|
| 262 | |
---|
| 263 | |
---|
[7d9a805b] | 264 | \section{Planet Example} |
---|
| 265 | |
---|
[f632117] | 266 | \VRef[Figure]{f:PlanetExample} shows an archetypal enumeration example illustrating most of the \CFA enumeration features. |
---|
[caaf424] | 267 | @Planet@ is an enumeration of type @MR@. |
---|
[7d9a805b] | 268 | Each of the planet enumerators is initialized to a specific mass/radius, @MR@, value. |
---|
[caaf424] | 269 | The unnamed enumeration provides the gravitational-constant enumerator @G@. |
---|
| 270 | Function @surfaceGravity@ uses the @with@ clause to remove @p@ qualification from fields @mass@ and @radius@. |
---|
| 271 | The program main uses @SizeE@ to obtain the number of enumerators in @Planet@, and safely converts the random value into a @Planet@ enumerator. |
---|
| 272 | The resulting random orbital body is used in a @choose@ statement. |
---|
| 273 | The enumerators in the @case@ clause use position for testing. |
---|
| 274 | The prints use @labelE@ to print the enumerators label. |
---|
| 275 | Finally, a loop iterates through the planets computing the weight on each planet for a given earth weight. |
---|
| 276 | The print statement does an equality comparison with an enumeration variable and enumerator. |
---|
[7d9a805b] | 277 | |
---|
| 278 | \begin{figure} |
---|
[caaf424] | 279 | \small |
---|
[7d9a805b] | 280 | \begin{cfa} |
---|
| 281 | struct MR { double mass, radius; }; |
---|
[caaf424] | 282 | enum( @MR@ ) Planet { |
---|
[f632117] | 283 | // mass (kg) radius (km) |
---|
| 284 | MERCURY = { 0.330_E24, 2.4397_E6 }, |
---|
| 285 | VENUS = { 4.869_E24, 6.0518_E6 }, |
---|
[7d9a805b] | 286 | EARTH = { 5.976_E24, 6.3781_E6 }, |
---|
[f632117] | 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 }, |
---|
[7d9a805b] | 293 | }; |
---|
[caaf424] | 294 | enum( double ) { G = 6.6743_E-11 }; $\C{// universal gravitational constant (m3 kg-1 s-2)}$ |
---|
| 295 | static double surfaceGravity( Planet p ) @with( p )@ { |
---|
| 296 | return G * mass / ( radius \ 2u ); $\C{// exponentiation}$ |
---|
[7d9a805b] | 297 | } |
---|
| 298 | static double surfaceWeight( Planet p, double otherMass ) { |
---|
| 299 | return otherMass * surfaceGravity( p ); |
---|
| 300 | } |
---|
| 301 | int 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 ); |
---|
[caaf424] | 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"; |
---|
[7d9a805b] | 318 | } |
---|
| 319 | } |
---|
[f632117] | 320 | $\$$ planet 100 |
---|
[caaf424] | 321 | JUPITER is a gas-giant planet |
---|
[f632117] | 322 | Your weight on MERCURY is 37.7 kg |
---|
| 323 | Your weight on VENUS is 90.5 kg |
---|
| 324 | Your weight on EARTH is 100.0 kg |
---|
[caaf424] | 325 | Your weight on the MOON is 16.6 kg |
---|
[f632117] | 326 | Your weight on MARS is 37.9 kg |
---|
| 327 | Your weight on JUPITER is 252.8 kg |
---|
| 328 | Your weight on SATURN is 106.6 kg |
---|
| 329 | Your weight on URANUS is 90.5 kg |
---|
| 330 | Your weight on NEPTUNE is 113.8 kg |
---|
[7d9a805b] | 331 | \end{cfa} |
---|
| 332 | \caption{Planet Example} |
---|
| 333 | \label{f:PlanetExample} |
---|
| 334 | \end{figure} |
---|
[de3a579] | 335 | |
---|
| 336 | \section{Enum Trait} |
---|
[d414664] | 337 | The header file @<enum.hfa>@ defines traits implemented by, and sets of operators and helper functions defined for enum. |
---|
[de3a579] | 338 | |
---|
[d414664] | 339 | \begin{figure} |
---|
| 340 | \small |
---|
[de3a579] | 341 | \begin{cfa} |
---|
| 342 | forall(E) trait Bounded { |
---|
| 343 | E lowerBound(); |
---|
| 344 | E upperBound(); |
---|
| 345 | }; |
---|
| 346 | \end{cfa} |
---|
[d414664] | 347 | \caption{f:Bounded Trait} |
---|
| 348 | \label{f:BoundedTrait} |
---|
| 349 | \end{figure} |
---|
[de3a579] | 350 | |
---|
[d414664] | 351 | \CFA enums satisfy Bounded trait thanks to the default implemention of @lowerBound()@ and @upperBound()@, with |
---|
| 352 | @lowerBound()@ returning the first enumerator and @upperBound()@ returning the last. |
---|
| 353 | |
---|
| 354 | \begin{figure} |
---|
| 355 | \small |
---|
[de3a579] | 356 | \begin{cfa} |
---|
| 357 | Workday day1 = lowerBound(); // Monday |
---|
| 358 | Planet lastPlanet = upperBound(); // NEPTUNE |
---|
| 359 | \end{cfa} |
---|
[d414664] | 360 | \caption{f:Bound Functions} |
---|
| 361 | \label{f:BoundFunctions} |
---|
| 362 | \end{figure} |
---|
| 363 | |
---|
| 364 | @lowerBound()@ and @upperBound()@ are overloaded with return types only. Calling either functions |
---|
| 365 | without a context can result in type ambiguity if more than one types implement the functions from the @Bounded@ traits. |
---|
| 366 | Because \CFA enum types implements @Bounded@, multiple type enumerations in the same lexical scope will |
---|
| 367 | cause ambiguity on @lowerBound()@ and @upperBound()@ \see{\VRef{f:BoundFunctions} }. |
---|
[de3a579] | 368 | |
---|
[d414664] | 369 | \begin{figure} |
---|
| 370 | \small |
---|
[de3a579] | 371 | \begin{cfa} |
---|
[d414664] | 372 | // lowerBound(); // Error because both Planet and Workday implement Bounded |
---|
| 373 | Workday day1 = lowerBound(); // Okay because type of day1 hints lowerBound() to return a Workday |
---|
[de3a579] | 374 | void foo(Planet p); |
---|
[d414664] | 375 | foo( upperBound() ); Okay because foo expects value with type Planet as parameter |
---|
[de3a579] | 376 | \end{cfa} |
---|
[d414664] | 377 | \caption{Bound Function ambiguity} |
---|
| 378 | \label{f:BoundAmbiguity} |
---|
| 379 | \end{figure} |
---|
[de3a579] | 380 | |
---|
[d414664] | 381 | \begin{figure} |
---|
| 382 | \small |
---|
[de3a579] | 383 | \begin{cfa} |
---|
| 384 | forall(E | Bounded(E)) trait Serial { |
---|
| 385 | unsigned fromInstance(E e); |
---|
| 386 | E fromInt(unsigned i); |
---|
| 387 | E succ(E e); |
---|
| 388 | E pred(E e); |
---|
| 389 | }; |
---|
| 390 | \end{cfa} |
---|
[d414664] | 391 | \caption{Bounded Trait} |
---|
| 392 | \label{f:BoundedTrait} |
---|
| 393 | \end{figure} |
---|
| 394 | |
---|
| 395 | A Serial type is a @Bounded@ type where elements can be mapped to an integer sequence. |
---|
| 396 | A serial type @T@ can project to the integer type: an instance of type T has a corresponding integer value, |
---|
| 397 | but the inverse may not be possible, and possible requires a bound check. |
---|
[de3a579] | 398 | |
---|
[d414664] | 399 | The mapping from a serial type to integer is defined as @fromInstance(E e)@. |
---|
| 400 | For enum types, @fromInstance(E e)@ is equivalent to getting the position of e. |
---|
| 401 | The inverse of @fromInstance(E e)@ is @fromInt(unsigned i)@ and \CFA implements it with a bound check. |
---|
| 402 | For an enum @E@ declares N enumerators, @fromInt(i)@ returns the $i-1_{th}$ enumerator if $0 \leq i < N$, or error otherwises. |
---|
| 403 | |
---|
| 404 | The Serial trait provides interface functions @succ(E e)@ and @pred(E e)@ as members of a serial type are consecutive and ordinal. |
---|
| 405 | If @e@ is the $i_{th}$ enumerator, @succ(e)@ returns the $i+1_{th}$ enumerator when $e != upperBound()$, and @pred(e)@ |
---|
| 406 | returns the $i-1_{th}$ enumerator when $e != lowerBound()$. |
---|
| 407 | \CFA compiler gives an error if the result of the operation is out the domain of type @T@. |
---|
| 408 | |
---|
| 409 | \begin{figure} |
---|
| 410 | \small |
---|
[de3a579] | 411 | \begin{cfa} |
---|
| 412 | forall(E, T) trait TypedEnum { |
---|
| 413 | T valueE(E e); |
---|
| 414 | char * labelE(E e); |
---|
| 415 | unsigned int posE(E e); |
---|
| 416 | }; |
---|
| 417 | \end{cfa} |
---|
[d414664] | 418 | \caption{Type Enum Trait} |
---|
| 419 | \label{f:TypeEnumTrait} |
---|
| 420 | \end{figure} |
---|
[de3a579] | 421 | |
---|
[d414664] | 422 | The @TypedEnum@ trait captures three basic attributes of a type enum: value, label, and position. |
---|
| 423 | TypedEnum asserts two types @E@ and @T@, with @T@ being the base type of enumeration @E@. |
---|
| 424 | Implementing functions for general type enums is possible by asserting @TypeEnum(E, T)@. |
---|
[de3a579] | 425 | |
---|
[d414664] | 426 | \begin{figure} |
---|
| 427 | \small |
---|
[de3a579] | 428 | \begin{cfa} |
---|
| 429 | forall( E, T | TypeEnum(E, T)) |
---|
| 430 | void printEnum(E e) { |
---|
| 431 | sout | "Enum "| labelE(e); |
---|
| 432 | } |
---|
| 433 | printEunm(MARS); |
---|
| 434 | \end{cfa} |
---|
[d414664] | 435 | \caption{Implement Functions for Enums} |
---|
| 436 | \label{f:ImplementEnumFunction} |
---|
| 437 | \end{figure} |
---|
[de3a579] | 438 | |
---|
| 439 | @<enum.hfa>@ overwrites comparison operators for type enums. |
---|
[d414664] | 440 | \begin{figure} |
---|
| 441 | \small |
---|
[de3a579] | 442 | \begin{cfa} |
---|
| 443 | forall(E, T| TypedEnum(E, T)) { |
---|
| 444 | // comparison |
---|
[d414664] | 445 | int ?==?(E l, E r); // returns True if l and r are the same enumerator |
---|
| 446 | int ?!=?(E l, E r); // returns True if l and r are the different enumerator |
---|
| 447 | int ?!=?(E l, zero_t); // return True if l is not the first enumerator |
---|
| 448 | int ?<?(E l, E r); // return True if l is an enuemerator before r |
---|
| 449 | int ?<=?(E l, E r); // return True if l==r or l<r |
---|
| 450 | int ?>?(E l, E r); // return True if l is an enuemrator after r |
---|
| 451 | int ?>=?(E l, E r); // return True if l>r or l==r |
---|
[de3a579] | 452 | } |
---|
| 453 | \end{cfa} |
---|
[d414664] | 454 | \caption{Enum Operators} |
---|
| 455 | \label{f:EnumOperators} |
---|
| 456 | \end{figure} |
---|
| 457 | The overloaded operators in \ref{f:EnumOperators} are defined when and only when the header @<enum.hfa>@ is included. |
---|
| 458 | If not, the compiler converts an enumerator to its value, and applies the operators defined for the value type @T@. |
---|
[de3a579] | 459 | |
---|
[d414664] | 460 | \begin{figure} |
---|
| 461 | \small |
---|
[de3a579] | 462 | \begin{cfa} |
---|
| 463 | // if not include <enum.hfa> |
---|
| 464 | enum(int) Fruits { |
---|
[d414664] | 465 | APPLE = 2, BANANA=10, CHERRY=2 |
---|
[de3a579] | 466 | }; |
---|
[d414664] | 467 | APPLE == CHERRY; // True because valueE(APPLE) == valueE(CHERRY) |
---|
[de3a579] | 468 | #include <enum.hfa> |
---|
| 469 | APPLE == CHERRY; // False because they are different enumerator |
---|
[d414664] | 470 | \end{cfa} |
---|
| 471 | \caption{Include <enum.hfa>} |
---|
| 472 | \label{f:IncludeHeader} |
---|
| 473 | \end{figure} |
---|
| 474 | |
---|
| 475 | An enumerator returns its @position@ by default. In particular, |
---|
| 476 | @printf(...)@ from @<stdio.h>@ functions provides no context to its parameter type, |
---|
| 477 | so it prints @position@. |
---|
| 478 | |
---|
| 479 | On the other hand, the pipeline operator @?|?(ostream os, E enumType)@ provides type context for type @E@, and \CFA |
---|
| 480 | has overwritten this operator to prints enumeration @value@ over @position@. |
---|
| 481 | \begin{figure} |
---|
| 482 | \small |
---|
| 483 | \begin{cfa} |
---|
| 484 | printf("Position of BANANA is \%d", BANANA); // Postion of BANANA is 1 |
---|
| 485 | sout | "Value of BANANA is " | BANANA; // Value of BANANA is 10 |
---|
| 486 | \end{cfa} |
---|
| 487 | \caption{Print Enums} |
---|
| 488 | \label{f:PrintEnum} |
---|
| 489 | \end{figure} |
---|
| 490 | |
---|
| 491 | Programmers can overwrite this behaviour by overloading the pipeline operator themselve. |
---|