source: doc/theses/jiada_liang_MMath/relatedwork.tex @ 7d9a805b

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

more proofreading for enumerations

  • Property mode set to 100644
File size: 96.0 KB
Line 
1\chapter{Related Work}
2\label{s:RelatedWork}
3
4\begin{comment}
5An algebraic data type (ADT) can be viewed as a recursive sum of product types.
6A sum type lists values as members.
7A member in a sum type definition is known as a data constructor.
8For example, C supports sum types union and enumeration (enum).
9An enumeration in C can be viewed as the creation of a list of zero-arity data constructors.
10A union instance holds a value of one of its member types.
11Defining a union does not generate new constructors.
12The definition of member types and their constructors are from the outer lexical scope.
13
14In general, an \Newterm{algebraic data type} (ADT) is a composite type, \ie, a type formed by combining other types.
15Three common classes of algebraic types are \Newterm{array type}, \ie homogeneous types, \Newterm{product type}, \ie heterogeneous tuples and records (structures), and \Newterm{sum type}, \ie tagged product-types (unions).
16Enumerated types are a special case of product/sum types with non-mutable fields, \ie initialized (constructed) once at the type's declaration, possible restricted to compile-time initialization.
17Values of algebraic types are access by subscripting, field qualification, or type (pattern) matching.
18\end{comment}
19
20Enumeration types exist in many popular programming languages, both past and present, \eg Pascal~\cite{Pascal}, Ada~\cite{Ada}, \Csharp~\cite{Csharp}, OCaml~\cite{OCaml} \CC, Go~\cite{Go}, Java~\cite{Java}, Modula-3~\cite{Modula-3}, Rust~\cite{Rust}, Swift~\cite{Swift}, Python~\cite{Python}.
21Among theses languages, there are a large set of overlapping features, but each language has its own unique extensions and restrictions.
22
23\section{Pascal}
24\label{s:Pascal}
25\lstnewenvironment{pascal}[1][]{\lstset{language=pascal,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
26
27Classic Pascal has the \lstinline[language=pascal]{const} declaration binding a name to a constant literal/expression.
28\begin{pascal}
29const one = 0 + 1;   Vowels = set of (A,E,I,O,U);   NULL = NIL;
30                 PI = 3.14159;   Plus = '+';   Fred = 'Fred';
31\end{pascal}
32This mechanism is not an enumeration because there is no specific type (pseudo enumeration).
33Hence, there is no notion of a (possibly ordered) set, modulo the \lstinline[language=pascal]{set of} type.
34The type of each constant name (enumerator) is inferred from the constant-expression type.
35
36Free Pascal~\cite[\S~3.1.1]{FreePascal} is a modern, object-oriented version of classic Pascal, with a C-style enumeration type.
37Enumerators must be assigned in ascending numerical order with a constant expression and the range can be non-consecutive.
38\begin{pascal}
39Type EnumType = ( one, two, three, forty @= 40@, fortyone );
40\end{pascal}
41Pseudo-functions @Pred@ and @Succ@ can only be used if the range is consecutive.
42The underlying type is an implementation-defined integral-type large enough to hold all enumerated values; it does not have to be the smallest possible type.
43The integral size can be explicitly specified using compiler directive @$PACKENUM@~$N$, where $N$ is the number of bytes, \eg:
44\begin{pascal}
45Type @{$\color{red}\$$PACKENUM 1}@ SmallEnum = ( one, two, three );
46            @{$\color{red}\$$PACKENUM 4}@ LargeEnum = ( BigOne, BigTwo, BigThree );
47Var S : SmallEnum; { 1 byte }
48          L : LargeEnum; { 4 bytes}
49\end{pascal}
50
51
52\section{Ada}
53\lstnewenvironment{ada}[1][]{\lstset{language=[2005]Ada,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},literate={'}{\ttfamily'\!}1}\lstset{#1}}{}
54
55An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators).
56\begin{ada}
57type RGB is ( Red, Green, Blue ); -- 3 literals (enumerators)
58\end{ada}
59Object initialization and assignment are restricted to the enumerators of this type.
60Enumerators without an explicitly designated constant value are auto-initialized: from left to right, starting at zero or the next explicitly initialized constant, incrementing by 1.
61To explicitly set enumerator values, \emph{all} enumerators must be set in \emph{ascending} order, \ie there is no auto-initialization.
62\begin{ada}
63type RGB is ( Red, Green, Blue );
64@for RGB use ( Red => 10, Green => 20, Blue => 30 );@ -- ascending order
65\end{ada}
66Hence, the position, value, label tuples are:
67\begin{ada}
68(0, 10, RED)  (1, 20, GREEN)  (2, 30, BLUE) 
69\end{ada}
70Note, Ada is case-\emph{insensitive} so names may appear in multiple forms and still be the same, \eg @Red@ and @RED@ (a questionable design decision).
71
72Like C, Ada enumerators are unscoped, \ie enumerators declared inside of an enum are visible (projected) into the enclosing scope.
73The enumeration operators are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of enumerators, which is always ascending.
74
75Ada enumerators are overloadable.
76\begin{ada}
77type Traffic_Light is ( @Red@, Yellow, @Green@ );
78\end{ada}
79Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded names.
80\VRef[Figure]{f:AdaEnumeration} shows how ambiguity is handled using a cast, \ie \lstinline[language=ada]{RGB'(Red)}.
81
82\begin{figure}
83\begin{ada}
84with Ada.Text_IO; use Ada.Text_IO;
85procedure test is
86        type RGB is ( @Red@, Green, Blue );
87        type Traffic_Light is ( @Red@, Yellow, Green );         -- overload
88        procedure @Red@( Colour : RGB ) is begin            -- overload
89                Put_Line( "Colour is " & RGB'Image( Colour ) );
90        end Red;
91        procedure @Red@( TL : Traffic_Light ) is begin       -- overload
92                Put_Line( "Light is " & Traffic_Light'Image( TL ) );
93        end Red;
94begin
95        @Red@( Blue );                           -- RGB
96        @Red@( Yellow );                                -- Traffic_Light
97        @Red@( @RGB'(Red)@ );           -- ambiguous without cast
98end test;
99\end{ada}
100\caption{Ada Enumeration Overload Resolution}
101\label{f:AdaEnumeration}
102\end{figure}
103
104Ada provides an alias mechanism, \lstinline[language=ada]{renames}, for aliasing types, which is useful to shorten package names.
105\begin{ada}
106OtherRed : RGB renames Red;
107\end{ada}
108which suggests a possible \CFA extension to @typedef@.
109\begin{cfa}
110typedef RGB.Red OtherRed;
111\end{cfa}
112
113There are three pairs of inverse enumeration pseudo-functions (attributes): @'Pos@ and @'Val@, @'Enum_Rep@ and @'Enum_Val@, and @'Image@ and @'Value@,
114\begin{cquote}
115\lstDeleteShortInline@
116\setlength{\tabcolsep}{15pt}
117\begin{tabular}{@{}ll@{}}
118\begin{ada}
119RGB'Pos( Red ) = 0;
120RGB'Enum_Rep( Red ) = 10;
121RGB'Image( Red ) = "RED";
122\end{ada}
123&
124\begin{ada}
125RGB'Val( 0 ) = Red
126RGB'Enum_Val( 10 ) =  Red
127RGB'Value( "Red" ) =  Red
128\end{ada}
129\end{tabular}
130\lstMakeShortInline@
131\end{cquote}
132These attributes are important for IO.
133An enumeration type @T@ also has the following attributes: @T'First@, @T'Last@, @T'Range@, @T'Pred@, @T'Succ@, @T'Min@, and @T'Max@, producing an intuitive result based on the attribute name.
134
135Ada allows the enumerator label to be a character constant.
136\begin{ada}
137type Operator is ( '+', '-', '*', '/' );
138\end{ada}
139which is syntactic sugar for the label and not character literals from the predefined type @Character@.
140The purpose is strictly readability using character literals rather than names.
141\begin{ada}
142Op : Operator := '+';
143if Op = '+' or else Op = '-' then ... ;
144elsif Op = '*' or else Op = '/' then ... ; end if;
145\end{ada}
146Interestingly, arrays of character enumerators can be treated as strings.
147\begin{ada}
148Ops : array( 0..3 ) of Operator;
149Ops := @"+-*/"@;            -- string assignment to array elements
150Ops := @"+-" & "*/"@;   -- string concatenation and assignment
151\end{ada}
152Ada's @Character@ type is defined as a character enumeration across all Latin-1 characters.
153
154Ada's boolean type is also a special enumeration, which can be used in conditions.
155\begin{ada}
156type Boolean is (False, True); -- False / True not keywords
157@Flag@ : Boolean;
158if @Flag@ then ...    -- conditional
159\end{ada}
160Since only types derived from @Boolean@ can be a conditional, @Boolean@ is essentially  a builtin type.
161
162Ada provides \emph{consecutive} subtyping of an enumeration using \lstinline[language=ada]{range}.
163\begin{ada}
164type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun );
165subtype Weekday is Week @range Mon .. Fri@;
166subtype Weekend is Week @range Sat .. Sun@;
167Day : Week;
168\end{ada}
169Hence, the ordering of the enumerators is crucial to provide the necessary ranges.
170
171An enumeration type can be used in the Ada \lstinline[language=ada]{case} (all enumerators must appear or a default) or iterating constructs.
172\begin{cquote}
173\lstDeleteShortInline@
174\setlength{\tabcolsep}{15pt}
175\begin{tabular}{@{}ll@{}}
176\begin{ada}
177case Day is
178        when @Mon .. Fri@ => ... ;
179        when @Sat .. Sun@ => ... ;
180end case;
181\end{ada}
182&
183\begin{ada}
184case Day is
185        when @Weekday@ => ... ;  -- subtype ranges
186        when @Weekend@ => ... ;
187end case;
188\end{ada}
189\end{tabular}
190\end{cquote}
191
192\begin{cquote}
193\setlength{\tabcolsep}{12pt}
194\begin{tabular}{@{}lll@{}}
195\begin{ada}
196for Day in @Mon .. Sun@ loop
197        ...
198end loop;
199\end{ada}
200&
201\begin{ada}
202for Day in @Weekday@ loop
203        ...
204end loop;
205\end{ada}
206&
207\begin{ada}
208for Day in @Weekend@ loop
209        ...
210end loop;
211\end{ada}
212\end{tabular}
213\lstMakeShortInline@
214\end{cquote}
215
216An enumeration type can be used as an array dimension and subscript.
217\begin{ada}
218Lunch : array( @Week@ ) of Time;
219for Day in Week loop
220        Lunch( @Day@ ) := ... ;       -- set lunch time
221end loop;
222\end{ada}
223
224
225\section{\CC}
226\label{s:C++RelatedWork}
227\lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
228
229\CC has the equivalent of Pascal typed @const@ declarations \see{\VRef{s:Pascal}}, with static and dynamic initialization.
230\begin{c++}
231const auto one = 0 + 1;                                 $\C{// static intialization}$
232const auto NULL = nullptr;
233const auto PI = 3.14159;
234const auto Plus = '+';
235const auto Fred = "Fred";
236const auto Mon = 0, Tue = Mon + 1, Wed = Tue + 1, Thu = Wed + 1, Fri = Thu + 1,
237                                Sat = Fri + 1, Sun = Sat + 1;
238int sa[Sun];
239const auto r = random();                                $\C{// dynamic intialization}$
240int da[r];                                                              $\C{// VLA}$
241\end{c++}
242Statically initialized identifiers may appear in any constant-expression context, \eg @case@.
243Dynamically intialized identifiers may appear as array dimensions in @g++@, which allows variable-sized arrays.
244Interestingly, global \CC @const@ declarations are implicitly marked @static@ (@r@ rather than @R@).
245\begin{c++}
246$\$$ nm test.o
2470000000000000018 @r@ Mon
248\end{c++}
249
250\CC enumeration is largely backwards compatible with C, so it inherited C's enumerations.
251However, the following non-backwards compatible changes are made.
252
253\begin{cquote}
2547.2 Change: \CC objects of enumeration type can only be assigned values of the same enumeration type.
255In C, objects of enumeration type can be assigned values of any integral type. \\
256Example:
257\begin{c++}
258enum color { red, blue, green };
259color c = 1;                                                    $\C{// valid C, invalid C++}$
260\end{c++}
261\textbf{Rationale}: The type-safe nature of \CC. \\
262\textbf{Effect on original feature}: Deletion of semantically well-defined feature. \\
263\textbf{Difficulty of converting}: Syntactic transformation. (The type error produced by the assignment can be automatically corrected by applying an explicit cast.) \\
264\textbf{How widely used}: Common.
265\end{cquote}
266
267\begin{cquote}
2687.2 Change: In \CC, the type of an enumerator is its enumeration.
269In C, the type of an enumerator is @int@. \\
270Example:
271\begin{c++}
272enum e { A };
273sizeof(A) == sizeof(int)                                $\C{// in C}$
274sizeof(A) == sizeof(e)                                  $\C{// in C++}$
275/* and sizeof(int) is not necessary equal to sizeof(e) */
276\end{c++}
277\textbf{Rationale}: In \CC, an enumeration is a distinct type. \\
278\textbf{Effect on original feature}: Change to semantics of well-defined feature. \\
279\textbf{Difficulty of converting}: Semantic transformation. \\
280\textbf{How widely used}: Seldom. The only time this affects existing C code is when the size of an enumerator is taken.
281Taking the size of an enumerator is not a common C coding practice.
282\end{cquote}
283
284Hence, the values in a \CC enumeration can only be its enumerators (without a cast).
285While the storage size of an enumerator is up to the compiler, there is still an implicit cast to @int@.
286\begin{c++}
287enum E { A, B, C };
288E e = A;
289int i = A;    i = e;                                    $\C{// implicit casts to int}$
290\end{c++}
291\CC{11} added a scoped enumeration, \lstinline[language=c++]{enum class} (or \lstinline[language=c++]{enum struct}), where the enumerators are accessed using type qualification.
292\begin{c++}
293enum class E { A, B, C };
294E e = @E::@A;                                                   $\C{// qualified enumerator}$
295e = B;                                                                  $\C{// error: B not in scope}$
296\end{c++}
297\CC{20} supports explicit unscoping with a \lstinline[language=c++]{using enum} declaration.
298\begin{c++}
299enum class E { A, B, C };
300@using enum E;@
301E e = A;    e = B;                                              $\C{// direct access}$
302\end{c++}
303\CC{11} added the ability to explicitly declare the underlying \emph{integral} type for \lstinline[language=c++]{enum class}.
304\begin{c++}
305enum class RGB @: long@ { Red, Green, Blue };
306enum class rgb @: char@ { Red = 'r', Green = 'g', Blue = 'b' };
307enum class srgb @: signed char@ { Red = -1, Green = 0, Blue = 1 };
308\end{c++}
309There is no implicit conversion from the \lstinline[language=c++]{enum class} type to its declared type.
310\begin{c++}
311rgb crgb = rgb::Red;
312char ch = rgb::Red;   ch = crgb;                $\C{// error}$
313\end{c++}
314Finally, enumerations can be used in the @switch@ statement but there is no mechanism to iterate through an enumeration.
315An enumeration type cannot declare an array dimension but can be used as a subscript.
316There is no mechanism to subtype or inherit from enumerations.
317
318
319\section{C\raisebox{-0.7ex}{\LARGE$^\sharp$}\xspace} % latex bug: cannot use \relsize{2} so use \LARGE
320\label{s:Csharp}
321\lstnewenvironment{csharp}[1][]{\lstset{language=[Sharp]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
322
323% https://www.tutorialsteacher.com/codeeditor?cid=cs-mk8Ojx
324
325\Csharp is a dynamically-typed programming-language with a scoped, integral enumeration-type similar to the C/\CC enumeration.
326\begin{csharp}
327enum Weekday : byte { Mon, Tue, Wed, Thu@ = 10@, Fri, Sat, Sun@,@ };
328\end{csharp}
329The default underlying type is @int@, with auto-incrementing, implicit/explicit initialization, terminator comma, and optional integral typing (default @int@).
330A method cannot be defined in an enumeration type.
331As well, there is an explicit bidirectional conversion between an enumeration and its integral type, and an implicit conversion to the enumerator label in display contexts.
332\begin{csharp}
333int day = (int)Weekday.Fri;             $\C{// day == 10}$
334Weekday weekday = (Weekdays)42;         $\C{// weekday == 42, logically invalid}$
335Console.WriteLine( Weekday.Fri ); $\C{// print Fri}$
336string mon = Weekday.Mon.ToString(); $\C{// mon == "Mon"}$
337\end{csharp}
338
339The @Enum.GetValues@ pseudo-method retrieves an array of the enumeration constants for looping over an enumeration type or variable (expensive operation).
340\begin{csharp}
341foreach ( Weekday constant in @Enum.GetValues@( typeof(Weekday) ) ) {
342        Console.WriteLine( constant + " " + (int)constant ); // label, position
343}
344\end{csharp}
345
346The @Flags@ attribute creates a bit-flags enumeration, allowing bitwise operators @&@, @|@, @~@ (complement), @^@ (xor).
347\begin{csharp}
348@[Flags]@ public enum Weekday {
349        None = 0x0, Mon = 0x1, Tue = 0x2, Wed = 0x4,
350        Thu = 0x8, Fri = 0x10, Sat = 0x20, Sun = 0x40,
351        Weekend = @Sat | Sun@,
352        Weekdays = @Mon | Tue | Wed | Thu | Fri@
353}
354Weekday meetings = @Weekday.Mon | Weekday.Wed@; // 0x5
355\end{csharp}
356
357\VRef[Figure]{CsharpFreeVersusClass} shows an enumeration with free routines for manipulation, and embedding the enumeration and operations into an enumeration class.
358The key observation is that an enumeration class is just a structuring mechanism without any additional semantics.
359
360% https://learn.microsoft.com/en-us/dotnet/api/system.enum?view=net-8.0
361
362\begin{figure}
363\centering
364\lstDeleteShortInline@
365\begin{tabular}{@{}l|l@{}}
366\multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
367\hline
368\begin{csharp}
369public class Program {
370
371        enum Weekday {
372                Mon, Tue, Wed, Thu, Fri, Sat, Sun };
373
374        static bool isWeekday( Weekday wd ) {
375                return wd <= Weekday.Fri;
376        }
377        static bool isWeekend( Weekday wd ) {
378                return Weekday.Sat <= wd;
379        }
380
381
382        public static void Main() {
383                Weekday day = Weekday.Sat;
384
385                Console.WriteLine( isWeekday( day ) );
386                Console.WriteLine( isWeekend( day ) );
387        }
388}
389\end{csharp}
390&
391\begin{csharp}
392public class Program {
393        public @class@ WeekDay : Enumeration {
394                public enum Day {
395                                Mon, Tue, Wed, Thu, Fri, Sat, Sun };
396                public enum Day2 : Day {
397                                XXX, YYY };
398                Day day;
399                public bool isWeekday() {
400                        return day <= Day.Fri;
401                }
402                public bool isWeekend() {
403                        return day > Day.Fri;
404                }
405                public WeekDay( Day d ) { day = d; }
406        }
407        public static void Main() {
408                WeekDay cday = new
409                                WeekDay( WeekDay.Day.Sat );
410                Console.WriteLine( cday.isWeekday() );
411                Console.WriteLine( cday.isWeekend() );
412        }
413}
414\end{csharp}
415\end{tabular}
416\lstMakeShortInline@
417\caption{\Csharp: Free Routine Versus Class Enumeration}
418\label{CsharpFreeVersusClass}
419\end{figure}
420
421
422\section{Golang}
423\lstnewenvironment{Go}[1][]{\lstset{language=Go,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
424
425Golang provides pseudo-enumeration similar to classic Pascal \lstinline[language=pascal]{const}, binding a name to a constant literal/expression.
426\begin{Go}
427const ( R = 0; G; B )                                   $\C{// implicit: 0 0 0}$
428const ( Fred = "Fred"; Mary = "Mary"; Jane = "Jane" ) $\C{// explicit: Fred Mary Jane}$
429const ( S = 0; T; USA = "USA"; U; V = 3.1; W ) $\C{// type change, implicit/explicit: 0 0 USA USA 3.1 3.1}$
430\end{Go}
431Constant names are unscoped and must be unique (no overloading).
432The first enumerator \emph{must} be explicitly initialized;
433subsequent enumerators can be implicitly or explicitly initialized.
434Implicit initialization is the previous (predecessor) enumerator value.
435
436Auto-incrementing is supported by the keyword \lstinline[language=Go]{iota}, available only in the \lstinline[language=Go]{const} declaration.
437The \lstinline[language=Go]{iota} is a \emph{per \lstinline[language=golang]{const} declaration} integer counter, starting at zero and implicitly incremented by one for each \lstinline[language=golang]{const} identifier (enumerator).
438\begin{Go}
439const ( R = @iota@; G; B )                              $\C{// implicit: 0 1 2}$
440const ( C = @iota + B + 1@; G; Y )              $\C{// implicit: 3 4 5}$
441\end{Go}
442An underscore \lstinline[language=golang]{const} identifier advances \lstinline[language=Go]{iota}.
443\begin{Go}
444const ( O1 = iota + 1; @_@; O3; @_@; O5 ) // 1, 3, 5 
445\end{Go}
446Auto-incrementing stops after an explicit initialization.
447\begin{Go}
448const ( Mon = iota; Tue; Wed; // 0, 1, 2
449        @Thu = 10@; Fri; Sat; Sun ) // 10, 10, 10, 10
450\end{Go}
451Auto-incrementing can be restarted with an expression containing \emph{one} \lstinline[language=Go]{iota}.
452\begin{Go}
453const ( V1 = iota; V2; @V3 = 7;@ V4 = @iota@; V5 ) // 0 1 7 3 4
454const ( Mon = iota; Tue; Wed; // 0, 1, 2
455        @Thu = 10;@ Fri = @iota - Wed + Thu - 1@; Sat; Sun ) // 10, 11, 12, 13
456\end{Go}
457Note, \lstinline[language=Go]{iota} is advanced for an explicitly initialized enumerator, like the underscore @_@ identifier.
458
459Basic switch and looping are possible.
460\begin{cquote}
461\lstDeleteShortInline@
462\setlength{\tabcolsep}{15pt}
463\begin{tabular}{@{}ll@{}}
464\begin{Go}
465day := Mon;
466switch day {
467  case Mon, Tue, Wed, Thu, Fri:
468        fmt.Println( "weekday" );
469  case Sat, Sun:
470        fmt.Println( "weekend" );
471}
472\end{Go}
473&
474\begin{Go}
475
476for i := Mon; i <= Sun; i += 1 {
477        fmt.Println( i )
478}
479
480
481
482\end{Go}
483\end{tabular}
484\lstMakeShortInline@
485\end{cquote}
486However, the loop prints the values from 0 to 13 because there is no actual enumeration.
487
488
489\section{Java}
490\lstnewenvironment{Java}[1][]{\lstset{language=Java,morekeywords={enum,assert,strictfp},
491        escapechar=\$,moredelim=**[is][\color{red}]{!}{!},}\lstset{#1}}{}
492
493Every enumeration in Java is an enumeration class.
494For a basic enumeration
495\begin{Java}
496enum Weekday { Mon, Tue, Wed, Thu, Fri, Sat, Sun };
497Weekday day = Weekday.Sat;
498\end{Java}
499the scoped enumerators are an ordered list of @final@ methods of type integer, ordered left to right starting at 0, increasing by 1.
500The value of an enumeration instance is restricted to the enumeration's enumerators.
501There is an implicit @int@ variable in the enumeration used to store the value of an enumeration instance.
502The position (ordinal) and label are accessible, where the value is the same as the position.
503\begin{Java}
504System.out.println( day.!ordinal()! + " " + day.!name()! ); // 5 Sat
505\end{Java}
506There is an inverse function @valueOf@ from string to enumerator.
507\begin{Java}
508day = Weekday.valueOf( "Wed" );
509\end{Java}
510There are no implicit conversions to/from an enumerator and its underlying type.
511Like \Csharp, \VRef[Figure]{f:JavaFreeVersusClass} shows the same example for an enumeration with free routines for manipulation, and embedding the enumeration and operations into an enumeration class.
512
513\begin{figure}
514\centering
515\lstDeleteShortInline@
516\begin{tabular}{@{}l|l@{}}
517\multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
518\hline
519\begin{Java}
520enum Weekday !{!
521        Mon, Tue, Wed, Thu, Fri, Sat, Sun !}!;
522
523static boolean isWeekday( Weekday wd ) {
524        return wd.ordinal() <= Weekday.Fri.ordinal();
525}
526static boolean isWeekend( Weekday wd ) {
527        return Weekday.Fri.ordinal() < wd.ordinal();
528}
529
530public static void main( String[] args ) {
531        Weekday day = Weekday.Sat;
532        System.out.println( isWeekday( day ) );
533        System.out.println( isWeekend( day ) );
534}
535\end{Java}
536&
537\begin{Java}
538enum Weekday !{!
539        Mon, Tue, Wed, Thu, Fri, Sat, Sun;
540
541        public boolean isWeekday() {
542                return ordinal() <= Weekday.Fri.ordinal();
543        }
544        public boolean isWeekend() {
545                return Weekday.Fri.ordinal() < ordinal();
546        }
547!}!
548public static void main( String[] args ) {
549        WeekDay day = WeekDay.Sat;
550        System.out.println( day.isWeekday() );
551        System.out.println( day.isWeekend() );
552}
553\end{Java}
554\end{tabular}
555\lstMakeShortInline@
556\caption{Java: Free Routine Versus Class Enumeration}
557\label{f:JavaFreeVersusClass}
558\end{figure}
559
560To explicitly assign enumerator values and/or use a non-@int@ enumeration type (any Java type may be used), the enumeration must specify an explicit type in the enumeration class and a constructor.
561\begin{Java}
562enum Weekday {
563        Mon!(1)!, Tue!(2)!, Wed!(3)!, Thu!(4)!, Fri!(5)!, Sat!(6)!, Sun!(7)!; // must appear first
564        private !long! day;                                     $\C{// underlying enumeration type}$
565        private Weekday( !long! d ) { day = d; } $\C{// used to initialize enumerators}$
566};
567Weekday day = Weekday.Sat;
568\end{Java}
569If an enumerator initialization is a runtime expression, the expression is executed once at the point the enumeration is declaraed.
570
571The position, value, and label are accessible.
572\begin{Java}
573System.out.println( !day.ordinal()! + " " + !day.day! + " " + !day.name()! )// 5 6 Sat
574\end{Java}
575The constructor is private so only initialization or assignment can be used to set an enumeration, which ensures only corresponding enumerator values are allowed.
576
577An enumeration can appear in a @switch@ statement, but no ranges.
578\begin{Java}
579switch ( day ) {
580  case Mon: case Tue: case Wed: case Thu: case Fri:
581        System.out.println( "weekday" );
582        break;
583  case Sat: case Sun:
584        System.out.println( "weekend" );
585        break;
586}
587\end{Java}
588Like \Csharp, looping over an enumeration is done using method @values@, which returns the array of enumerator values (expensive operation).
589\begin{Java}
590for ( Weekday iday : Weekday.values() ) {
591        System.out.print( iday.ordinal() + iday.day + " " +  iday.name() + ",  " );
592}
5930 1 Mon,  1 2 Tue,  2 3 Wed,  3 4 Thu,  4 5 Fri,  5 6 Sat,  6 7 Sun, 
594\end{Java}
595
596As well, Java provides an @EnumSet@ where the underlying type is an efficient set of bits, one per enumeration \see{\Csharp \lstinline{Flags}, \VRef{s:Csharp}}, providing (logical) operations on groups of enumerators.
597There is also a specialized version of @HashMap@ with enumerator keys, which has performance benefits.
598
599Enumeration inheritence is disallowed because an enumeration is @final@.
600
601
602
603\section{Modula-3}
604
605
606
607\section{Rust}
608\lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
609
610Enumerations
611\begin{rust}
612        Syntax
613        Enumeration :
614           enum IDENTIFIER  GenericParams? WhereClause? { EnumItems? }
615
616        EnumItems :
617           EnumItem ( , EnumItem )* ,?
618
619        EnumItem :
620           OuterAttribute* Visibility?
621           IDENTIFIER ( EnumItemTuple | EnumItemStruct )? EnumItemDiscriminant?
622
623        EnumItemTuple :
624           ( TupleFields? )
625
626        EnumItemStruct :
627           { StructFields? }
628
629        EnumItemDiscriminant :
630           = Expression
631\end{rust}
632An enumeration, also referred to as an enum, is a simultaneous definition of a nominal enumerated type as well as a set of constructors, that can be used to create or pattern-match values of the corresponding enumerated type.
633
634Enumerations are declared with the keyword enum.
635
636An example of an enum item and its use:
637\begin{rust}
638enum Animal {
639        Dog,
640        Cat,
641}
642
643let mut a: Animal = Animal::Dog;
644a = Animal::Cat;
645\end{rust}
646Enum constructors can have either named or unnamed fields:
647\begin{rust}
648enum Animal {
649        Dog(String, f64),
650        Cat { name: String, weight: f64 },
651}
652
653let mut a: Animal = Animal::Dog("Cocoa".to_string(), 37.2);
654a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };
655\end{rust}
656In this example, Cat is a struct-like enum variant, whereas Dog is simply called an enum variant.
657
658An enum where no constructors contain fields are called a field-less enum. For example, this is a fieldless enum:
659\begin{rust}
660enum Fieldless {
661        Tuple(),
662        Struct{},
663        Unit,
664}
665\end{rust}
666If a field-less enum only contains unit variants, the enum is called an unit-only enum. For example:
667\begin{rust}
668enum Enum {
669        Foo = 3,
670        Bar = 2,
671        Baz = 1,
672}
673\end{rust}
674
675\subsection{Discriminants}
676
677Each enum instance has a discriminant: an integer logically associated to it that is used to determine which variant it holds.
678
679Under the default representation, the discriminant is interpreted as an isize value. However, the compiler is allowed to use a smaller type (or another means of distinguishing variants) in its actual memory layout.
680
681\subsection{Assigning discriminant values}
682
683\subsection{Explicit discriminants}
684
685In two circumstances, the discriminant of a variant may be explicitly set by following the variant name with = and a constant expression:
686
687        if the enumeration is "unit-only".
688
689        if a primitive representation is used. For example:
690\begin{rust}
691        #[repr(u8)]
692        enum Enum {
693                Unit = 3,
694                Tuple(u16),
695                Struct {
696                        a: u8,
697                        b: u16,
698                } = 1,
699        }
700\end{rust}
701
702\subsection{Implicit discriminants}
703
704If a discriminant for a variant is not specified, then it is set to one higher than the discriminant of the previous variant in the declaration. If the discriminant of the first variant in the declaration is unspecified, then it is set to zero.
705\begin{rust}
706enum Foo {
707        Bar,                    // 0
708        Baz = 123,        // 123
709        Quux,              // 124
710}
711
712let baz_discriminant = Foo::Baz as u32;
713assert_eq!(baz_discriminant, 123);
714\end{rust}
715
716\subsection{Restrictions}
717
718It is an error when two variants share the same discriminant.
719\begin{rust}
720enum SharedDiscriminantError {
721        SharedA = 1,
722        SharedB = 1
723}
724
725enum SharedDiscriminantError2 {
726        Zero,      // 0
727        One,            // 1
728        OneToo = 1  // 1 (collision with previous!)
729}
730\end{rust}
731It is also an error to have an unspecified discriminant where the previous discriminant is the maximum value for the size of the discriminant.
732\begin{rust}
733#[repr(u8)]
734enum OverflowingDiscriminantError {
735        Max = 255,
736        MaxPlusOne // Would be 256, but that overflows the enum.
737}
738
739#[repr(u8)]
740enum OverflowingDiscriminantError2 {
741        MaxMinusOne = 254, // 254
742        Max,                       // 255
743        MaxPlusOne               // Would be 256, but that overflows the enum.
744}
745\end{rust}
746
747\subsection{Accessing discriminant}
748
749\begin{rust}
750Via mem::discriminant
751\end{rust}
752@mem::discriminant@ returns an opaque reference to the discriminant of an enum value which can be compared. This cannot be used to get the value of the discriminant.
753
754\subsection{Casting}
755
756If an enumeration is unit-only (with no tuple and struct variants), then its discriminant can be directly accessed with a numeric cast; e.g.:
757\begin{rust}
758enum Enum {
759        Foo,
760        Bar,
761        Baz,
762}
763
764assert_eq!(0, Enum::Foo as isize);
765assert_eq!(1, Enum::Bar as isize);
766assert_eq!(2, Enum::Baz as isize);
767\end{rust}
768Field-less enums can be casted if they do not have explicit discriminants, or where only unit variants are explicit.
769\begin{rust}
770enum Fieldless {
771        Tuple(),
772        Struct{},
773        Unit,
774}
775
776assert_eq!(0, Fieldless::Tuple() as isize);
777assert_eq!(1, Fieldless::Struct{} as isize);
778assert_eq!(2, Fieldless::Unit as isize);
779\end{rust}
780\begin{rust}
781#[repr(u8)]
782enum FieldlessWithDiscrimants {
783        First = 10,
784        Tuple(),
785        Second = 20,
786        Struct{},
787        Unit,
788}
789
790assert_eq!(10, FieldlessWithDiscrimants::First as u8);
791assert_eq!(11, FieldlessWithDiscrimants::Tuple() as u8);
792assert_eq!(20, FieldlessWithDiscrimants::Second as u8);
793assert_eq!(21, FieldlessWithDiscrimants::Struct{} as u8);
794assert_eq!(22, FieldlessWithDiscrimants::Unit as u8);
795\end{rust}
796
797\subsection{Pointer casting}
798
799If the enumeration specifies a primitive representation, then the discriminant may be reliably accessed via unsafe pointer casting:
800\begin{rust}
801#[repr(u8)]
802enum Enum {
803        Unit,
804        Tuple(bool),
805        Struct{a: bool},
806}
807
808impl Enum {
809        fn discriminant(&self) -> u8 {
810                unsafe { *(self as *const Self as *const u8) }
811        }
812}
813
814let unit_like = Enum::Unit;
815let tuple_like = Enum::Tuple(true);
816let struct_like = Enum::Struct{a: false};
817
818assert_eq!(0, unit_like.discriminant());
819assert_eq!(1, tuple_like.discriminant());
820assert_eq!(2, struct_like.discriminant());
821\end{rust}
822
823\subsection{Zero-variant enums}
824
825Enums with zero variants are known as zero-variant enums. As they have no valid values, they cannot be instantiated.
826\begin{rust}
827enum ZeroVariants {}
828\end{rust}
829Zero-variant enums are equivalent to the never type, but they cannot be coerced into other types.
830\begin{rust}
831let x: ZeroVariants = panic!();
832let y: u32 = x; // mismatched type error
833\end{rust}
834
835\subsection{Variant visibility}
836
837Enum variants syntactically allow a Visibility annotation, but this is rejected when the enum is validated. This allows items to be parsed with a unified syntax across different contexts where they are used.
838\begin{rust}
839macro_rules! mac_variant {
840        ($vis:vis $name:ident) => {
841                enum $name {
842                        $vis Unit,
843
844                        $vis Tuple(u8, u16),
845
846                        $vis Struct { f: u8 },
847                }
848        }
849}
850
851// Empty `vis` is allowed.
852mac_variant! { E }
853
854// This is allowed, since it is removed before being validated.
855#[cfg(FALSE)]
856enum E {
857        pub U,
858        pub(crate) T(u8),
859        pub(super) T { f: String }
860}
861\end{rust}
862
863
864\section{Swift}
865\lstnewenvironment{swift}[1][]{\lstset{language=Swift,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
866
867% https://www.programiz.com/swift/online-compiler
868
869A Swift enumeration provides a heterogenous set of enumerators, like a tagged @union@, where the field name is the enumerator and its list of type parameters form its type.
870\begin{swift}
871enum Many {
872        case Mon, Tue, Wed, Thu, Fri, Sat, Sun // basic enumerator
873        case code( String ) // string enumerator
874        case tuple( Int, Int, Int ) // tuple enumerator
875};
876var day = Many.Sat; // qualification to resolve type
877print( day );
878day = .Wed // no qualification after type resolved
879print( day );
880day = .code( "ABC" );
881print( day );
882day = .tuple( 1, 2, 3 );
883print( day );
884
885Sat
886Wed
887code("ABC")
888tuple(1, 2, 3)
889\end{swift}
890
891
892An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code.
893
894If you are familiar with C, you will know that C enumerations assign related names to a set of integer values.
895Enumerations in Swift are much more flexible, and don't have to provide a value for each case of the enumeration.
896If a value (known as a raw value) is provided for each enumeration case, the value can be a string, a character, or a value of any integer or floating-point type.
897
898Alternatively, enumeration cases can specify associated values of any type to be stored along with each different case value, much as unions or variants do in other languages.
899You can define a common set of related cases as part of one enumeration, each of which has a different set of values of appropriate types associated with it.
900
901Enumerations in Swift are first-class types in their own right.
902They adopt many features traditionally supported only by classes, such as computed properties to provide additional information about the enumeration's current value, and instance methods to provide functionality related to the values the enumeration represents.
903Enumerations can also define initializers to provide an initial case value;
904can be extended to expand their functionality beyond their original implementation; and can conform to protocols to provide standard functionality.
905
906For more about these capabilities, see Properties, Methods, Initialization, Extensions, and Protocols.
907
908\paragraph{Enumeration Syntax}
909
910
911Note:
912Swift enumeration cases don't have an integer value set by default, unlike languages like C and Objective-C.
913In the CompassPoint example above, @north@, @south@, @east@ and @west@ don't implicitly equal 0, 1, 2 and 3.
914Instead, the different enumeration cases are values in their own right, with an explicitly defined type of CompassPoint.
915
916Multiple cases can appear on a single line, separated by commas:
917\begin{swift}
918enum Planet {
919        case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
920}
921\end{swift}
922Each enumeration definition defines a new type.
923Like other types in Swift, their names (such as @CompassPoint@ and @Planet@) start with a capital letter.
924Give enumeration types singular rather than plural names, so that they read as self-evident:
925\begin{swift}
926var directionToHead = CompassPoint.west
927\end{swift}
928The type of @directionToHead@ is inferred when it's initialized with one of the possible values of @CompassPoint@.
929Once @directionToHead@ is declared as a @CompassPoint@, you can set it to a different @CompassPoint@ value using a shorter dot syntax:
930\begin{swift}
931directionToHead = .east
932\end{swift}
933The type of @directionToHead@ is already known, and so you can drop the type when setting its value.
934This makes for highly readable code when working with explicitly typed enumeration values.
935
936\paragraph{Matching Enumeration Values with a Switch Statement}
937
938You can match individual enumeration values with a switch statement:
939\begin{swift}
940directionToHead = .south
941switch directionToHead {
942case .north:
943        print("Lots of planets have a north")
944case .south:
945        print("Watch out for penguins")
946case .east:
947        print("Where the sun rises")
948case .west:
949        print("Where the skies are blue")
950}
951// Prints "Watch out for penguins"
952\end{swift}
953You can read this code as:
954\begin{quote}
955"Consider the value of directionToHead.
956In the case where it equals @.north@, print "Lots of planets have a north".
957In the case where it equals @.south@, print "Watch out for penguins"."
958
959...and so on.
960\end{quote}
961As described in Control Flow, a switch statement must be exhaustive when considering an enumeration's cases.
962If the case for @.west@ is omitted, this code doesn't compile, because it doesn't consider the complete list of @CompassPoint@ cases.
963Requiring exhaustiveness ensures that enumeration cases aren't accidentally omitted.
964
965When it isn't appropriate to provide a case for every enumeration case, you can provide a default case to cover any cases that aren't addressed explicitly:
966\begin{swift}
967let somePlanet = Planet.earth
968switch somePlanet {
969case .earth:
970        print("Mostly harmless")
971default:
972        print("Not a safe place for humans")
973}
974// Prints "Mostly harmless"
975\end{swift}
976
977\paragraph{Iterating over Enumeration Cases}
978
979For some enumerations, it's useful to have a collection of all of that enumeration's cases.
980You enable this by writing @CaseIterable@ after the enumeration's name.
981Swift exposes a collection of all the cases as an allCases property of the enumeration type.
982Here's an example:
983\begin{swift}
984enum Beverage: CaseIterable {
985        case coffee, tea, juice
986}
987let numberOfChoices = Beverage.allCases.count
988print("\(numberOfChoices) beverages available")
989// Prints "3 beverages available"
990\end{swift}
991In the example above, you write @Beverage.allCases@ to access a collection that contains all of the cases of the @Beverage@ enumeration.
992You can use @allCases@ like any other collection -- the collection's elements are instances of the enumeration type, so in this case they're Beverage values.
993The example above counts how many cases there are, and the example below uses a for-in loop to iterate over all the cases.
994\begin{swift}
995for beverage in Beverage.allCases {
996        print(beverage)
997}
998// coffee
999// tea
1000// juice
1001\end{swift}
1002The syntax used in the examples above marks the enumeration as conforming to the @CaseIterable@ protocol.
1003For information about protocols, see Protocols.
1004
1005\paragraph{Associated Values}
1006The examples in the previous section show how the cases of an enumeration are a defined (and typed) value in their own right.
1007You can set a constant or variable to Planet.earth, and check for this value later.
1008However, it's sometimes useful to be able to store values of other types alongside these case values.
1009This additional information is called an associated value, and it varies each time you use that case as a value in your code.
1010
1011You can define Swift enumerations to store associated values of any given type, and the value types can be different for each case of the enumeration if needed.
1012Enumerations similar to these are known as discriminated unions, tagged unions, or variants in other programming languages.
1013
1014For example, suppose an inventory tracking system needs to track products by two different types of barcode.
1015Some products are labeled with 1D barcodes in UPC format, which uses the numbers 0 to 9.
1016Each barcode has a number system digit, followed by five manufacturer code digits and five product code digits.
1017These are followed by a check digit to verify that the code has been scanned correctly:
1018
1019Other products are labeled with 2D barcodes in QR code format, which can use any ISO 8859-1 character and can encode a string up to 2,953 characters long:
1020
1021It's convenient for an inventory tracking system to store UPC barcodes as a tuple of four integers, and QR code barcodes as a string of any length.
1022
1023In Swift, an enumeration to define product barcodes of either type might look like this:
1024\begin{swift}
1025enum Barcode {
1026        case upc(Int, Int, Int, Int)
1027        case qrCode(String)
1028}
1029\end{swift}
1030This can be read as:
1031\begin{quote}
1032"Define an enumeration type called Barcode, which can take either a value of upc with an associated value of type @(Int, Int, Int, Int)@, or a value of @qrCode@ with an associated value of type @String@."
1033\end{quote}
1034This definition doesn't provide any actual @Int@ or @String@ values -- it just defines the type of associated values that Barcode constants and variables can store when they're equal to @Barcode.upc@ or @Barcode.qrCode@.
1035
1036You can then create new barcodes using either type:
1037\begin{swift}
1038var productBarcode = Barcode.upc(8, 85909, 51226, 3)
1039\end{swift}
1040This example creates a new variable called @productBarcode@ and assigns it a value of @Barcode.upc@ with an associated tuple value of @(8, 85909, 51226, 3)@.
1041
1042You can assign the same product a different type of barcode:
1043\begin{swift}
1044productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
1045\end{swift}
1046At this point, the original @Barcode.upc@ and its integer values are replaced by the new @Barcode.qrCode@ and its string value.
1047Constants and variables of type Barcode can store either a @.upc@ or a @.qrCode@ (together with their associated values), but they can store only one of them at any given time.
1048
1049You can check the different barcode types using a switch statement, similar to the example in Matching Enumeration Values with a Switch Statement.
1050This time, however, the associated values are extracted as part of the switch statement.
1051You extract each associated value as a constant (with the let prefix) or a variable (with the var prefix) for use within the switch case's body:
1052\begin{swift}
1053switch productBarcode {
1054case .upc(let numberSystem, let manufacturer, let product, let check):
1055        print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
1056case .qrCode(let productCode):
1057        print("QR code: \(productCode).")
1058}
1059// Prints "QR code: ABCDEFGHIJKLMNOP."
1060\end{swift}
1061If all of the associated values for an enumeration case are extracted as constants, or if all are extracted as variables, you can place a single let or var annotation before the case name, for brevity:
1062\begin{swift}
1063switch productBarcode {
1064case let .upc(numberSystem, manufacturer, product, check):
1065        print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
1066case let .qrCode(productCode):
1067        print("QR code: \(productCode).")
1068}
1069// Prints "QR code: ABCDEFGHIJKLMNOP."
1070\end{swift}
1071
1072\paragraph{Raw Values}
1073
1074The barcode example in Associated Values shows how cases of an enumeration can declare that they store associated values of different types.
1075As an alternative to associated values, enumeration cases can come prepopulated with default values (called raw values), which are all of the same type.
1076
1077Here's an example that stores raw ASCII values alongside named enumeration cases:
1078\begin{swift}
1079enum ASCIIControlCharacter: Character {
1080        case tab = "\t"
1081        case lineFeed = "\n"
1082        case carriageReturn = "\r"
1083}
1084\end{swift}
1085Here, the raw values for an enumeration called ASCIIControlCharacter are defined to be of type Character, and are set to some of the more common ASCII control characters.
1086Character values are described in Strings and Characters.
1087
1088Raw values can be strings, characters, or any of the integer or floating-point number types.
1089Each raw value must be unique within its enumeration declaration.
1090
1091Note
1092
1093Raw values are not the same as associated values.
1094Raw values are set to prepopulated values when you first define the enumeration in your code, like the three ASCII codes above.
1095The raw value for a particular enumeration case is always the same.
1096Associated values are set when you create a new constant or variable based on one of the enumeration's cases, and can be different each time you do so.
1097Implicitly Assigned Raw Values
1098
1099When you're working with enumerations that store integer or string raw values, you don't have to explicitly assign a raw value for each case.
1100When you don't, Swift automatically assigns the values for you.
1101
1102For example, when integers are used for raw values, the implicit value for each case is one more than the previous case.
1103If the first case doesn't have a value set, its value is 0.
1104
1105The enumeration below is a refinement of the earlier Planet enumeration, with integer raw values to represent each planet's order from the sun:
1106
1107\begin{swift}
1108enum Planet: Int {
1109        case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
1110}
1111\end{swift}
1112In the example above, Planet.mercury has an explicit raw value of 1, Planet.venus has an implicit raw value of 2, and so on.
1113
1114When strings are used for raw values, the implicit value for each case is the text of that case's name.
1115
1116The enumeration below is a refinement of the earlier CompassPoint enumeration, with string raw values to represent each direction's name:
1117\begin{swift}
1118enum CompassPoint: String {
1119        case north, south, east, west
1120}
1121\end{swift}
1122In the example above, CompassPoint.south has an implicit raw value of "south", and so on.
1123
1124You access the raw value of an enumeration case with its rawValue property:
1125\begin{swift}
1126let earthsOrder = Planet.earth.rawValue
1127// earthsOrder is 3
1128
1129let sunsetDirection = CompassPoint.west.rawValue
1130// sunsetDirection is "west"
1131\end{swift}
1132
1133\paragraph{Initializing from a Raw Value}
1134
1135If you define an enumeration with a raw-value type, the enumeration automatically receives an initializer that takes a value of the raw value's type (as a parameter called rawValue) and returns either an enumeration case or nil.
1136You can use this initializer to try to create a new instance of the enumeration.
1137
1138This example identifies Uranus from its raw value of 7:
1139\begin{swift}
1140let possiblePlanet = Planet(rawValue: 7)
1141// possiblePlanet is of type Planet? and equals Planet.uranus
1142\end{swift}
1143Not all possible Int values will find a matching planet, however.
1144Because of this, the raw value initializer always returns an optional enumeration case.
1145In the example above, possiblePlanet is of type Planet?, or "optional Planet."
1146Note
1147
1148The raw value initializer is a failable initializer, because not every raw value will return an enumeration case.
1149For more information, see Failable Initializers.
1150
1151If you try to find a planet with a position of 11, the optional Planet value returned by the raw value initializer will be nil:
1152\begin{swift}
1153let positionToFind = 11
1154if let somePlanet = Planet(rawValue: positionToFind) {
1155        switch somePlanet {
1156        case .earth:
1157                print("Mostly harmless")
1158        default:
1159                print("Not a safe place for humans")
1160        }
1161} else {
1162        print("There isn't a planet at position \(positionToFind)")
1163}
1164// Prints "There isn't a planet at position 11"
1165\end{swift}
1166This example uses optional binding to try to access a planet with a raw value of 11.
1167The statement if let somePlanet = Planet(rawValue: 11) creates an optional Planet, and sets somePlanet to the value of that optional Planet if it can be retrieved.
1168In this case, it isn't possible to retrieve a planet with a position of 11, and so the else branch is executed instead.
1169
1170\paragraph{Recursive Enumerations}
1171
1172A recursive enumeration is an enumeration that has another instance of the enumeration as the associated value for one or more of the enumeration cases.
1173You indicate that an enumeration case is recursive by writing indirect before it, which tells the compiler to insert the necessary layer of indirection.
1174
1175For example, here is an enumeration that stores simple arithmetic expressions:
1176\begin{swift}
1177enum ArithmeticExpression {
1178        case number(Int)
1179        indirect case addition(ArithmeticExpression, ArithmeticExpression)
1180        indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
1181}
1182\end{swift}
1183You can also write indirect before the beginning of the enumeration to enable indirection for all of the enumeration's cases that have an associated value:
1184\begin{swift}
1185indirect enum ArithmeticExpression {
1186        case number(Int)
1187        case addition(ArithmeticExpression, ArithmeticExpression)
1188        case multiplication(ArithmeticExpression, ArithmeticExpression)
1189}
1190\end{swift}
1191This enumeration can store three kinds of arithmetic expressions: a plain number, the addition of two expressions, and the multiplication of two expressions.
1192The addition and multiplication cases have associated values that are also arithmetic expressions -- these associated values make it possible to nest expressions.
1193For example, the expression (5 + 4) * 2 has a number on the right-hand side of the multiplication and another expression on the left-hand side of the multiplication.
1194Because the data is nested, the enumeration used to store the data also needs to support nesting -- this means the enumeration needs to be recursive.
1195The code below shows the ArithmeticExpression recursive enumeration being created for (5 + 4) * 2:
1196\begin{swift}
1197let five = ArithmeticExpression.number(5)
1198let four = ArithmeticExpression.number(4)
1199let sum = ArithmeticExpression.addition(five, four)
1200let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
1201\end{swift}
1202A recursive function is a straightforward way to work with data that has a recursive structure.
1203For example, here's a function that evaluates an arithmetic expression:
1204\begin{swift}
1205func evaluate(_ expression: ArithmeticExpression) -> Int {
1206        switch expression {
1207        case let .number(value):
1208                return value
1209        case let .addition(left, right):
1210                return evaluate(left) + evaluate(right)
1211        case let .multiplication(left, right):
1212                return evaluate(left) * evaluate(right)
1213        }
1214}
1215
1216print(evaluate(product))
1217// Prints "18"
1218\end{swift}
1219This function evaluates a plain number by simply returning the associated value.
1220It evaluates an addition or multiplication by evaluating the expression on the left-hand side, evaluating the expression on the right-hand side, and then adding them or multiplying them.
1221
1222
1223\section{Python}
1224\lstnewenvironment{python}[1][]{\lstset{language=Python,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
1225
1226A Python enumeration is a set of symbolic names bound to \emph{unique} values.
1227They are similar to global variables, but offer a more useful @repr()@, grouping, type-safety, and additional features.
1228Enumerations inherits from the @Enum@ class, \eg:
1229\begin{python}
1230class Weekday(@Enum@): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
1231class RGB(@Enum@): Red = 1; Green = 2; Blue = 3
1232\end{python}
1233
1234Depending on the nature of the enum a member's value may or may not be important, but either way that value can be used to get the corresponding member:
1235\begin{python}
1236print( repr( Weekday( 3 ) ) )
1237<Weekday.Wed: 3>
1238\end{python}
1239As you can see, the @repr()@ of a member shows the enum name, the member name, and the value.
1240The @str()@ of a member shows only the enum name and member name:
1241\begin{python}
1242print( str( Weekday.Thu ), Weekday.Thu )
1243Weekday.Thu Weekday.Thu
1244\end{python}
1245The type of an enumeration member is the enum it belongs to:
1246\begin{python}
1247print( type( Weekday.Thu ) )
1248<enum 'Weekday'>
1249print( isinstance(Weekday.Fri, Weekday) )
1250True
1251\end{python}
1252Enum members have an attribute that contains just their name:
1253\begin{python}
1254print(Weekday.TUESDAY.name)
1255TUESDAY
1256\end{python}
1257Likewise, they have an attribute for their value:
1258\begin{python}
1259Weekday.WEDNESDAY.value
12603
1261\end{python}
1262
1263Unlike many languages that treat enumerations solely as name/value pairs, Python @Enum@s can have behavior added.
1264For example, @datetime.date@ has two methods for returning the weekday: @weekday()@ and @isoweekday()@.
1265The difference is that one of them counts from 0-6 and the other from 1-7.
1266Rather than keep track of that ourselves we can add a method to the @Weekday@ enum to extract the day from the date instance and return the matching enum member:
1267\begin{python}
1268class Weekday(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = 15; Sat = 16; Sun = 17
1269$@$classmethod
1270def from_date(cls, date):
1271        return cls(date.isoweekday())
1272\end{python}
1273Now we can find out what today is! Observe:
1274\begin{python}
1275>>> from datetime import date
1276>>> Weekday.from_date(date.today())     
1277<Weekday.TUESDAY: 2>
1278\end{python}
1279Of course, if you're reading this on some other day, you'll see that day instead.
1280
1281This Weekday enum is great if our variable only needs one day, but what if we need several? Maybe we're writing a function to plot chores during a week, and don't want to use a @list@ -- we could use a different type of @Enum@:
1282\begin{python}
1283from enum import Flag
1284class WeekdayF(@Flag@): Mon = @1@; Tue = @2@; Wed = @4@; Thu = @8@; Fri = @16@; Sat = @32@; Sun = @64@
1285\end{python}
1286We've changed two things: we're inherited from @Flag@, and the values are all powers of 2.
1287
1288@Flag@ allows combining several members into a single variable:
1289\begin{python}
1290print( repr(WeekdayF.Sat | WeekdayF.Sun) )
1291<WeekdayF.Sun|Sat: 96>
1292\end{python}
1293You can even iterate over a @Flag@ variable:
1294\begin{python}
1295for day in weekend:
1296        print(day)
1297Weekday.SATURDAY
1298Weekday.SUNDAY
1299\end{python}
1300Okay, let's get some chores set up:
1301\begin{python}
1302>>> chores_for_ethan = {
1303...    'feed the cat': Weekday.MONDAY | Weekday.WEDNESDAY | Weekday.FRIDAY,
1304...    'do the dishes': Weekday.TUESDAY | Weekday.THURSDAY,
1305...    'answer SO questions': Weekday.SATURDAY,
1306...    }
1307\end{python}
1308And a function to display the chores for a given day:
1309\begin{python}
1310>>> def show_chores(chores, day):
1311...    for chore, days in chores.items():
1312...        if day in days:
1313...            print(chore)
1314>>> show_chores(chores_for_ethan, Weekday.SATURDAY)
1315answer SO questions
1316\end{python}
1317In cases where the actual values of the members do not matter, you can save yourself some work and use @auto()@ for the values:
1318\begin{python}
1319>>> from enum import auto
1320>>> class Weekday(Flag):
1321...    MONDAY = auto()
1322...    TUESDAY = auto()
1323...    WEDNESDAY = auto()
1324...    THURSDAY = auto()
1325...    FRIDAY = auto()
1326...    SATURDAY = auto()
1327...    SUNDAY = auto()
1328...    WEEKEND = SATURDAY | SUNDAY
1329\end{python}
1330
1331\subsection{Programmatic access to enumeration members and their attributes}
1332
1333Sometimes it's useful to access members in enumerations programmatically (i.e. situations where @Color.RED@ won't do because the exact color is not known at program-writing time).
1334@Enum@ allows such access:
1335\begin{python}
1336>>> Color(1)
1337<Color.RED: 1>
1338>>> Color(3)
1339<Color.BLUE: 3>
1340\end{python}
1341If you want to access enum members by name, use item access:
1342\begin{python}
1343Color['RED']
1344<Color.RED: 1>
1345
1346Color['GREEN']
1347<Color.GREEN: 2>
1348\end{python}
1349If you have an enum member and need its name or value:
1350\begin{python}
1351>>> member = Color.RED
1352>>> member.name
1353'RED'
1354>>> member.value
13551
1356\end{python}
1357
1358\subsection{Duplicating enum members and values}
1359
1360An enum member can have other names associated with it.
1361Given two entries @A@ and @B@ with the same value (and @A@ defined first), @B@ is an alias for the member @A@.
1362By-value lookup of the value of @A@ will return the member @A@.
1363By-name lookup of @A@ will return the member @A@.
1364By-name lookup of @B@ will also return the member @A@:
1365\begin{python}
1366class Shape(Enum): SQUARE = 2; DIAMOND = 1; CIRCLE = 3; ALIAS_FOR_SQUARE = 2
1367>>> Shape.SQUARE
1368<Shape.SQUARE: 2>
1369>>> Shape.ALIAS_FOR_SQUARE
1370<Shape.SQUARE: 2>
1371>>> Shape(2)
1372<Shape.SQUARE: 2>
1373\end{python}
1374
1375Note: Attempting to create a member with the same name as an already defined attribute (another member, a method, etc.) or attempting to create an attribute with the same name as a member is not allowed.
1376
1377\subsection{Ensuring unique enumeration values}
1378
1379By default, enumerations allow multiple names as aliases for the same value.
1380When this behavior isn't desired, you can use the @unique()@ decorator:
1381\begin{python}
1382from enum import Enum, unique
1383$@$unique
1384class DupVal(Enum): ONE = 1; TWO = 2; THREE = 3; FOUR = 3
1385ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE
1386\end{python}
1387
1388\subsection{Using automatic values}
1389
1390If the exact value is unimportant you can use @auto@:
1391\begin{python}
1392from enum import Enum, auto
1393class RGBa(Enum): RED = auto(); BLUE = auto(); GREEN = auto()
1394\end{python}
1395(Like Golang @iota@.)
1396The values are chosen by @_generate_next_value_()@, which can be overridden:
1397\begin{python}
1398>>> class AutoName(Enum):
1399...     $@$staticmethod
1400...     def _generate_next_value_(name, start, count, last_values):
1401...         return name
1402...
1403>>> class Ordinal(AutoName):
1404...     NORTH = auto()
1405...     SOUTH = auto()
1406...     EAST = auto()
1407...     WEST = auto()
1408...
1409>>> [member.value for member in Ordinal]
1410['NORTH', 'SOUTH', 'EAST', 'WEST']
1411\end{python}
1412Note The @_generate_next_value_()@ method must be defined before any members.
1413
1414\subsection{Iteration}
1415
1416Iterating over the members of an enum does not provide the aliases:
1417\begin{python}
1418>>> list(Shape)
1419[<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
1420>>> list(Weekday)
1421[<Weekday.MONDAY: 1>, <Weekday.TUESDAY: 2>, <Weekday.WEDNESDAY: 4>, <Weekday.THURSDAY: 8>,
1422<Weekday.FRIDAY: 16>, <Weekday.SATURDAY: 32>, <Weekday.SUNDAY: 64>]
1423\end{python}
1424Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Weekday.WEEKEND@ aren't shown.
1425
1426The special attribute @__members__@ is a read-only ordered mapping of names to members.
1427It includes all names defined in the enumeration, including the aliases:
1428\begin{python}
1429>>> for name, member in Shape.__members__.items():
1430...     name, member
1431...
1432('SQUARE', <Shape.SQUARE: 2>)
1433('DIAMOND', <Shape.DIAMOND: 1>)
1434('CIRCLE', <Shape.CIRCLE: 3>)
1435('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)
1436\end{python}
1437The @__members__@ attribute can be used for detailed programmatic access to the enumeration members.
1438For example, finding all the aliases:
1439\begin{python}
1440>>> [name for name, member in Shape.__members__.items() if member.name != name]
1441['ALIAS_FOR_SQUARE']
1442\end{python}
1443Note: Aliases for flags include values with multiple flags set, such as 3, and no flags set, i.e. 0.
1444
1445\subsection{Comparisons}
1446
1447Enumeration members are compared by identity:
1448\begin{python}
1449>>> Color.RED is Color.RED
1450True
1451>>> Color.RED is Color.BLUE
1452False
1453>>> Color.RED is not Color.BLUE
1454True
1455\end{python}
1456Ordered comparisons between enumeration values are not supported.
1457Enum members are not integers (but see @IntEnum@ below):
1458\begin{python}
1459>>> Color.RED < Color.BLUE
1460Traceback (most recent call last):
1461  File "<stdin>", line 1, in <module>
1462TypeError: '<' not supported between instances of 'Color' and 'Color'
1463\end{python}
1464Equality comparisons are defined though:
1465\begin{python}
1466>>> Color.BLUE == Color.RED
1467False
1468>>> Color.BLUE != Color.RED
1469True
1470>>> Color.BLUE == Color.BLUE
1471True
1472\end{python}
1473Comparisons against non-enumeration values will always compare not equal (again, @IntEnum@ was explicitly designed to behave differently, see below):
1474\begin{python}
1475>>> Color.BLUE == 2
1476False
1477\end{python}
1478
1479Warning: It is possible to reload modules -- if a reloaded module contains enums, they will be recreated, and the new members may not compare identical/equal to the original members.
1480
1481\subsection{Allowed members and attributes of enumerations}
1482
1483Most of the examples above use integers for enumeration values.
1484Using integers is short and handy (and provided by default by the Functional API), but not strictly enforced.
1485In the vast majority of use-cases, one doesn't care what the actual value of an enumeration is.
1486But if the value is important, enumerations can have arbitrary values.
1487
1488Enumerations are Python classes, and can have methods and special methods as usual. If we have this enumeration:
1489\begin{python}
1490>>> class Mood(Enum):
1491...     FUNKY = 1
1492...     HAPPY = 3
1493...
1494...     def describe(self):
1495...         # self is the member here
1496...         return self.name, self.value
1497...
1498...     def __str__(self):
1499...         return 'my custom str! {0}'.format(self.value)
1500...
1501...     $@$classmethod
1502...
1503...     def favorite_mood(cls):
1504...         # cls here is the enumeration
1505...         return cls.HAPPY
1506...
1507\end{python}
1508Then:
1509\begin{python}
1510>>> Mood.favorite_mood()
1511<Mood.HAPPY: 3>
1512>>> Mood.HAPPY.describe()
1513('HAPPY', 3)
1514>>> str(Mood.FUNKY)
1515'my custom str! 1'
1516\end{python}
1517The rules for what is allowed are as follows: names that start and end with a single underscore are reserved by enum and cannot be used;
1518all other attributes defined within an enumeration will become members of this enumeration, with the exception of special methods (@__str__()@, @__add__()@, etc.), descriptors (methods are also descriptors), and variable names listed in @_ignore_@.
1519
1520Note: if your enumeration defines @__new__()@ and/or @__init__()@, any value(s) given to the enum member will be passed into those methods.
1521See Planet for an example.
1522
1523Note: The @__new__()@ method, if defined, is used during creation of the Enum members;
1524it is then replaced by Enum's @__new__()@ which is used after class creation for lookup of existing members.
1525See When to use @__new__()@ vs. @__init__()@ for more details.
1526
1527\subsection{Restricted Enum subclassing}
1528
1529A new @Enum@ class must have one base enum class, up to one concrete data type, and as many object-based mixin classes as needed.
1530The order of these base classes is:
1531\begin{python}
1532class EnumName([mix-in, ...,] [data-type,] base-enum):
1533        pass
1534\end{python}
1535Also, subclassing an enumeration is allowed only if the enumeration does not define any members.
1536So this is forbidden:
1537\begin{python}
1538>>> class MoreColor(Color):
1539...     PINK = 17
1540...
1541Traceback (most recent call last):
1542...
1543TypeError: <enum 'MoreColor'> cannot extend <enum 'Color'>
1544\end{python}
1545But this is allowed:
1546\begin{python}
1547>>> class Foo(Enum):
1548...     def some_behavior(self):
1549...         pass
1550...
1551>>> class Bar(Foo):
1552...     HAPPY = 1
1553...     SAD = 2
1554...
1555\end{python}
1556Allowing subclassing of enums that define members would lead to a violation of some important invariants of types and instances.
1557On the other hand, it makes sense to allow sharing some common behavior between a group of enumerations. (See OrderedEnum for an example.)
1558
1559\subsection{Dataclass support}
1560
1561When inheriting from a @dataclass@, the @__repr__()@ omits the inherited class' name.
1562For example:
1563\begin{python}
1564>>> from dataclasses import dataclass, field
1565>>> $@$dataclass
1566... class CreatureDataMixin:
1567...     size: str
1568...     legs: int
1569...     tail: bool = field(repr=False, default=True)
1570...
1571>>> class Creature(CreatureDataMixin, Enum):
1572...     BEETLE = 'small', 6
1573...     DOG = 'medium', 4
1574...
1575>>> Creature.DOG
1576<Creature.DOG: size='medium', legs=4>
1577\end{python}
1578Use the @dataclass()@ argument repr=False to use the standard @repr()@.
1579
1580Changed in version 3.12: Only the dataclass fields are shown in the value area, not the dataclass' name.
1581
1582\subsection{Pickling}
1583
1584Enumerations can be pickled and unpickled:
1585\begin{python}
1586>>> from test.test_enum import Fruit
1587>>> from pickle import dumps, loads
1588>>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))
1589True
1590\end{python}
1591The usual restrictions for pickling apply: picklable enums must be defined in the top level of a module, since unpickling requires them to be importable from that module.
1592
1593Note: With pickle protocol version 4 it is possible to easily pickle enums nested in other classes.
1594
1595It is possible to modify how enum members are pickled/unpickled by defining @__reduce_ex__()@ in the enumeration class.
1596The default method is by-value, but enums with complicated values may want to use by-name:
1597\begin{python}
1598>>> import enum
1599>>> class MyEnum(enum.Enum):
1600...     __reduce_ex__ = enum.pickle_by_enum_name
1601\end{python}
1602Note: Using by-name for flags is not recommended, as unnamed aliases will not unpickle.
1603
1604\subsection{Functional API}
1605
1606The @Enum@ class is callable, providing the following functional API:
1607\begin{python}
1608>>> Animal = Enum('Animal', 'ANT BEE CAT DOG')
1609>>> Animal
1610<enum 'Animal'>
1611>>> Animal.ANT
1612<Animal.ANT: 1>
1613>>> list(Animal)
1614[<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]
1615\end{python}
1616The semantics of this API resemble @namedtuple@.
1617The first argument of the call to @Enum@ is the name of the enumeration.
1618
1619The second argument is the source of enumeration member names.
1620It can be a whitespace-separated string of names, a sequence of names, a sequence of 2-tuples with key/value pairs, or a mapping (e.g. dictionary) of names to values.
1621The last two options enable assigning arbitrary values to enumerations;
1622the others auto-assign increasing integers starting with 1 (use the @start@ parameter to specify a different starting value).
1623A new class derived from @Enum@ is returned.
1624In other words, the above assignment to Animal is equivalent to:
1625\begin{python}
1626>>> class Animal(Enum):
1627...     ANT = 1
1628...     BEE = 2
1629...     CAT = 3
1630...     DOG = 4
1631...
1632\end{python}
1633The reason for defaulting to 1 as the starting number and not 0 is that 0 is @False@ in a boolean sense, but by default enum members all evaluate to @True@.
1634
1635Pickling enums created with the functional API can be tricky as frame stack implementation details are used to try and figure out which module the enumeration is being created in (e.g. it will fail if you use a utility function in a separate module, and also may not work on IronPython or Jython).
1636The solution is to specify the module name explicitly as follows:
1637\begin{python}
1638>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)
1639\end{python}
1640Warning: If module is not supplied, and @Enum@ cannot determine what it is, the new @Enum@ members will not be unpicklable; to keep errors closer to the source, pickling will be disabled.
1641
1642The new pickle protocol 4 also, in some circumstances, relies on @__qualname__@ being set to the location where pickle will be able to find the class.
1643For example, if the class was made available in class SomeData in the global scope:
1644\begin{python}
1645>>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')
1646\end{python}
1647The complete signature is:
1648\begin{python}
1649Enum(
1650        value='NewEnumName',
1651        names=<...>,
1652        *,
1653        module='...',
1654        qualname='...',
1655        type=<mixed-in class>,
1656        start=1,
1657        )
1658\end{python}
1659\begin{itemize}
1660\item
1661@value@: What the new enum class will record as its name.
1662\item
1663@names@: The enum members.
1664This can be a whitespace- or comma-separated string (values will start at 1 unless otherwise specified):
1665\begin{python}
1666'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'
1667\end{python}
1668or an iterator of names:
1669\begin{python}
1670['RED', 'GREEN', 'BLUE']
1671\end{python}
1672or an iterator of (name, value) pairs:
1673\begin{python}
1674[('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]
1675\end{python}
1676or a mapping:
1677\begin{python}
1678{'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}
1679\end{python}
1680\item
1681module: name of module where new enum class can be found.
1682\item
1683@qualname@: where in module new enum class can be found.
1684\item
1685@type@: type to mix in to new enum class.
1686\item
1687@start@: number to start counting at if only names are passed in.
1688\end{itemize}
1689Changed in version 3.5: The start parameter was added.
1690
1691\subsection{Derived Enumerations}
1692
1693\subsection{IntEnum}
1694
1695The first variation of @Enum@ that is provided is also a subclass of @int@.
1696Members of an @IntEnum@ can be compared to integers;
1697by extension, integer enumerations of different types can also be compared to each other:
1698\begin{python}
1699>>> from enum import IntEnum
1700>>> class Shape(IntEnum):
1701...     CIRCLE = 1
1702...     SQUARE = 2
1703...
1704>>> class Request(IntEnum):
1705...     POST = 1
1706...     GET = 2
1707...
1708>>> Shape == 1
1709False
1710>>> Shape.CIRCLE == 1
1711True
1712>>> Shape.CIRCLE == Request.POST
1713True
1714\end{python}
1715However, they still can't be compared to standard @Enum@ enumerations:
1716\begin{python}
1717>>> class Shape(IntEnum):
1718...     CIRCLE = 1
1719...     SQUARE = 2
1720...
1721>>> class Color(Enum):
1722...     RED = 1
1723...     GREEN = 2
1724...
1725>>> Shape.CIRCLE == Color.RED
1726False
1727\end{python}
1728@IntEnum@ values behave like integers in other ways you'd expect:
1729\begin{python}
1730>>> int(Shape.CIRCLE)
17311
1732>>> ['a', 'b', 'c'][Shape.CIRCLE]
1733'b'
1734>>> [i for i in range(Shape.SQUARE)]
1735[0, 1]
1736\end{python}
1737
1738\subsection{StrEnum}
1739
1740The second variation of @Enum@ that is provided is also a subclass of @str@.
1741Members of a @StrEnum@ can be compared to strings;
1742by extension, string enumerations of different types can also be compared to each other.
1743
1744New in version 3.11.
1745
1746\subsection{IntFlag}
1747
1748The next variation of @Enum@ provided, @IntFlag@, is also based on @int@.
1749The difference being @IntFlag@ members can be combined using the bitwise operators (@&, |, ^, ~@) and the result is still an @IntFlag@ member, if possible.
1750Like @IntEnum@, @IntFlag@ members are also integers and can be used wherever an int is used.
1751
1752Note: Any operation on an IntFlag member besides the bit-wise operations will lose the @IntFlag@ membership.
1753
1754Bit-wise operations that result in invalid @IntFlag@ values will lose the @IntFlag@ membership.
1755See @FlagBoundary@ for details.
1756
1757New in version 3.6.
1758
1759Changed in version 3.11.
1760
1761Sample @IntFlag@ class:
1762\begin{python}
1763>>> from enum import IntFlag
1764>>> class Perm(IntFlag):
1765...     R = 4
1766...     W = 2
1767...     X = 1
1768...
1769>>> Perm.R | Perm.W
1770<Perm.R|W: 6>
1771>>> Perm.R + Perm.W
17726
1773>>> RW = Perm.R | Perm.W
1774>>> Perm.R in RW
1775True
1776\end{python}
1777It is also possible to name the combinations:
1778\begin{python}
1779>>> class Perm(IntFlag):
1780...     R = 4
1781...     W = 2
1782...     X = 1
1783...     RWX = 7
1784...
1785>>> Perm.RWX
1786<Perm.RWX: 7>
1787>>> ~Perm.RWX
1788<Perm: 0>
1789>>> Perm(7)
1790<Perm.RWX: 7>
1791\end{python}
1792Note: Named combinations are considered aliases. Aliases do not show up during iteration, but can be returned from by-value lookups.
1793
1794Changed in version 3.11.
1795
1796Another important difference between @IntFlag@ and @Enum@ is that if no flags are set (the value is 0), its boolean evaluation is @False@:
1797\begin{python}
1798>>> Perm.R & Perm.X
1799<Perm: 0>
1800>>> bool(Perm.R & Perm.X)
1801False
1802\end{python}
1803Because @IntFlag@ members are also subclasses of int they can be combined with them (but may lose @IntFlag@ membership:
1804\begin{python}
1805>>> Perm.X | 4
1806<Perm.R|X: 5>
1807
1808>>> Perm.X + 8
18099
1810\end{python}
1811Note: The negation operator, @~@, always returns an @IntFlag@ member with a positive value:
1812\begin{python}
1813>>> (~Perm.X).value == (Perm.R|Perm.W).value == 6
1814True
1815\end{python}
1816@IntFlag@ members can also be iterated over:
1817\begin{python}
1818>>> list(RW)
1819[<Perm.R: 4>, <Perm.W: 2>]
1820\end{python}
1821New in version 3.11.
1822
1823\subsection{Flag}
1824
1825The last variation is @Flag@.
1826Like @IntFlag@, @Flag@ members can be combined using the bitwise operators (@&, |, ^, ~@).
1827Unlike @IntFlag@, they cannot be combined with, nor compared against, any other @Flag@ enumeration, nor @int@.
1828While it is possible to specify the values directly it is recommended to use @auto@ as the value and let @Flag@ select an appropriate value.
1829
1830New in version 3.6.
1831
1832Like @IntFlag@, if a combination of @Flag@ members results in no flags being set, the boolean evaluation is @False@:
1833\begin{python}
1834>>> from enum import Flag, auto
1835>>> class Color(Flag):
1836...     RED = auto()
1837...     BLUE = auto()
1838...     GREEN = auto()
1839...
1840>>> Color.RED & Color.GREEN
1841<Color: 0>
1842>>> bool(Color.RED & Color.GREEN)
1843False
1844\end{python}
1845Individual flags should have values that are powers of two (1, 2, 4, 8, ...), while combinations of flags will not:
1846\begin{python}
1847>>> class Color(Flag):
1848...     RED = auto()
1849...     BLUE = auto()
1850...     GREEN = auto()
1851...     WHITE = RED | BLUE | GREEN
1852...
1853>>> Color.WHITE
1854<Color.WHITE: 7>
1855\end{python}
1856Giving a name to the ``no flags set'' condition does not change its boolean value:
1857\begin{python}
1858>>> class Color(Flag):
1859...     BLACK = 0
1860...     RED = auto()
1861...     BLUE = auto()
1862...     GREEN = auto()
1863...
1864>>> Color.BLACK
1865<Color.BLACK: 0>
1866>>> bool(Color.BLACK)
1867False
1868\end{python}
1869@Flag@ members can also be iterated over:
1870\begin{python}
1871>>> purple = Color.RED | Color.BLUE
1872>>> list(purple)
1873[<Color.RED: 1>, <Color.BLUE: 2>]
1874\end{python}
1875New in version 3.11.
1876
1877Note: For the majority of new code, @Enum@ and @Flag@ are strongly recommended, since @IntEnum@ and @IntFlag@ break some semantic promises of an enumeration (by being comparable to integers, and thus by transitivity to other unrelated enumerations).
1878@IntEnum@ and @IntFlag@ should be used only in cases where @Enum@ and @Flag@ will not do;
1879for example, when integer constants are replaced with enumerations, or for interoperability with other systems.
1880
1881\subsection{Others}
1882
1883While @IntEnum@ is part of the enum module, it would be very simple to implement independently:
1884\begin{python}
1885class IntEnum(int, Enum):
1886        pass
1887\end{python}
1888This demonstrates how similar derived enumerations can be defined;
1889for example a @FloatEnum@ that mixes in float instead of @int@.
1890
1891Some rules:
1892\begin{itemize}
1893\item
1894When subclassing @Enum@, mix-in types must appear before @Enum@ itself in the sequence of bases, as in the @IntEnum@ example above.
1895\item
1896Mix-in types must be subclassable.
1897For example, @bool@ and @range@ are not subclassable and will throw an error during Enum creation if used as the mix-in type.
1898\item
1899While @Enum@ can have members of any type, once you mix in an additional type, all the members must have values of that type, e.g. @int@ above.
1900This restriction does not apply to mix-ins which only add methods and don't specify another type.
1901\item
1902When another data type is mixed in, the value attribute is not the same as the enum member itself, although it is equivalent and will compare equal.
1903\item
1904A data type is a mixin that defines @__new__()@, or a @dataclass@
1905\item
1906\%-style formatting: @%s@ and @%r@ call the @Enum@ class's @__str__()@ and @__repr__()@ respectively; other codes (such as @%i@ or @%h@ for @IntEnum@) treat the enum member as its mixed-in type.
1907\item
1908Formatted string literals, @str.format()@, and format() will use the enum's @__str__()@ method.
1909\end{itemize}
1910Note: Because @IntEnum@, @IntFlag@, and @StrEnum@ are designed to be drop-in replacements for existing constants, their @__str__()@ method has been reset to their data types' @__str__()@ method.
1911
1912\subsection{When to use \lstinline{__new__()} vs. \lstinline{__init__()}}
1913
1914@__new__()@ must be used whenever you want to customize the actual value of the @Enum@ member.
1915Any other modifications may go in either @__new__()@ or @__init__()@, with @__init__()@ being preferred.
1916
1917For example, if you want to pass several items to the constructor, but only want one of them to be the value:
1918\begin{python}
1919>>> class Coordinate(bytes, Enum):
1920...     """
1921...     Coordinate with binary codes that can be indexed by the int code.
1922...     """
1923...     def __new__(cls, value, label, unit):
1924...         obj = bytes.__new__(cls, [value])
1925...         obj._value_ = value
1926...         obj.label = label
1927...         obj.unit = unit
1928...         return obj
1929...     PX = (0, 'P.X', 'km')
1930...     PY = (1, 'P.Y', 'km')
1931...     VX = (2, 'V.X', 'km/s')
1932...     VY = (3, 'V.Y', 'km/s')
1933
1934>>> print(Coordinate['PY'])
1935Coordinate.PY
1936
1937>>> print(Coordinate(3))
1938Coordinate.VY
1939\end{python}
1940Warning: Do not call @super().__new__()@, as the lookup-only @__new__@ is the one that is found; instead, use the data type directly.
1941
1942\subsection{Finer Points}
1943
1944Supported @__dunder__@ names
1945
1946@__members__@ is a read-only ordered mapping of member\_name:member items. It is only available on the class.
1947
1948@__new__()@, if specified, must create and return the enum members; it is also a very good idea to set the member's @_value_@ appropriately. Once all the members are created it is no longer used.
1949Supported @_sunder_@ names
1950\begin{itemize}
1951\item
1952@_name_@ -- name of the member
1953\item
1954@_value_@ -- value of the member; can be set / modified in @__new__@
1955\item
1956@_missing_@ -- a lookup function used when a value is not found; may be overridden
1957\item
1958@_ignore_@ -- a list of names, either as a @list@ or a @str@, that will not be transformed into members, and will be removed from the final class
1959\item
1960@_order_@ -- used in Python 2/3 code to ensure member order is consistent (class attribute, removed during class creation)
1961\item
1962@_generate_@next@_value_@ -- used by the Functional API and by @auto@ to get an appropriate value for an enum member; may be overridden
1963\end{itemize}
1964Note: For standard @Enum@ classes the next value chosen is the last value seen incremented by one.
1965
1966For @Flag@ classes the next value chosen will be the next highest power-of-two, regardless of the last value seen.
1967
1968New in version 3.6: @_missing_@, @_order_@, @_generate_@next@_value_@
1969
1970New in version 3.7: @_ignore_@
1971
1972To help keep Python 2 / Python 3 code in sync an @_order_@ attribute can be provided.
1973It will be checked against the actual order of the enumeration and raise an error if the two do not match:
1974\begin{python}
1975>>> class Color(Enum):
1976...     _order_ = 'RED GREEN BLUE'
1977...     RED = 1
1978...     BLUE = 3
1979...     GREEN = 2
1980...
1981Traceback (most recent call last):
1982...
1983TypeError: member order does not match _order_:
1984  ['RED', 'BLUE', 'GREEN']
1985  ['RED', 'GREEN', 'BLUE']
1986\end{python}
1987Note: In Python 2 code the @_order_@ attribute is necessary as definition order is lost before it can be recorded.
1988
1989\subsection{\lstinline{_Private__names}}
1990
1991Private names are not converted to enum members, but remain normal attributes.
1992
1993Changed in version 3.11.
1994
1995\subsection{\lstinline{Enum} member type}
1996
1997@Enum@ members are instances of their enum class, and are normally accessed as @EnumClass.member@.
1998In certain situations, such as writing custom enum behavior, being able to access one member directly from another is useful, and is supported;
1999however, in order to avoid name clashes between member names and attributes/methods from mixed-in classes, upper-case names are strongly recommended.
2000
2001Changed in version 3.5.
2002
2003\subsection{Creating members that are mixed with other data types}
2004
2005When subclassing other data types, such as @int@ or @str@, with an @Enum@, all values after the = @are@ passed to that data type's constructor. For example:
2006\begin{python}
2007>>> class MyEnum(IntEnum):      # help(int) -> int(x, base=10) -> integer
2008...     example = '11', 16      # so x='11' and base=16
2009...
2010MyEnum.example.value        # and hex(11) is...
201117
2012\end{python}
2013
2014\subsection{\lstinline{Boolean} value of \lstinline{Enum} classes and members}
2015
2016Enum classes that are mixed with non-@Enum@ types (such as @int@, @str@, etc.) are evaluated according to the mixed-in type's rules;
2017otherwise, all members evaluate as @True@.
2018To make your own enum's boolean evaluation depend on the member's value add the following to your class:
2019\begin{python}
2020def __bool__(self):
2021        return bool(self.value)
2022\end{python}
2023Plain @Enum@ classes always evaluate as @True@.
2024
2025\subsection{\lstinline{Enum} classes with methods}
2026
2027If you give your enum subclass extra methods, like the Planet class below, those methods will show up in a dir() of the member, but not of the class:
2028\begin{python}
2029>>> dir(Planet)                         
2030['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS',
2031 '__class__', '__doc__', '__members__', '__module__']
2032>>> dir(Planet.EARTH)                   
2033['__class__', '__doc__', '__module__', 'mass', 'name', 'radius', 'surface_gravity', 'value']
2034\end{python}
2035
2036\subsection{Combining members of \lstinline{Flag}}
2037
2038Iterating over a combination of @Flag@ members will only return the members that are comprised of a single bit:
2039\begin{python}
2040>>> class Color(Flag):
2041...     RED = auto()
2042...     GREEN = auto()
2043...     BLUE = auto()
2044...     MAGENTA = RED | BLUE
2045...     YELLOW = RED | GREEN
2046...     CYAN = GREEN | BLUE
2047...
2048>>> Color(3)  # named combination
2049<Color.YELLOW: 3>
2050>>> Color(7)      # not named combination
2051<Color.RED|GREEN|BLUE: 7>
2052\end{python}
2053
2054\subsection{\lstinline{Flag} and \lstinline{IntFlag} minutia}
2055
2056Using the following snippet for our examples:
2057\begin{python}
2058>>> class Color(IntFlag):
2059...     BLACK = 0
2060...     RED = 1
2061...     GREEN = 2
2062...     BLUE = 4
2063...     PURPLE = RED | BLUE
2064...     WHITE = RED | GREEN | BLUE
2065...
2066\end{python}
2067the following are true:
2068\begin{itemize}
2069\item
2070single-bit flags are canonical
2071\item
2072multi-bit and zero-bit flags are aliases
2073\item
2074only canonical flags are returned during iteration:
2075\begin{python}
2076>>> list(Color.WHITE)
2077[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
2078\end{python}
2079negating a flag or flag set returns a new flag/flag set with the corresponding positive integer value:
2080\begin{python}
2081>>> Color.BLUE
2082<Color.BLUE: 4>
2083
2084>>> ~Color.BLUE
2085<Color.RED|GREEN: 3>
2086\end{python}
2087\item
2088names of pseudo-flags are constructed from their members' names:
2089\begin{python}
2090>>> (Color.RED | Color.GREEN).name
2091'RED|GREEN'
2092\end{python}
2093\item
2094multi-bit flags, aka aliases, can be returned from operations:
2095\begin{python}
2096>>> Color.RED | Color.BLUE
2097<Color.PURPLE: 5>
2098
2099>>> Color(7)  # or Color(-1)
2100<Color.WHITE: 7>
2101
2102>>> Color(0)
2103<Color.BLACK: 0>
2104\end{python}
2105\item
2106membership / containment checking: zero-valued flags are always considered to be contained:
2107\begin{python}
2108>>> Color.BLACK in Color.WHITE
2109True
2110\end{python}
2111otherwise, only if all bits of one flag are in the other flag will True be returned:
2112\begin{python}
2113>>> Color.PURPLE in Color.WHITE
2114True
2115
2116>>> Color.GREEN in Color.PURPLE
2117False
2118\end{python}
2119\end{itemize}
2120There is a new boundary mechanism that controls how out-of-range / invalid bits are handled: @STRICT@, @CONFORM@, @EJECT@, and @KEEP@:
2121\begin{itemize}
2122\item
2123@STRICT@ --> raises an exception when presented with invalid values
2124\item
2125@CONFORM@ --> discards any invalid bits
2126\item
2127@EJECT@ --> lose Flag status and become a normal int with the given value
2128\item
2129@KEEP@ --> keep the extra bits
2130\begin{itemize}
2131\item
2132keeps Flag status and extra bits
2133\item
2134extra bits do not show up in iteration
2135\item
2136extra bits do show up in repr() and str()
2137\end{itemize}
2138\end{itemize}
2139The default for @Flag@ is @STRICT@, the default for @IntFlag@ is @EJECT@, and the default for @_convert_@ is @KEEP@ (see @ssl.Options@ for an example of when @KEEP@ is needed).
2140
2141\section{How are Enums and Flags different?}
2142
2143Enums have a custom metaclass that affects many aspects of both derived @Enum@ classes and their instances (members).
2144
2145\subsection{Enum Classes}
2146
2147The @EnumType@ metaclass is responsible for providing the @__contains__()@, @__dir__()@, @__iter__()@ and other methods that allow one to do things with an @Enum@ class that fail on a typical class, such as @list(Color)@ or @some_enum_var@ in @Color@.
2148@EnumType@ is responsible for ensuring that various other methods on the final @Enum@ class are correct (such as @__new__()@, @__getnewargs__()@, @__str__()@ and @__repr__()@).
2149
2150\subsection{Flag Classes}
2151
2152Flags have an expanded view of aliasing: to be canonical, the value of a flag needs to be a power-of-two value, and not a duplicate name.
2153So, in addition to the @Enum@ definition of alias, a flag with no value (a.k.a. 0) or with more than one power-of-two value (e.g. 3) is considered an alias.
2154
2155\subsection{Enum Members (aka instances)}
2156
2157The most interesting thing about enum members is that they are singletons.
2158@EnumType@ creates them all while it is creating the enum class itself, and then puts a custom @__new__()@ in place to ensure that no new ones are ever instantiated by returning only the existing member instances.
2159
2160\subsection{Flag Members}
2161
2162Flag members can be iterated over just like the @Flag@ class, and only the canonical members will be returned.
2163For example:
2164\begin{python}
2165>>> list(Color)
2166[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
2167\end{python}
2168(Note that BLACK, PURPLE, and WHITE do not show up.)
2169
2170Inverting a flag member returns the corresponding positive value, rather than a negative value -- for example:
2171\begin{python}
2172>>> ~Color.RED
2173<Color.GREEN|BLUE: 6>
2174\end{python}
2175Flag members have a length corresponding to the number of power-of-two values they contain. For example:
2176\begin{python}
2177>>> len(Color.PURPLE)
21782
2179\end{python}
2180
2181\subsection{Enum Cookbook}
2182
2183While @Enum@, @IntEnum@, @StrEnum@, @Flag@, and @IntFlag@ are expected to cover the majority of use-cases, they cannot cover them all. Here are recipes for some different types of enumerations that can be used directly, or as examples for creating one's own.
2184
2185\subsection{Omitting values}
2186
2187In many use-cases, one doesn't care what the actual value of an enumeration is. There are several ways to define this type of simple enumeration:
2188\begin{itemize}
2189\item
2190use instances of auto for the value
2191\item
2192use instances of object as the value
2193\item
2194use a descriptive string as the value
2195\item
2196use a tuple as the value and a custom @__new__()@ to replace the tuple with an @int@ value
2197\end{itemize}
2198Using any of these methods signifies to the user that these values are not important, and also enables one to add, remove, or reorder members without having to renumber the remaining members.
2199
2200\subsection{Using \lstinline{auto}}
2201
2202Using @auto@ would look like:
2203\begin{python}
2204>>> class Color(Enum):
2205...     RED = auto()
2206...     BLUE = auto()
2207...     GREEN = auto()
2208...
2209>>> Color.GREEN
2210<Color.GREEN: 3>
2211\end{python}
2212
2213\subsection{Using \lstinline{object}}
2214
2215Using @object@ would look like:
2216\begin{python}
2217>>> class Color(Enum):
2218...     RED = object()
2219...     GREEN = object()
2220...     BLUE = object()
2221...
2222>>> Color.GREEN                         
2223<Color.GREEN: <object object at 0x...>>
2224\end{python}
2225This is also a good example of why you might want to write your own @__repr__()@:
2226\begin{python}
2227>>> class Color(Enum):
2228...     RED = object()
2229...     GREEN = object()
2230...     BLUE = object()
2231...     def __repr__(self):
2232...         return "<%s.%s>" % (self.__class__.__name__, self._name_)
2233...
2234>>> Color.GREEN
2235<Color.GREEN>
2236\end{python}
2237
2238\subsection{Using a descriptive string}
2239
2240Using a string as the value would look like:
2241\begin{python}
2242>>> class Color(Enum):
2243...     RED = 'stop'
2244...     GREEN = 'go'
2245...     BLUE = 'too fast!'
2246...
2247>>> Color.GREEN
2248<Color.GREEN: 'go'>
2249\end{python}
2250
2251\subsection{Using a custom \lstinline{__new__()}}
2252
2253Using an auto-numbering @__new__()@ would look like:
2254\begin{python}
2255>>> class AutoNumber(Enum):
2256...     def __new__(cls):
2257...         value = len(cls.__members__) + 1
2258...         obj = object.__new__(cls)
2259...         obj._value_ = value
2260...         return obj
2261...
2262>>> class Color(AutoNumber):
2263...     RED = ()
2264...     GREEN = ()
2265...     BLUE = ()
2266...
2267>>> Color.GREEN
2268<Color.GREEN: 2>
2269\end{python}
2270To make a more general purpose @AutoNumber@, add @*args@ to the signature:
2271\begin{python}
2272>>> class AutoNumber(Enum):
2273...     def __new__(cls, *args):      # this is the only change from above
2274...         value = len(cls.__members__) + 1
2275...         obj = object.__new__(cls)
2276...         obj._value_ = value
2277...         return obj
2278\end{python}
2279Then when you inherit from @AutoNumber@ you can write your own @__init__@ to handle any extra arguments:
2280\begin{python}
2281>>> class Swatch(AutoNumber):
2282...     def __init__(self, pantone='unknown'):
2283...         self.pantone = pantone
2284...     AUBURN = '3497'
2285...     SEA_GREEN = '1246'
2286...     BLEACHED_CORAL = () # New color, no Pantone code yet!
2287...
2288>>> Swatch.SEA_GREEN
2289<Swatch.SEA_GREEN: 2>
2290>>> Swatch.SEA_GREEN.pantone
2291'1246'
2292>>> Swatch.BLEACHED_CORAL.pantone
2293'unknown'
2294\end{python}
2295Note: The @__new__()@ method, if defined, is used during creation of the Enum members;
2296it is then replaced by Enum's @__new__()@ which is used after class creation for lookup of existing members.
2297
2298Warning: Do not call @super().__new__()@, as the lookup-only @__new__@ is the one that is found;
2299instead, use the data type directly -- e.g.:
2300\begin{python}
2301obj = int.__new__(cls, value)
2302\end{python}
2303
2304\subsection{OrderedEnum}
2305
2306An ordered enumeration that is not based on @IntEnum@ and so maintains the normal @Enum@ invariants (such as not being comparable to other enumerations):
2307\begin{python}
2308>>> class OrderedEnum(Enum):
2309...     def __ge__(self, other):
2310...         if self.__class__ is other.__class__:
2311...             return self.value >= other.value
2312...         return NotImplemented
2313...     def __gt__(self, other):
2314...         if self.__class__ is other.__class__:
2315...             return self.value > other.value
2316...         return NotImplemented
2317...     def __le__(self, other):
2318...         if self.__class__ is other.__class__:
2319...             return self.value <= other.value
2320...         return NotImplemented
2321...     def __lt__(self, other):
2322...         if self.__class__ is other.__class__:
2323...             return self.value < other.value
2324...         return NotImplemented
2325...
2326>>> class Grade(OrderedEnum):
2327...     A = 5
2328...     B = 4
2329...     C = 3
2330...     D = 2
2331...     F = 1
2332>>> Grade.C < Grade.A
2333True
2334\end{python}
2335
2336\subsection{DuplicateFreeEnum}
2337
2338Raises an error if a duplicate member value is found instead of creating an alias:
2339\begin{python}
2340>>> class DuplicateFreeEnum(Enum):
2341...     def __init__(self, *args):
2342...         cls = self.__class__
2343...         if any(self.value == e.value for e in cls):
2344...             a = self.name
2345...             e = cls(self.value).name
2346...             raise ValueError(
2347...                 "aliases not allowed in DuplicateFreeEnum:  %r --> %r"
2348...                 % (a, e))
2349>>> class Color(DuplicateFreeEnum):
2350...     RED = 1
2351...     GREEN = 2
2352...     BLUE = 3
2353...     GRENE = 2
2354...
2355Traceback (most recent call last):
2356  ...
2357ValueError: aliases not allowed in DuplicateFreeEnum:  'GRENE' --> 'GREEN'
2358\end{python}
2359Note: This is a useful example for subclassing Enum to add or change other behaviors as well as disallowing aliases.
2360If the only desired change is disallowing aliases, the @unique()@ decorator can be used instead.
2361
2362\subsection{Planet}
2363
2364If @__new__()@ or @__init__()@ is defined, the value of the enum member will be passed to those methods:
2365\begin{figure}
2366\begin{python}
2367from enum import Enum
2368class Planet(Enum):
2369        MERCURY = ( 3.303E23, 2.4397E6 )
2370        VENUS       = ( 4.869E24, 6.0518E6 )
2371        EARTH       = (5.976E24, 6.37814E6)
2372        MARS         = (6.421E23, 3.3972E6)
2373        JUPITER    = (1.9E27,   7.1492E7)
2374        SATURN     = (5.688E26, 6.0268E7)
2375        URANUS    = (8.686E25, 2.5559E7)
2376        NEPTUNE  = (1.024E26, 2.4746E7)
2377        def __init__( self, mass, radius ):
2378                self.mass = mass                # in kilograms
2379                self.radius = radius    # in meters
2380        def surface_gravity( self ):
2381                # universal gravitational constant  (m3 kg-1 s-2)
2382                G = 6.67300E-11
2383                return G * self.mass / (self.radius * self.radius)
2384for p in Planet:
2385        print( f"{p.name}: {p.value}" )
2386
2387MERCURY: (3.303e+23, 2439700.0)
2388VENUS: (4.869e+24, 6051800.0)
2389EARTH: (5.976e+24, 6378140.0)
2390MARS: (6.421e+23, 3397200.0)
2391JUPITER: (1.9e+27, 71492000.0)
2392SATURN: (5.688e+26, 60268000.0)
2393URANUS: (8.686e+25, 25559000.0)
2394NEPTUNE: (1.024e+26, 24746000.0)
2395\end{python}
2396\caption{Python Planet Example}
2397\label{f:PythonPlanetExample}
2398\end{figure}
2399
2400
2401\subsection{TimePeriod}
2402
2403An example to show the @_ignore_@ attribute in use:
2404\begin{python}
2405>>> from datetime import timedelta
2406>>> class Period(timedelta, Enum):
2407...     "different lengths of time"
2408...     _ignore_ = 'Period i'
2409...     Period = vars()
2410...     for i in range(367):
2411...         Period['day_%d' % i] = i
2412...
2413>>> list(Period)[:2]
2414[<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]
2415>>> list(Period)[-2:]
2416[<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]
2417\end{python}
2418
2419\subsection{Subclassing EnumType}
2420
2421While most enum needs can be met by customizing @Enum@ subclasses, either with class decorators or custom functions, @EnumType@ can be subclassed to provide a different Enum experience.
2422
2423
2424\section{OCaml}
2425\lstnewenvironment{ocaml}[1][]{\lstset{language=OCaml,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
2426
2427% https://ocaml.org/docs/basic-data-types#enumerated-data-types
2428
2429OCaml provides a variant (union) type, where multiple heterogeneously-typed objects share the same storage.
2430The simplest form of the variant type is a list of nullary datatype constructors, which is like an unscoped, pure enumeration.
2431\begin{ocaml}
2432type weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun
2433let day : weekday @= Mon@                               $\C{(* bind *)}$
2434let take_class( d : weekday ) =
2435        @match@ d with                                          $\C{(* matching *)}$
2436                Mon | Wed -> Printf.printf "CS442\n" |
2437                Tue | Thu -> Printf.printf "CS343\n" |
2438                Fri -> Printf.printf "Tutorial\n" |
2439                _ -> Printf.printf "Take a break\n"
2440let _ = take_class( Mon );
2441@CS442@
2442\end{ocaml}
2443The only operations are binding and pattern matching (equality), where the variant name is logically the implementation tag stored in the union for discriminating the vale in the object storage.
2444Here, function @take_class@ has a @weekday@ parameter, and returns @"CS442"@, if the weekday value is @Mon@ or @Wed@, @"CS343"@, if the value is @Tue@ or @Thu@, and @"Tutorial"@ for @Fri@.
2445The ``@_@'' is a wildcard matching any @weekday@ value, so the function returns @"Take a break"@ for values @Sat@ or @Sun@, which are not matched by the previous cases.
2446Since the variant has no type, it has a \Newterm{0-arity constructor}, \ie no parameters.
2447Because @weekday@ is a union of values @Mon@ to @Sun@, it is a \Newterm{union type} in turns of the functional-programming paradigm.
2448
2449Each variant can have an associated heterogeneous type, with an n-ary constructor for creating a corresponding value.
2450\begin{ocaml}
2451type colour = Red | Green of @string@ | Blue of @int * float@
2452\end{ocaml}
2453@colour@ is a summation of a nullary type, a unary product type of @string@, and a cross product of @int@ and @float@.
2454(Mathematically, a @Blue@ value is a Cartesian product of the types @int@ type and @float@.)
2455Hence, a variant type creates a sum of product of different types.
2456\begin{ocaml}
2457let c = Red                                                             $\C{(* 0-ary constructor, set tag *)}$
2458let _ = match c with Red -> Printf.printf "Red, "
2459let c = Green( "abc" )                                  $\C{(* 1-ary constructor, set tag *)}$
2460let _ = match c with Green g -> Printf.printf "%s, " g
2461let c = Blue( 1, 1.5 )                                  $\C{(* 2-ary constructor, set tag *)}$
2462let _ = match c with Blue( i, f ) -> Printf.printf "%d %g\n" i f
2463@Red, abc, 1 1.5@
2464\end{ocaml}
2465
2466A variant type can have a recursive definition.
2467\begin{ocaml}
2468type @stringList@ = Empty | Pair of string * @stringList@
2469\end{ocaml}
2470which is a recursive sum of product of types, called an \Newterm{algebraic data-type}.
2471A recursive function is often used to pattern match against a recursive variant type.
2472\begin{ocaml}
2473let rec @len_of_string_list@( list : stringList ): int =
2474        match list with
2475                Empty -> 0 |
2476                Pair( _ , r ) -> 1 + @len_of_string_list@ r
2477\end{ocaml}
2478Here, the head of the recursive type is removed and the remainder is processed until the type is empty.
2479Each recursion is counted to obtain the number of elements in the type.
2480
2481Note, the compiler statically guarantees that only the correct kind of type is used in the \lstinline[language=OCaml]{match} statement.
2482However, the union tag is dynamically set on binding (and possible reset on assignment), so a \lstinline[language=OCaml]{match} statement is effectively doing RTTI to select the matching case clause.
2483
2484In summary, an OCaml variant is a singleton value rather than a set of possibly ordered values, and hence, has no notion of enumerabilty.
2485Therefore it is not an enumeration, except for the simple pure (nullary) case.
2486
2487\begin{comment}
2488Date: Wed, 13 Mar 2024 10:52:34 -0400
2489Subject: Re: OCaml
2490To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
2491From: Gregor Richards <gregor.richards@uwaterloo.ca>
2492
2493On 3/12/24 18:34, Peter A. Buhr wrote:
2494> Gregor, attached is a section Jiada wrote on OCaml (1-page).
2495> Does it reflect our discussion about functional languages and enumerations?
2496
2497Yeah, I think so. The most important part, i.e., that once they're
2498parameterized they're not really enumerations at all, is covered clearly
2499enough.
2500
2501A couple quibbles:
2502
2503<<a list of untyped tags>>
2504
2505This is true, but leaking implementation details. These are nullary datatype
2506constructors. Indeed, you later talk about "tagged variants", which are really
2507just parameterized variants, using the term "tag" differently, confusing the
2508term "tag" further.
2509
2510<<Because weekday is a summation of values Mon to Sun, it is a sum type in
2511turns of the functional-programming paradigm>>
2512
2513It is a *union* of values and is a *union* type.
2514
2515With valediction,
2516  - Gregor Richards
2517
2518
2519Date: Thu, 14 Mar 2024 21:45:52 -0400
2520Subject: Re: OCaml "enums" do come with ordering
2521To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
2522From: Gregor Richards <gregor.richards@uwaterloo.ca>
2523
2524On 3/14/24 21:30, Peter A. Buhr wrote:
2525> I've marked 3 places with your name to shows places with enum ordering.
2526>
2527> type weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun
2528> let day : weekday = Mon
2529> let take_class( d : weekday ) =
2530>       if d <= Fri then                                (* Gregor *)
2531>               Printf.printf "weekday\n"
2532>       else if d >= Sat then                   (* Gregor *)
2533>               Printf.printf "weekend\n";
2534>       match d with
2535>               Mon | Wed -> Printf.printf "CS442\n" |
2536>               Tue | Thu -> Printf.printf "CS343\n" |
2537>               Fri -> Printf.printf "Tutorial\n" |
2538>               _ -> Printf.printf "Take a break\n"
2539>
2540> let _ = take_class( Mon ); take_class( Sat );
2541>
2542> type colour = Red | Green of string | Blue of int * float
2543> let c = Red
2544> let _ = match c with Red -> Printf.printf "Red, "
2545> let c = Green( "abc" )
2546> let _ = match c with Green g -> Printf.printf "%s, " g
2547> let c = Blue( 1, 1.5 )
2548> let _ = match c with Blue( i, f ) -> Printf.printf "%d %g\n" i f
2549>
2550> let check_colour(c: colour): string =
2551>       if c < Green( "xyz" ) then              (* Gregor *)
2552>               Printf.printf "green\n";
2553>       match c with
2554>               Red -> "Red" |
2555>               Green g -> g |
2556>               Blue(i, f) -> string_of_int i ^ string_of_float f
2557> let _ = check_colour( Red ); check_colour( Green( "xyz" ) );
2558>
2559> type stringList = Empty | Pair of string * stringList
2560> let rec len_of_string_list(l: stringList): int =
2561>       match l with
2562>               Empty -> 0 |
2563>               Pair(_ , r) -> 1 + len_of_string_list r
2564>
2565> let _ = for i = 1 to 10 do
2566>       Printf.printf "%d, " i
2567> done
2568>
2569> (* Local Variables: *)
2570> (* tab-width: 4 *)
2571> (* compile-command: "ocaml test.ml" *)
2572> (* End: *)
2573
2574My functional-language familiarity is far more with Haskell than OCaml.  I
2575mostly view OCaml through a lens of "it's Haskell but with cheating".  Haskell
2576"enums" (ADTs) aren't ordered unless you specifically and manually put them in
2577the Ord typeclass by defining the comparators.  Apparently, OCaml has some
2578other rule, which I would guess is something like "sort by tag then by order of
2579parameter". Having a default behavior for comparators is *bizarre*; my guess
2580would be that it gained this behavior in its flirtation with object
2581orientation, but that's just a guess (and irrelevant).
2582
2583This gives a total order, but not enumerability (which would still be
2584effectively impossible or even meaningless since enums are just a special case
2585of ADTs).
2586
2587With valediction,
2588  - Gregor Richards
2589\end{comment}
2590
2591
2592\section{Comparison}
2593
2594\VRef[Table]{t:FeatureLanguageComparison} shows a comparison of enumeration features and programming languages.
2595The features are high level and may not capture nuances within a particular language
2596The @const@ feature is simple macros substitution and not a typed enumeration.
2597
2598\begin{table}
2599\caption{Enumeration Feature / Language Comparison}
2600\label{t:FeatureLanguageComparison}
2601\small
2602\setlength{\tabcolsep}{3pt}
2603\newcommand{\CM}{\checkmark}
2604\begin{tabular}{r|c|c|c|c|c|c|c|c|c|c|c|c|c}
2605                                &Pascal & Ada   &\Csharp& OCaml & Java  &Modula-3&Golang& Rust  & Swift & Python& C             & \CC   & \CFA  \\
2606\hline
2607@const@                 & \CM   &               &               &               &               &               & \CM   &               &               &               &               & \CM   &               \\
2608\hline
2609\hline
2610pure                    &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
2611\hline
2612typed                   &               &               &               &               &               &               &               &               &               &               & @int@ & integral      & @T@   \\
2613\hline
2614safe                    &               &               &               &               &               &               &               &               &               &               &               & \CM   & \CM   \\
2615\hline
2616ordered                 &               &               &               &               &               &               &               &               &               &               & \CM   & \CM   & \CM   \\
2617\hline
2618dup. values             &               &               &               &               &               &               &               &               &               & alias & \CM   & \CM   & \CM   \\
2619\hline
2620setable                 &               &               &               &               &               &               &               &               &               &               & \CM   & \CM   & \CM   \\
2621\hline
2622auto-init               &               &               &               &               &               &               &               &               &               &               & \CM   & \CM   & \CM   \\
2623\hline
2624(un)scoped              &               &               &               &               &               &               &               &               &               &               & U             & U/S   & U/S   \\
2625\hline
2626overload                &               & \CM   &               &               &               &               &               &               &               &               &               & \CM   & \CM   \\
2627\hline
2628switch                  &               &               &               &               &               &               &               &               &               &               & \CM   & \CM   & \CM   \\
2629\hline
2630loop                    &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
2631\hline
2632array                   &               &               &               &               &               &               &               &               &               &               & \CM   &               & \CM   \\
2633\hline
2634subtype                 &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
2635\hline
2636inheritance             &               &               &               &               &               &               &               &               &               &               &               &               & \CM   \\
2637\end{tabular}
2638\end{table}
Note: See TracBrowser for help on using the repository browser.