source: doc/theses/jiada_liang_MMath/relatedwork.tex @ 03606ce

Last change on this file since 03606ce was 9262fe9, checked in by Peter A. Buhr <pabuhr@…>, 8 months ago

more proofreading for enumeration related-work

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