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

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

proofread section Enumeration Trait, and a few other wording changes

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