source: doc/theses/jiada_liang_MMath/relatedwork.tex @ 0139351

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

add comparison table for related work

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