Changeset c033405 for doc/theses


Ignore:
Timestamp:
Jun 12, 2024, 9:19:14 AM (3 weeks ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
master
Children:
bc17be98
Parents:
736a38d
Message:

first complete proofread of related-work chapter, still needs harmonizing across languages

File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/jiada_liang_MMath/relatedwork.tex

    r736a38d rc033405  
    4343\begin{pascal}
    4444Type @{$\color{red}\$$PACKENUM 1}@ SmallEnum = ( one, two, three );
    45             @{$\color{red}\$$PACKENUM 4}@ LargeEnum = ( BigOne, BigTwo, BigThree );
     45                @{$\color{red}\$$PACKENUM 4}@ LargeEnum = ( BigOne, BigTwo, BigThree );
    4646Var S : SmallEnum; { 1 byte }
    4747          L : LargeEnum; { 4 bytes}
     
    406406Mon 0, Tue 1, Wed 2, Thu 10, Fri 11, Sat 12, Sun 13,
    407407\end{csharp}
     408Hence, enumerating is not supplied directly by the enumeration, but indirectly through another enumerable type, array.
    408409
    409410An enumeration type cannot declare an array dimension but an enumerator can be used as a subscript.
     
    535536\begin{Java}
    536537public boolean isWeekday() { return !ordinal()! <= Fri.ordinal(); }
    537 public boolean isWeekend() { return Fri.ordinal() < !ordinal()!; }
     538public boolean isWeekend() { return Sat.ordinal() <= !ordinal()!; }
    538539\end{Java}
    539540Notice the unqualified calls to @ordinal@ in the members implying a \lstinline[language=Java]{this} to some implicit implementation variable, likely an @int@.
     
    5905910 1 Mon,  1 2 Tue,  2 3 Wed,  3 4 Thu,  4 5 Fri,  5 6 Sat,  6 7 Sun, 
    591592\end{Java}
     593Like \Csharp, enumerating is supplied indirectly through another enumerable type, not via the enumeration.
    592594
    593595An enumeration type cannot declare an array dimension nor can an enumerator be used as a subscript.
     
    602604% https://doc.rust-lang.org/reference/items/enumerations.html
    603605
    604 Rust @enum@ provides two largely independent mechanisms: an ADT and an enumeration.
     606Rust @enum@ provides two largely independent mechanisms from a single language feature: an ADT and an enumeration.
    605607When @enum@ is an ADT, pattern matching is used to discriminate among the variant types.
    606608\begin{cquote}
    607 \sf\setlength{\tabcolsep}{20pt}
    608 \begin{tabular}{@{}ll@{}}
     609\begin{tabular}{@{}l@{\hspace{30pt}}ll@{}}
    609610\begin{rust}
    610611struct S {
    611612        i : isize,  j : isize
    612613}
     614let mut s = S{ i : 3, j : 4 };
    613615enum @ADT@ {
    614         I(isize),   // int
    615         F(f64),   // float
    616         S(S),     // struct
     616        I( isize ), $\C[1in]{// int}$
     617        F( f64 ),   $\C{// float}$
     618        S( S ),     $\C{// struct}\CRT$
    617619}
    618620\end{rust}
    619621&
    620622\begin{rust}
    621 let mut s = S{ i : 3, j : 4 };
    622623let mut adt : ADT;
    623 adt = ADT::I(3);  adt = ADT::F(3.5);  adt = ADT::S(s); // init examples
     624adt = ADT::I(3);  println!( "{:?}", adt );
     625adt = ADT::F(3.5);  println!( "{:?}", adt );
     626adt = ADT::S(s);  println!( "{:?}", adt );
    624627@match@ adt {
    625         ADT::I(i) => println!( "{:?}", i ),
    626         ADT::F(f) => println!( "{:?}", f ),
    627         ADT::S(s) => println!( "{:?} {:?}", s.i, s.j ),
     628        ADT::I( i ) => println!( "{:}", i ),
     629        ADT::F( f ) => println!( "{:}", f ),
     630        ADT::S( s ) => println!( "{:} {:}", s.i, s.j ),
    628631}
    629632\end{rust}
    630 \end{tabular}
    631 \end{cquote}
    632 When the variant types are the unit type, the ADT is still not an enumeration because there is no enumerating \see{\VRef{s:AlgebraicDataType}}.
     633&
     634\begin{rust}
     635I(3)
     636F(3.5)
     637S(S { i: 3, j: 4 })
     6383 4
     639
     640
     641
     642
     643
     644\end{rust}
     645\end{tabular}
     646\end{cquote}
     647Even when the variant types are the unit type, the ADT is still not an enumeration because there is no enumerating \see{\VRef{s:AlgebraicDataType}}.
    633648\begin{rust}
    634649enum Week { Mon, Tues, Wed, Thu, Fri, Sat, Sun@,@ } // terminating comma
     
    643658However, Rust allows direct setting of the ADT constructor, which means it is actually a tag.
    644659\begin{cquote}
    645 \sf\setlength{\tabcolsep}{15pt}
     660\setlength{\tabcolsep}{15pt}
    646661\begin{tabular}{@{}ll@{}}
    647662\begin{rust}
     
    696711\end{tabular}
    697712\end{cquote}
    698 However, there is no mechanism to iterate through an enumeration without an casting to integral and positions versus values is not handled.
     713However, there is no mechanism to iterate through an enumeration without casting to integral and positions versus values is not handled.
    699714\begin{c++}
    700715for d in Week::Mon as isize ..= Week::Sun as isize {
     
    711726% https://www.programiz.com/swift/online-compiler
    712727
    713 A 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.
     728Like Rust, Swift @enum@ provides two largely independent mechanisms from a single language feature: an ADT and an enumeration.
     729When @enum@ is an ADT, pattern matching is used to discriminate among the variant types.
     730\begin{cquote}
     731\setlength{\tabcolsep}{20pt}
     732\begin{tabular}{@{}l@{\hspace{55pt}}ll@{}}
    714733\begin{swift}
    715 enum Many {
    716         case Mon, Tue, Wed, Thu, Fri, Sat, Sun // basic enumerator
    717         case code( String ) // string enumerator
    718         case tuple( Int, Int, Int ) // tuple enumerator
     734struct S {
     735        var i : Int,  j : Int
     736}
     737var s = S( i : 3, j : 5 )
     738@enum@ ADT {
     739        case I(Int)   $\C[1.125in]{// int}$
     740        case F(Float) $\C{// float}$
     741        case S(S)     $\C{// struct}\CRT$
     742}
     743\end{swift}
     744&
     745\begin{swift}
     746var adt : ADT
     747adt = .I( 3 );  print( adt )
     748adt = .F( 3.5 );  print( adt )
     749adt = .S( s );  print( adt )
     750@switch@ adt {  // pattern matching
     751        case .I(let i):  print( i )
     752        case .F(let f):  print( f )
     753        case .S(let s):  print( s.i, s.j )
     754}
     755\end{swift}
     756&
     757\begin{swift}
     758I(3)
     759F(3.5)
     760S(S(i: 3, j: 5))
     7613 5
     762
     763
     764
     765
     766
     767\end{swift}
     768\end{tabular}
     769\end{cquote}
     770(Note, after an @adt@'s type is know, the enumerator is inferred without qualification, \eg @.I(3)@.)
     771
     772An enumeration is created when \emph{all} the enumerators are unit-type.
     773\begin{swift}
     774enum Week {
     775        case Mon, Tue, Wed, Thu, Fri, Sat, Sun // unit-type
    719776};
    720 var day = Many.Sat; // qualification to resolve type
    721 print( day );
    722 day = .Wed // no qualification after type resolved
    723 print( day );
    724 day = .code( "ABC" );
    725 print( day );
    726 day = .tuple( 1, 2, 3 );
    727 print( day );
    728 
    729 Sat
    730 Wed
    731 code("ABC")
    732 tuple(1, 2, 3)
     777var week : Week = Week.Mon;
    733778\end{swift}
    734 
    735 
    736 An 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.
    737 
    738 If you are familiar with C, you will know that C enumerations assign related names to a set of integer values.
    739 Enumerations in Swift are much more flexible, and don't have to provide a value for each case of the enumeration.
    740 If 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.
    741 
    742 Alternatively, 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.
    743 You 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.
    744 
    745 Enumerations in Swift are first-class types in their own right.
    746 They 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.
    747 Enumerations can also define initializers to provide an initial case value;
    748 can be extended to expand their functionality beyond their original implementation; and can conform to protocols to provide standard functionality.
    749 
    750 For more about these capabilities, see Properties, Methods, Initialization, Extensions, and Protocols.
    751 
    752 \paragraph{Enumeration Syntax}
    753 
    754 
    755 Note:
    756 Swift enumeration cases don't have an integer value set by default, unlike languages like C and Objective-C.
    757 In the CompassPoint example above, @north@, @south@, @east@ and @west@ don't implicitly equal 0, 1, 2 and 3.
    758 Instead, the different enumeration cases are values in their own right, with an explicitly defined type of CompassPoint.
    759 
    760 Multiple cases can appear on a single line, separated by commas:
     779As well, it is possible to type \emph{all} the enumerators with a common type, and set different values for each enumerator;
     780for integral types, there is auto-incrementing.
     781\begin{cquote}
     782\setlength{\tabcolsep}{15pt}
     783\begin{tabular}{@{}lll@{}}
    761784\begin{swift}
    762 enum Planet {
    763         case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
    764 }
     785enum WeekInt: @Int@ {
     786        case Mon, Tue, Wed, Thu = 10, Fri,
     787                        Sat = 4, Sun // auto-incrementing
     788};
    765789\end{swift}
    766 Each enumeration definition defines a new type.
    767 Like other types in Swift, their names (such as @CompassPoint@ and @Planet@) start with a capital letter.
    768 Give enumeration types singular rather than plural names, so that they read as self-evident:
     790&
    769791\begin{swift}
    770 var directionToHead = CompassPoint.west
     792enum WeekStr: @String@ {
     793        case Mon = "MON", Tue, Wed, Thu, Fri,
     794                        Sat = "SAT", Sun
     795};
    771796\end{swift}
    772 The type of @directionToHead@ is inferred when it's initialized with one of the possible values of @CompassPoint@.
    773 Once @directionToHead@ is declared as a @CompassPoint@, you can set it to a different @CompassPoint@ value using a shorter dot syntax:
     797\end{tabular}
     798\end{cquote}
     799An enumeration only supports equality comparison between enumerator values, unless it inherits from @Comparable@, adding relational operators @<@, @<=@, @>@, and @>=@.
     800
     801An enumeration can have methods.
    774802\begin{swift}
    775 directionToHead = .east
     803enum Week: Comparable {
     804        case Mon, Tue, Wed, Thu, Fri, Sat, Sun // unit-type
     805        func @isWeekday() -> Bool@ { return self <= .Fri }    // method
     806        func @isWeekend() -> Bool@ { return .Sat <= self }  // method
     807};
    776808\end{swift}
    777 The type of @directionToHead@ is already known, and so you can drop the type when setting its value.
    778 This makes for highly readable code when working with explicitly typed enumeration values.
    779 
    780 \paragraph{Matching Enumeration Values with a Switch Statement}
    781 
    782 You can match individual enumeration values with a switch statement:
     809An enumeration can be used in the @if@ and @switch@ statements, where @switch@ must be exhaustive or have a @default@.
     810\begin{cquote}
     811\setlength{\tabcolsep}{15pt}
     812\begin{tabular}{@{}ll@{}}
    783813\begin{swift}
    784 directionToHead = .south
    785 switch directionToHead {
    786 case .north:
    787         print("Lots of planets have a north")
    788 case .south:
    789         print("Watch out for penguins")
    790 case .east:
    791         print("Where the sun rises")
    792 case .west:
    793         print("Where the skies are blue")
    794 }
    795 // Prints "Watch out for penguins"
     814if @week <= .Fri@ {
     815        print( "weekday" );
     816}
     817
     818
    796819\end{swift}
    797 You can read this code as:
    798 \begin{quote}
    799 "Consider the value of directionToHead.
    800 In the case where it equals @.north@, print "Lots of planets have a north".
    801 In the case where it equals @.south@, print "Watch out for penguins"."
    802 
    803 ...and so on.
    804 \end{quote}
    805 As described in Control Flow, a switch statement must be exhaustive when considering an enumeration's cases.
    806 If the case for @.west@ is omitted, this code doesn't compile, because it doesn't consider the complete list of @CompassPoint@ cases.
    807 Requiring exhaustiveness ensures that enumeration cases aren't accidentally omitted.
    808 
    809 When 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:
     820&
    810821\begin{swift}
    811 let somePlanet = Planet.earth
    812 switch somePlanet {
    813 case .earth:
    814         print("Mostly harmless")
    815 default:
    816         print("Not a safe place for humans")
    817 }
    818 // Prints "Mostly harmless"
     822switch @week@ {
     823        case .Mon: print( "Mon" )
     824        ...
     825        case .Sun: print( "Sun" )
     826}
    819827\end{swift}
    820 
    821 \paragraph{Iterating over Enumeration Cases}
    822 
    823 For some enumerations, it's useful to have a collection of all of that enumeration's cases.
    824 You enable this by writing @CaseIterable@ after the enumeration's name.
    825 Swift exposes a collection of all the cases as an allCases property of the enumeration type.
    826 Here's an example:
     828\end{tabular}
     829\end{cquote}
     830
     831Enumerating is accomplished by inheriting from @CaseIterable@ without any associated values.
    827832\begin{swift}
    828 enum Beverage: CaseIterable {
    829         case coffee, tea, juice
    830 }
    831 let numberOfChoices = Beverage.allCases.count
    832 print("\(numberOfChoices) beverages available")
    833 // Prints "3 beverages available"
     833enum Week: Comparable, @CaseIterable@ {
     834        case Mon, Tue, Wed, Thu, Fri, Sat, Sun // unit-type
     835};
     836var weeki : Week = Week.Mon;
     837if weeki <= .Fri {
     838        print( "weekday" );
     839}
     840for day in Week@.allCases@ {
     841        print( day, terminator:" " )
     842}
     843weekday
     844Mon Tue Wed Thu Fri Sat Sun
    834845\end{swift}
    835 In the example above, you write @Beverage.allCases@ to access a collection that contains all of the cases of the @Beverage@ enumeration.
    836 You 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.
    837 The example above counts how many cases there are, and the example below uses a for-in loop to iterate over all the cases.
     846The @enum.allCases@ property returns a collection of all the cases for looping over an enumeration type or variable (expensive operation).
     847
     848A typed enumeration is accomplished by inheriting from any Swift type, and accessing the underlying enumerator value is done with attribute @rawValue@.
     849Type @Int@ has auto-incrementing from previous enumerator;
     850type @String@ has auto-incrementing of the enumerator label.
     851\begin{cquote}
     852\setlength{\tabcolsep}{15pt}
     853\begin{tabular}{@{}lll@{}}
    838854\begin{swift}
    839 for beverage in Beverage.allCases {
    840         print(beverage)
    841 }
    842 // coffee
    843 // tea
    844 // juice
     855enum WeekInt: @Int@, CaseIterable {
     856        case Mon, Tue, Wed, Thu = 10, Fri,
     857                        Sat = 4, Sun // auto-incrementing
     858};
     859for day in WeekInt.allCases {
     860        print( day@.rawValue@, terminator:" " )
     861}
     8620 1 2 10 11 4 5
    845863\end{swift}
    846 The syntax used in the examples above marks the enumeration as conforming to the @CaseIterable@ protocol.
    847 For information about protocols, see Protocols.
    848 
    849 \paragraph{Associated Values}
    850 The examples in the previous section show how the cases of an enumeration are a defined (and typed) value in their own right.
    851 You can set a constant or variable to Planet.earth, and check for this value later.
    852 However, it's sometimes useful to be able to store values of other types alongside these case values.
    853 This additional information is called an associated value, and it varies each time you use that case as a value in your code.
    854 
    855 You 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.
    856 Enumerations similar to these are known as discriminated unions, tagged unions, or variants in other programming languages.
    857 
    858 For example, suppose an inventory tracking system needs to track products by two different types of barcode.
    859 Some products are labeled with 1D barcodes in UPC format, which uses the numbers 0 to 9.
    860 Each barcode has a number system digit, followed by five manufacturer code digits and five product code digits.
    861 These are followed by a check digit to verify that the code has been scanned correctly:
    862 
    863 Other 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:
    864 
    865 It'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.
    866 
    867 In Swift, an enumeration to define product barcodes of either type might look like this:
     864&
    868865\begin{swift}
    869 enum Barcode {
    870         case upc(Int, Int, Int, Int)
    871         case qrCode(String)
    872 }
     866enum WeekStr: @String@, CaseIterable {
     867        case Mon = "MON", Tue, Wed, Thu, Fri,
     868                        Sat = "SAT", Sun
     869};
     870for day in WeekStr.allCases {
     871        print( day@.rawValue@, terminator:" " )
     872}
     873MON Tue Wed Thu Fri SAT Sun
    873874\end{swift}
    874 This can be read as:
    875 \begin{quote}
    876 "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@."
    877 \end{quote}
    878 This 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@.
    879 
    880 You can then create new barcodes using either type:
     875\end{tabular}
     876\end{cquote}
     877
     878There is a bidirectional conversion from typed enumerator to @rawValue@ and vise versa.
    881879\begin{swift}
    882 var productBarcode = Barcode.upc(8, 85909, 51226, 3)
     880var weekInt : WeekInt = WeekInt.Mon;
     881if let opt = WeekInt( rawValue: 0 ) {  // test optional return value
     882        print( weekInt.rawValue, opt )  // 0 Mon
     883} else {
     884        print( "invalid weekday lookup" )
     885}
    883886\end{swift}
    884 This 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)@.
    885 
    886 You can assign the same product a different type of barcode:
    887 \begin{swift}
    888 productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
    889 \end{swift}
    890 At this point, the original @Barcode.upc@ and its integer values are replaced by the new @Barcode.qrCode@ and its string value.
    891 Constants 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.
    892 
    893 You can check the different barcode types using a switch statement, similar to the example in Matching Enumeration Values with a Switch Statement.
    894 This time, however, the associated values are extracted as part of the switch statement.
    895 You 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:
    896 \begin{swift}
    897 switch productBarcode {
    898 case .upc(let numberSystem, let manufacturer, let product, let check):
    899         print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
    900 case .qrCode(let productCode):
    901         print("QR code: \(productCode).")
    902 }
    903 // Prints "QR code: ABCDEFGHIJKLMNOP."
    904 \end{swift}
    905 If 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:
    906 \begin{swift}
    907 switch productBarcode {
    908 case let .upc(numberSystem, manufacturer, product, check):
    909         print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
    910 case let .qrCode(productCode):
    911         print("QR code: \(productCode).")
    912 }
    913 // Prints "QR code: ABCDEFGHIJKLMNOP."
    914 \end{swift}
    915 
    916 \paragraph{Raw Values}
    917 
    918 The barcode example in Associated Values shows how cases of an enumeration can declare that they store associated values of different types.
    919 As an alternative to associated values, enumeration cases can come prepopulated with default values (called raw values), which are all of the same type.
    920 
    921 Here's an example that stores raw ASCII values alongside named enumeration cases:
    922 \begin{swift}
    923 enum ASCIIControlCharacter: Character {
    924         case tab = "\t"
    925         case lineFeed = "\n"
    926         case carriageReturn = "\r"
    927 }
    928 \end{swift}
    929 Here, 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.
    930 Character values are described in Strings and Characters.
    931 
    932 Raw values can be strings, characters, or any of the integer or floating-point number types.
    933 Each raw value must be unique within its enumeration declaration.
    934 
    935 Note
    936 
    937 Raw values are not the same as associated values.
    938 Raw values are set to prepopulated values when you first define the enumeration in your code, like the three ASCII codes above.
    939 The raw value for a particular enumeration case is always the same.
    940 Associated 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.
    941 Implicitly Assigned Raw Values
    942 
    943 When 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.
    944 When you don't, Swift automatically assigns the values for you.
    945 
    946 For example, when integers are used for raw values, the implicit value for each case is one more than the previous case.
    947 If the first case doesn't have a value set, its value is 0.
    948 
    949 The enumeration below is a refinement of the earlier Planet enumeration, with integer raw values to represent each planet's order from the sun:
    950 
    951 \begin{swift}
    952 enum Planet: Int {
    953         case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
    954 }
    955 \end{swift}
    956 In the example above, Planet.mercury has an explicit raw value of 1, Planet.venus has an implicit raw value of 2, and so on.
    957 
    958 When strings are used for raw values, the implicit value for each case is the text of that case's name.
    959 
    960 The enumeration below is a refinement of the earlier CompassPoint enumeration, with string raw values to represent each direction's name:
    961 \begin{swift}
    962 enum CompassPoint: String {
    963         case north, south, east, west
    964 }
    965 \end{swift}
    966 In the example above, CompassPoint.south has an implicit raw value of "south", and so on.
    967 
    968 You access the raw value of an enumeration case with its rawValue property:
    969 \begin{swift}
    970 let earthsOrder = Planet.earth.rawValue
    971 // earthsOrder is 3
    972 
    973 let sunsetDirection = CompassPoint.west.rawValue
    974 // sunsetDirection is "west"
    975 \end{swift}
    976 
    977 \paragraph{Initializing from a Raw Value}
    978 
    979 If 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.
    980 You can use this initializer to try to create a new instance of the enumeration.
    981 
    982 This example identifies Uranus from its raw value of 7:
    983 \begin{swift}
    984 let possiblePlanet = Planet(rawValue: 7)
    985 // possiblePlanet is of type Planet? and equals Planet.uranus
    986 \end{swift}
    987 Not all possible Int values will find a matching planet, however.
    988 Because of this, the raw value initializer always returns an optional enumeration case.
    989 In the example above, possiblePlanet is of type Planet?, or "optional Planet."
    990 Note
    991 
    992 The raw value initializer is a failable initializer, because not every raw value will return an enumeration case.
    993 For more information, see Failable Initializers.
    994 
    995 If you try to find a planet with a position of 11, the optional Planet value returned by the raw value initializer will be nil:
    996 \begin{swift}
    997 let positionToFind = 11
    998 if let somePlanet = Planet(rawValue: positionToFind) {
    999         switch somePlanet {
    1000         case .earth:
    1001                 print("Mostly harmless")
    1002         default:
    1003                 print("Not a safe place for humans")
    1004         }
    1005 } else {
    1006         print("There isn't a planet at position \(positionToFind)")
    1007 }
    1008 // Prints "There isn't a planet at position 11"
    1009 \end{swift}
    1010 This example uses optional binding to try to access a planet with a raw value of 11.
    1011 The 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.
    1012 In this case, it isn't possible to retrieve a planet with a position of 11, and so the else branch is executed instead.
    1013 
    1014 \paragraph{Recursive Enumerations}
    1015 
    1016 A recursive enumeration is an enumeration that has another instance of the enumeration as the associated value for one or more of the enumeration cases.
    1017 You indicate that an enumeration case is recursive by writing indirect before it, which tells the compiler to insert the necessary layer of indirection.
    1018 
    1019 For example, here is an enumeration that stores simple arithmetic expressions:
    1020 \begin{swift}
    1021 enum ArithmeticExpression {
    1022         case number(Int)
    1023         indirect case addition(ArithmeticExpression, ArithmeticExpression)
    1024         indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
    1025 }
    1026 \end{swift}
    1027 You 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:
    1028 \begin{swift}
    1029 indirect enum ArithmeticExpression {
    1030         case number(Int)
    1031         case addition(ArithmeticExpression, ArithmeticExpression)
    1032         case multiplication(ArithmeticExpression, ArithmeticExpression)
    1033 }
    1034 \end{swift}
    1035 This enumeration can store three kinds of arithmetic expressions: a plain number, the addition of two expressions, and the multiplication of two expressions.
    1036 The addition and multiplication cases have associated values that are also arithmetic expressions -- these associated values make it possible to nest expressions.
    1037 For 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.
    1038 Because the data is nested, the enumeration used to store the data also needs to support nesting -- this means the enumeration needs to be recursive.
    1039 The code below shows the ArithmeticExpression recursive enumeration being created for (5 + 4) * 2:
    1040 \begin{swift}
    1041 let five = ArithmeticExpression.number(5)
    1042 let four = ArithmeticExpression.number(4)
    1043 let sum = ArithmeticExpression.addition(five, four)
    1044 let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
    1045 \end{swift}
    1046 A recursive function is a straightforward way to work with data that has a recursive structure.
    1047 For example, here's a function that evaluates an arithmetic expression:
    1048 \begin{swift}
    1049 func evaluate(_ expression: ArithmeticExpression) -> Int {
    1050         switch expression {
    1051         case let .number(value):
    1052                 return value
    1053         case let .addition(left, right):
    1054                 return evaluate(left) + evaluate(right)
    1055         case let .multiplication(left, right):
    1056                 return evaluate(left) * evaluate(right)
    1057         }
    1058 }
    1059 
    1060 print(evaluate(product))
    1061 // Prints "18"
    1062 \end{swift}
    1063 This function evaluates a plain number by simply returning the associated value.
    1064 It 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.
     887Conversion from @rawValue@ to enumerator may fail (bad lookup), so the result is an optional value.
    1065888
    1066889
     
    1068891% https://docs.python.org/3/howto/enum.html
    1069892
    1070 Python 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.
     893Python is a dynamically-typed reflexive programming language with multiple incompatible versions.
     894The generality of the language makes it is possible to extend existing or build new language features.
    1071895As a result, discussing Python enumerations is a moving target, because if a features does not exist, it can often be created with varying levels of complexity within the language.
    1072 Nevertheless, the following is a discuss of the core enumeration features that come with Python 3.13.
    1073 
    1074 A Python enumeration type is a set of ordered scoped identifiers (enumerators) bound to \emph{unique} values.
    1075 An enumeration is not a basic type;
    1076 it is a @class@ inheriting from the @Enum@ class, where the enumerators must be explicitly initialized, \eg:
    1077 \begin{python}
    1078 class Week(@Enum@): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
     896Therefore, the following discussion is (mostly) restricted to the core enumeration features in Python 3.13.
     897
     898A Python enumeration is not a basic type;
     899it is a @class@ inheriting from the @Enum@ class.
     900The @Enum@ class presents a set of scoped enumerators, where each enumerator is a pair object with a \emph{constant} string name and arbitrary value.
     901Hence, an enumeration instance is a fixed type (enumeration pair), and its value is the type of one of the enumerator pairs.
     902
     903The enumerator value fields must be explicitly initialized and be \emph{unique}.
     904\begin{python}
     905class Week(!Enum!): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
    1079906\end{python}
    1080907and/or explicitly auto initialized, \eg:
    1081908\begin{python}
    1082 class Week(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = @auto()@; Sat = 4; Sun = @auto()@
    1083 \end{python}
    1084 where @auto@ increments by 1 from the previous enumerator value \see{Golang \lstinline[language=Go]{iota}, \VRef{s:Golang}}.
    1085 Object initialization and assignment are restricted to the enumerators of this type.
    1086 An enumerator initialized with same value is an alias and invisible at the enumeration level, \ie the alias it substituted for its aliasee.
    1087 \begin{python}
    1088 class Week(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = @10@; Sat = @10@; Sun = @10@
     909class Week(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = !auto()!; Sat = 4; Sun = !auto()!
     910Mon : 1 Tue : 2 Wed : 3 Thu : 10 Fri : !11! Sat : 4 Sun : !12!
     911\end{python}
     912where @auto@ increments by 1 from the previous @auto@ value \see{Golang \lstinline[language=Go]{iota}, \VRef{s:Golang}}.
     913@auto@ is controlled by member @_generate_next_value_()@, which can be overridden:
     914\begin{python}
     915@staticmethod
     916def _generate_next_value_( name, start, count, last_values ):
     917        return name
     918\end{python}
     919
     920There is no direct concept of restricting the enumerators in an enumeration \emph{instance} because the dynamic typing changes the type.
     921\begin{python}
     922class RGB(Enum): Red = 1; Green = 2; Blue = 3
     923day : Week = Week.Tue;          $\C{\# type is Week}$
     924!day = RGB.Red!                         $\C{\# type is RGB}$
     925!day : Week = RGB.Red!          $\C{\# type is RGB}$
     926\end{python}
     927The enumerators are constants and cannot be reassigned.
     928Hence, while enumerators can be different types,
     929\begin{python}
     930class Diff(Enum): Int = 1; Float = 3.5; Str = "ABC"
     931\end{python}
     932it is not an ADT because the enumerator names are not constructors.
     933
     934An enumerator initialized with the same value is an alias and invisible at the enumeration level, \ie the alias is substituted for its aliasee.
     935\begin{python}
     936class WeekD(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = !10!; Fri = !10!; Sat = !10!; Sun = !10!
    1089937\end{python}
    1090938Here, the enumeration has only 4 enumerators and 3 aliases.
    1091939An alias is only visible by dropping down to the @class@ level and asking for class members.
    1092 @Enum@ only supports equality comparison between enumerator values;
    1093 the extended class @OrderedEnum@ adds relational operators @<@, @<=@, @>@, and @>=@.
    1094 
    1095 There are bidirectional enumeration pseudo-functions for label and value, but there is no concept of access using ordering (position).
     940Aliasing is prevented using the @unique@ decorator.
     941\begin{python}
     942!@unique!
     943class DupVal(Enum): One = 1; Two = 2; Three = !3!; Four = !3!
     944ValueError: duplicate values found in <enum 'DupVal'>: Four -> Three
     945\end{python}
     946
     947\begin{lrbox}{\myboxA}
     948\begin{python}
     949def by_position(enum_type, position):
     950        for index, value in enumerate(enum_type):
     951                if position == index: return value
     952        raise Exception("by_position out of range")
     953\end{python}
     954\end{lrbox}
     955There are bidirectional enumeration pseudo-functions for label and value, but there is no concept of access using ordering (position).\footnote{
     956There is an $O(N)$ mechanism to access an enumerator's value by position. \newline \usebox\myboxA}
    1096957\begin{cquote}
    1097958\setlength{\tabcolsep}{15pt}
    1098959\begin{tabular}{@{}ll@{}}
    1099960\begin{python}
    1100 Week.Thu.value == 10;
    1101 Week.Thu.name == 'Thu';
    1102 \end{python}
    1103 &
    1104 \begin{python}
    1105 Week( 10 ) == Thu
    1106 Week['Thu'].value = 10
    1107 \end{python}
    1108 \end{tabular}
    1109 \end{cquote}
     961Week.Thu.value == 4;
     962Week.Thu.name == "Thu";
     963\end{python}
     964&
     965\begin{python}
     966Week( 4 ) == Week.Thu
     967Week["Thu"].value == 4
     968\end{python}
     969\end{tabular}
     970\end{cquote}
     971@Enum@ only supports equality comparison between enumerator values.
     972There are multiple library extensions to @Enum@, \eg @OrderedEnum@ recipe class, adding relational operators @<@, @<=@, @>@, and @>=@.
    1110973
    1111974An enumeration \lstinline[language=python]{class} can have methods.
    1112975\begin{python}
    1113 class Week(Enum):
     976class Week(!OrderedEnum!):
    1114977        Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
    1115         $\\@$classmethod
    1116         def today(cls, date):
    1117                 return cls(date.isoweekday())
    1118 print( "today:", Week.today(date.today()))
    1119 today: Week.Mon
    1120 \end{python}
    1121 The method @today@ retrieves the day of the week and uses it as an index to print out the corresponding label of @Week@.
    1122 
    1123 @Flag@ allows combining several members into a single variable:
    1124 \begin{python}
    1125 print( repr(WeekF.Sat | WeekF.Sun) )
    1126 <WeekF.Sun|Sat: 96>
    1127 \end{python}
    1128 You can even iterate over a @Flag@ variable:
    1129 \begin{python}
     978        def !isWeekday(self)!:          # method
     979                return Week(self.value) !<=! Week.Fri
     980        def !isWeekend(self)!:          # method
     981                return Week.Sat !<=! Week(self.value)
     982\end{python}
     983
     984An enumeration can be used in the @if@ and @switch@ statements but only for equality tests, unless extended to @OrderedEnum@.
     985\begin{cquote}
     986\setlength{\tabcolsep}{12pt}
     987\begin{tabular}{@{}ll@{}}
     988\begin{python}
     989if day <= Week.Fri :
     990        print( "weekday" );
     991
     992
     993
     994\end{python}
     995&
     996\begin{python}
     997match day:
     998        case Week.Mon | Week.Tue | Week.Wed | Week.Thu | Week.Fri:
     999                print( "weekday" );
     1000        case Week.Sat | Week.Sun:
     1001                print( "weekend" );
     1002\end{python}
     1003\end{tabular}
     1004\end{cquote}
     1005Looping is performed using the enumeration type or @islice@ from @itertools@ based on position.
     1006\begin{python}
     1007for day in !Week!:                                      $\C[2.25in]{\# Mon : 1 Tue : 2 Wed : 3 Thu : 4 Fri : 5 Sat : 6 Sun : 7}$
     1008        print( day.name, ":", day.value, end=" " )
     1009for day in !islice(Week, 0, 5)!:        $\C{\# Mon : 1 Tue : 2 Wed : 3 Thu : 4 Fri : 5}$
     1010        print( day.name, ":", day.value, end=" " )
     1011for day in !islice(Week, 5, 7)!:        $\C{\# Sat : 6 Sun : 7}$
     1012        print( day.name, ":", day.value, end=" " )
     1013for day in !islice(Week,0, 7, 2)!:      $\C{\# Mon : 1 Wed : 3 Fri : 5 Sun : 7}\CRT$
     1014        print( day.name, ":", day.value, end=" " )
     1015\end{python}
     1016Iterating that includes alias names only (strings) is done using attribute @__members__@.
     1017\begin{python}
     1018for day in WeekD.__members__:
     1019        print( day, ":", end=" " )
     1020Mon : Tue : Wed : Thu : Fri : Sat : Sun
     1021\end{python}
     1022
     1023Enumeration subclassing is allowed only if the enumeration base-class does not define any members.
     1024\begin{python}
     1025class WeekE(OrderedEnum): !pass!;  # no members
     1026class WeekDay(WeekE): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5;
     1027class WeekEnd(WeekE): Sat = 6; Sun = 7
     1028\end{python}
     1029Here, type @WeekE@ is an abstract type because the dynamic typing never uses it.
     1030\begin{cquote}
     1031\setlength{\tabcolsep}{25pt}
     1032\begin{tabular}{@{}ll@{}}
     1033\begin{python}
     1034print( type(WeekE) )
     1035day : WeekE = WeekDay.Fri       # set type
     1036print( type(day), day )
     1037day = WeekEnd.Sat                           # set type
     1038print( type(day), day )
     1039\end{python}
     1040&
     1041\begin{python}
     1042<$class$ 'enum.EnumType'>
     1043
     1044<enum 'WeekDay'> WeekDay.Fri
     1045
     1046<enum 'WeekEnd'> WeekEnd.Sat
     1047\end{python}
     1048\end{tabular}
     1049\end{cquote}
     1050
     1051There are a number of supplied enumeration base-types: @IntEnum@, @StrEnum@, @IntFalg@, @Flag@, which restrict the values in an enum using multi-inheritance.
     1052@IntEnum@ is a subclass of @int@ and @Enum@, allowing enumerator comparison to @int@ and other enumerators of this type (like C enumerators).
     1053@StrEnum@ is the same as @IntEnum@ but a subclass of the string type \lstinline[language=python]{str}.
     1054@IntFlag@, is a restricted subclass of @int@ where the enumerators can be combined using the bitwise operators (@&@, @|@, @^@, @~@) and the result is an @IntFlag@ member.
     1055@Flag@ is the same as @IntFlag@ but cannot be combined with, nor compared against, any other @Flag@ enumeration, nor @int@.
     1056Auto increment for @IntFlag@ and @Flag@ is by powers of 2.
     1057Enumerators that are a combinations of single bit enumerators are aliases, and hence, invisible.
     1058The following is an example for @Flag@.
     1059\begin{python}
     1060class WeekF(Flag): Mon = 1; Tue = 2; Wed = 4; Thu = !auto()!; Fri = 16; Sat = 32; Sun = 64; \
     1061          Weekday = Mon | Tue | Wed | Thu | Fri; \
     1062          Weekend = Sat | Sun
     1063print( f"0x{repr(WeekF.Weekday.value)} 0x{repr(WeekF.Weekend.value)}" )
     10640x31 0x96
     1065\end{python}
     1066It is possible to enumerate through a @Flag@ enumerator (no aliases):
     1067\begin{python}
     1068for day in WeekF:
     1069        print( f"{day.name}: {day.value}", end=" ")
     1070Mon: 1 Tue: 2 Wed: 4 Thu: 8 Fri: 16 Sat: 32 Sun: 64
     1071\end{python}
     1072and a combined alias enumerator for @Flag@.
     1073\begin{cquote}
     1074\setlength{\tabcolsep}{15pt}
     1075\begin{tabular}{@{}ll@{}}
     1076\begin{python}
     1077weekday = WeekF.Weekday
     1078for day in weekday:
     1079        print( f"{day.name}:"
     1080                   f" {day.value}", end=" " )
     1081Mon: 1 Tue: 2 Wed: 4 Thu: 8 Fri: 16
     1082\end{python}
     1083&
     1084\begin{python}
     1085weekend = WeekF.Weekend
    11301086for day in weekend:
    1131         print(day)
    1132 WeekF.Sat
    1133 WeekF.Sun
    1134 \end{python}
    1135 Okay, let's get some chores set up:
    1136 \begin{python}
    1137 >>> chores_for_ethan = {
    1138 ...    'feed the cat': Week.MONDAY | Week.WEDNESDAY | Week.FRIDAY,
    1139 ...    'do the dishes': Week.TUESDAY | Week.THURSDAY,
    1140 ...    'answer SO questions': Week.SATURDAY,
    1141 ...    }
    1142 \end{python}
    1143 And a function to display the chores for a given day:
    1144 \begin{python}
    1145 >>> def show_chores(chores, day):
    1146 ...    for chore, days in chores.items():
    1147 ...        if day in days:
    1148 ...            print(chore)
    1149 >>> show_chores(chores_for_ethan, Week.SATURDAY)
    1150 answer SO questions
    1151 \end{python}
    1152 Auto incrmenet for @Flag@ is by powers of 2.
    1153 \begin{python}
    1154 class WeekF(Flag): Mon = auto(); Tue = auto(); Wed = auto(); Thu = auto(); Fri = auto();  \
    1155                                                         Sat = auto(); Sun = auto(); Weekend = Sat | Sun
    1156 for d in WeekF:
    1157         print( f"{d.name}: {d.value}", end=" ")
    1158 Mon: 1 Tue: 2 Wed: 4 Thu: 8 Fri: 16 Sat: 32 Sun: 64 WeekA.Weekend
    1159 \end{python}
    1160 
    1161 \subsection{Programmatic access to enumeration members and their attributes}
    1162 
    1163 Sometimes 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).
    1164 @Enum@ allows such access:
    1165 \begin{python}
    1166 print(RGB(1), RGB(3), )
    1167 RGB.RED RGB.GREEN
    1168 \end{python}
    1169 If you want to access enum members by name, use item access:
    1170 \begin{python}
    1171 print( RGBa['RED'], RGBa['GREEN'] )
    1172 RGB.RED RGB.GREEN
    1173 \end{python}
    1174 If you have an enum member and need its name or value:
    1175 \begin{python}
    1176 member = RGBa.RED
    1177 print( f"{member.name} {member.value}" )
    1178 RED 1
    1179 \end{python}
    1180 
    1181 
    1182 \subsection{Ensuring unique enumeration values}
    1183 
    1184 By default, enumerations allow multiple names as aliases for the same value.
    1185 When this behavior isn't desired, you can use the @unique()@ decorator:
    1186 \begin{python}
    1187 from enum import Enum, unique
    1188 $@$unique
    1189 class DupVal(Enum): ONE = 1; TWO = 2; THREE = 3; FOUR = 3
    1190 ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE
    1191 \end{python}
    1192 
    1193 \subsection{Using automatic values}
    1194 
    1195 If the exact value is unimportant you can use @auto@:
    1196 \begin{python}
    1197 from enum import Enum, auto
    1198 class RGBa(Enum): RED = auto(); BLUE = auto(); GREEN = auto()
    1199 \end{python}
    1200 (Like Golang @iota@.)
    1201 The values are chosen by @_generate_next_value_()@, which can be overridden:
    1202 \begin{python}
    1203 >>> class AutoName(Enum):
    1204 ...     $@$staticmethod
    1205 ...     def _generate_next_value_(name, start, count, last_values):
    1206 ...         return name
    1207 ...
    1208 >>> class Ordinal(AutoName):
    1209 ...     NORTH = auto()
    1210 ...     SOUTH = auto()
    1211 ...     EAST = auto()
    1212 ...     WEST = auto()
    1213 ...
    1214 >>> [member.value for member in Ordinal]
    1215 ['NORTH', 'SOUTH', 'EAST', 'WEST']
    1216 \end{python}
    1217 Note The @_generate_next_value_()@ method must be defined before any members.
    1218 
    1219 \subsection{Iteration}
    1220 
    1221 Iterating over the members of an enum does not provide the aliases:
    1222 \begin{python}
    1223 >>> list(Shape)
    1224 [<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]
    1225 >>> list(Week)
    1226 [<Week.MONDAY: 1>, <Week.TUESDAY: 2>, <Week.WEDNESDAY: 4>, <Week.THURSDAY: 8>,
    1227 <Week.FRIDAY: 16>, <Week.SATURDAY: 32>, <Week.SUNDAY: 64>]
    1228 \end{python}
    1229 Note that the aliases @Shape.ALIAS_FOR_SQUARE@ and @Week.WEEKEND@ aren't shown.
    1230 
    1231 The special attribute @__members__@ is a read-only ordered mapping of names to members.
    1232 It includes all names defined in the enumeration, including the aliases:
    1233 \begin{python}
    1234 >>> for name, member in Shape.__members__.items():
    1235 ...     name, member
    1236 ...
    1237 ('SQUARE', <Shape.SQUARE: 2>)
    1238 ('DIAMOND', <Shape.DIAMOND: 1>)
    1239 ('CIRCLE', <Shape.CIRCLE: 3>)
    1240 ('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)
    1241 \end{python}
    1242 The @__members__@ attribute can be used for detailed programmatic access to the enumeration members.
    1243 For example, finding all the aliases:
    1244 \begin{python}
    1245 >>> [name for name, member in Shape.__members__.items() if member.name != name]
    1246 ['ALIAS_FOR_SQUARE']
    1247 \end{python}
    1248 Note: Aliases for flags include values with multiple flags set, such as 3, and no flags set, i.e. 0.
    1249 
    1250 \subsection{Comparisons}
    1251 
    1252 Enumeration members are compared by identity:
    1253 \begin{python}
    1254 >>> Color.RED is Color.RED
    1255 True
    1256 >>> Color.RED is Color.BLUE
    1257 False
    1258 >>> Color.RED is not Color.BLUE
    1259 True
    1260 \end{python}
    1261 Ordered comparisons between enumeration values are not supported.
    1262 Enum members are not integers (but see @IntEnum@ below):
    1263 \begin{python}
    1264 >>> Color.RED < Color.BLUE
    1265 Traceback (most recent call last):
    1266   File "<stdin>", line 1, in <module>
    1267 TypeError: '<' not supported between instances of 'Color' and 'Color'
    1268 \end{python}
    1269 Equality comparisons are defined though:
    1270 \begin{python}
    1271 >>> Color.BLUE == Color.RED
    1272 False
    1273 >>> Color.BLUE != Color.RED
    1274 True
    1275 >>> Color.BLUE == Color.BLUE
    1276 True
    1277 \end{python}
    1278 Comparisons against non-enumeration values will always compare not equal (again, @IntEnum@ was explicitly designed to behave differently, see below):
    1279 \begin{python}
    1280 >>> Color.BLUE == 2
    1281 False
    1282 \end{python}
    1283 
    1284 Warning: 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.
    1285 
    1286 \subsection{Allowed members and attributes of enumerations}
    1287 
    1288 Most of the examples above use integers for enumeration values.
    1289 Using integers is short and handy (and provided by default by the Functional API), but not strictly enforced.
    1290 In the vast majority of use-cases, one doesn't care what the actual value of an enumeration is.
    1291 But if the value is important, enumerations can have arbitrary values.
    1292 
    1293 Enumerations are Python classes, and can have methods and special methods as usual. If we have this enumeration:
    1294 \begin{python}
    1295 >>> class Mood(Enum):
    1296 ...     FUNKY = 1
    1297 ...     HAPPY = 3
    1298 ...
    1299 ...     def describe(self):
    1300 ...         # self is the member here
    1301 ...         return self.name, self.value
    1302 ...
    1303 ...     def __str__(self):
    1304 ...         return 'my custom str! {0}'.format(self.value)
    1305 ...
    1306 ...     $@$classmethod
    1307 ...
    1308 ...     def favorite_mood(cls):
    1309 ...         # cls here is the enumeration
    1310 ...         return cls.HAPPY
    1311 ...
    1312 \end{python}
    1313 Then:
    1314 \begin{python}
    1315 >>> Mood.favorite_mood()
    1316 <Mood.HAPPY: 3>
    1317 >>> Mood.HAPPY.describe()
    1318 ('HAPPY', 3)
    1319 >>> str(Mood.FUNKY)
    1320 'my custom str! 1'
    1321 \end{python}
    1322 The 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;
    1323 all 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_@.
    1324 
    1325 Note: if your enumeration defines @__new__()@ and/or @__init__()@, any value(s) given to the enum member will be passed into those methods.
    1326 See Planet for an example.
    1327 
    1328 Note: The @__new__()@ method, if defined, is used during creation of the Enum members;
    1329 it is then replaced by Enum's @__new__()@ which is used after class creation for lookup of existing members.
    1330 See When to use @__new__()@ vs. @__init__()@ for more details.
    1331 
    1332 \subsection{Restricted Enum subclassing}
    1333 
    1334 A new @Enum@ class must have one base enum class, up to one concrete data type, and as many object-based mixin classes as needed.
    1335 The order of these base classes is:
    1336 \begin{python}
    1337 class EnumName([mix-in, ...,] [data-type,] base-enum):
    1338         pass
    1339 \end{python}
    1340 Also, subclassing an enumeration is allowed only if the enumeration does not define any members.
    1341 So this is forbidden:
    1342 \begin{python}
    1343 >>> class MoreColor(Color):
    1344 ...     PINK = 17
    1345 ...
    1346 Traceback (most recent call last):
    1347 ...
    1348 TypeError: <enum 'MoreColor'> cannot extend <enum 'Color'>
    1349 \end{python}
    1350 But this is allowed:
    1351 \begin{python}
    1352 >>> class Foo(Enum):
    1353 ...     def some_behavior(self):
    1354 ...         pass
    1355 ...
    1356 >>> class Bar(Foo):
    1357 ...     HAPPY = 1
    1358 ...     SAD = 2
    1359 ...
    1360 \end{python}
    1361 Allowing subclassing of enums that define members would lead to a violation of some important invariants of types and instances.
    1362 On the other hand, it makes sense to allow sharing some common behavior between a group of enumerations. (See OrderedEnum for an example.)
    1363 
    1364 \subsection{Dataclass support}
    1365 
    1366 When inheriting from a @dataclass@, the @__repr__()@ omits the inherited class' name.
    1367 For example:
    1368 \begin{python}
    1369 >>> from dataclasses import dataclass, field
    1370 >>> $@$dataclass
    1371 ... class CreatureDataMixin:
    1372 ...     size: str
    1373 ...     legs: int
    1374 ...     tail: bool = field(repr=False, default=True)
    1375 ...
    1376 >>> class Creature(CreatureDataMixin, Enum):
    1377 ...     BEETLE = 'small', 6
    1378 ...     DOG = 'medium', 4
    1379 ...
    1380 >>> Creature.DOG
    1381 <Creature.DOG: size='medium', legs=4>
    1382 \end{python}
    1383 Use the @dataclass()@ argument repr=False to use the standard @repr()@.
    1384 
    1385 Changed in version 3.12: Only the dataclass fields are shown in the value area, not the dataclass' name.
    1386 
    1387 \subsection{Pickling}
    1388 
    1389 Enumerations can be pickled and unpickled:
    1390 \begin{python}
    1391 >>> from test.test_enum import Fruit
    1392 >>> from pickle import dumps, loads
    1393 >>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))
    1394 True
    1395 \end{python}
    1396 The 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.
    1397 
    1398 Note: With pickle protocol version 4 it is possible to easily pickle enums nested in other classes.
    1399 
    1400 It is possible to modify how enum members are pickled/unpickled by defining @__reduce_ex__()@ in the enumeration class.
    1401 The default method is by-value, but enums with complicated values may want to use by-name:
    1402 \begin{python}
    1403 >>> import enum
    1404 >>> class MyEnum(enum.Enum):
    1405 ...     __reduce_ex__ = enum.pickle_by_enum_name
    1406 \end{python}
    1407 Note: Using by-name for flags is not recommended, as unnamed aliases will not unpickle.
    1408 
    1409 \subsection{Functional API}
    1410 
    1411 The @Enum@ class is callable, providing the following functional API:
    1412 \begin{python}
    1413 >>> Animal = Enum('Animal', 'ANT BEE CAT DOG')
    1414 >>> Animal
    1415 <enum 'Animal'>
    1416 >>> Animal.ANT
    1417 <Animal.ANT: 1>
    1418 >>> list(Animal)
    1419 [<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]
    1420 \end{python}
    1421 The semantics of this API resemble @namedtuple@.
    1422 The first argument of the call to @Enum@ is the name of the enumeration.
    1423 
    1424 The second argument is the source of enumeration member names.
    1425 It 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.
    1426 The last two options enable assigning arbitrary values to enumerations;
    1427 the others auto-assign increasing integers starting with 1 (use the @start@ parameter to specify a different starting value).
    1428 A new class derived from @Enum@ is returned.
    1429 In other words, the above assignment to Animal is equivalent to:
    1430 \begin{python}
    1431 >>> class Animal(Enum):
    1432 ...     ANT = 1
    1433 ...     BEE = 2
    1434 ...     CAT = 3
    1435 ...     DOG = 4
    1436 ...
    1437 \end{python}
    1438 The 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@.
    1439 
    1440 Pickling 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).
    1441 The solution is to specify the module name explicitly as follows:
    1442 \begin{python}
    1443 >>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)
    1444 \end{python}
    1445 Warning: 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.
    1446 
    1447 The 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.
    1448 For example, if the class was made available in class SomeData in the global scope:
    1449 \begin{python}
    1450 >>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')
    1451 \end{python}
    1452 The complete signature is:
    1453 \begin{python}
    1454 Enum(
    1455         value='NewEnumName',
    1456         names=<...>,
    1457         *,
    1458         module='...',
    1459         qualname='...',
    1460         type=<mixed-in class>,
    1461         start=1,
    1462         )
    1463 \end{python}
    1464 \begin{itemize}
    1465 \item
    1466 @value@: What the new enum class will record as its name.
    1467 \item
    1468 @names@: The enum members.
    1469 This can be a whitespace- or comma-separated string (values will start at 1 unless otherwise specified):
    1470 \begin{python}
    1471 'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'
    1472 \end{python}
    1473 or an iterator of names:
    1474 \begin{python}
    1475 ['RED', 'GREEN', 'BLUE']
    1476 \end{python}
    1477 or an iterator of (name, value) pairs:
    1478 \begin{python}
    1479 [('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]
    1480 \end{python}
    1481 or a mapping:
    1482 \begin{python}
    1483 {'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}
    1484 \end{python}
    1485 \item
    1486 module: name of module where new enum class can be found.
    1487 \item
    1488 @qualname@: where in module new enum class can be found.
    1489 \item
    1490 @type@: type to mix in to new enum class.
    1491 \item
    1492 @start@: number to start counting at if only names are passed in.
    1493 \end{itemize}
    1494 Changed in version 3.5: The start parameter was added.
    1495 
    1496 \subsection{Derived Enumerations}
    1497 
    1498 \subsection{IntEnum}
    1499 
    1500 The first variation of @Enum@ that is provided is also a subclass of @int@.
    1501 Members of an @IntEnum@ can be compared to integers;
    1502 by extension, integer enumerations of different types can also be compared to each other:
    1503 \begin{python}
    1504 >>> from enum import IntEnum
    1505 >>> class Shape(IntEnum):
    1506 ...     CIRCLE = 1
    1507 ...     SQUARE = 2
    1508 ...
    1509 >>> class Request(IntEnum):
    1510 ...     POST = 1
    1511 ...     GET = 2
    1512 ...
    1513 >>> Shape == 1
    1514 False
    1515 >>> Shape.CIRCLE == 1
    1516 True
    1517 >>> Shape.CIRCLE == Request.POST
    1518 True
    1519 \end{python}
    1520 However, they still can't be compared to standard @Enum@ enumerations:
    1521 \begin{python}
    1522 >>> class Shape(IntEnum):
    1523 ...     CIRCLE = 1
    1524 ...     SQUARE = 2
    1525 ...
    1526 >>> class Color(Enum):
    1527 ...     RED = 1
    1528 ...     GREEN = 2
    1529 ...
    1530 >>> Shape.CIRCLE == Color.RED
    1531 False
    1532 \end{python}
    1533 @IntEnum@ values behave like integers in other ways you'd expect:
    1534 \begin{python}
    1535 >>> int(Shape.CIRCLE)
    1536 1
    1537 >>> ['a', 'b', 'c'][Shape.CIRCLE]
    1538 'b'
    1539 >>> [i for i in range(Shape.SQUARE)]
    1540 [0, 1]
    1541 \end{python}
    1542 
    1543 \subsection{StrEnum}
    1544 
    1545 The second variation of @Enum@ that is provided is also a subclass of @str@.
    1546 Members of a @StrEnum@ can be compared to strings;
    1547 by extension, string enumerations of different types can also be compared to each other.
    1548 
    1549 New in version 3.11.
    1550 
    1551 \subsection{IntFlag}
    1552 
    1553 The next variation of @Enum@ provided, @IntFlag@, is also based on @int@.
    1554 The difference being @IntFlag@ members can be combined using the bitwise operators (@&, |, ^, ~@) and the result is still an @IntFlag@ member, if possible.
    1555 Like @IntEnum@, @IntFlag@ members are also integers and can be used wherever an int is used.
    1556 
    1557 Note: Any operation on an IntFlag member besides the bit-wise operations will lose the @IntFlag@ membership.
    1558 
    1559 Bit-wise operations that result in invalid @IntFlag@ values will lose the @IntFlag@ membership.
    1560 See @FlagBoundary@ for details.
    1561 
    1562 New in version 3.6.
    1563 
    1564 Changed in version 3.11.
    1565 
    1566 Sample @IntFlag@ class:
    1567 \begin{python}
    1568 >>> from enum import IntFlag
    1569 >>> class Perm(IntFlag):
    1570 ...     R = 4
    1571 ...     W = 2
    1572 ...     X = 1
    1573 ...
    1574 >>> Perm.R | Perm.W
    1575 <Perm.R|W: 6>
    1576 >>> Perm.R + Perm.W
    1577 6
    1578 >>> RW = Perm.R | Perm.W
    1579 >>> Perm.R in RW
    1580 True
    1581 \end{python}
    1582 It is also possible to name the combinations:
    1583 \begin{python}
    1584 >>> class Perm(IntFlag):
    1585 ...     R = 4
    1586 ...     W = 2
    1587 ...     X = 1
    1588 ...     RWX = 7
    1589 ...
    1590 >>> Perm.RWX
    1591 <Perm.RWX: 7>
    1592 >>> ~Perm.RWX
    1593 <Perm: 0>
    1594 >>> Perm(7)
    1595 <Perm.RWX: 7>
    1596 \end{python}
    1597 Note: Named combinations are considered aliases. Aliases do not show up during iteration, but can be returned from by-value lookups.
    1598 
    1599 Changed in version 3.11.
    1600 
    1601 Another important difference between @IntFlag@ and @Enum@ is that if no flags are set (the value is 0), its boolean evaluation is @False@:
    1602 \begin{python}
    1603 >>> Perm.R & Perm.X
    1604 <Perm: 0>
    1605 >>> bool(Perm.R & Perm.X)
    1606 False
    1607 \end{python}
    1608 Because @IntFlag@ members are also subclasses of int they can be combined with them (but may lose @IntFlag@ membership:
    1609 \begin{python}
    1610 >>> Perm.X | 4
    1611 <Perm.R|X: 5>
    1612 
    1613 >>> Perm.X + 8
    1614 9
    1615 \end{python}
    1616 Note: The negation operator, @~@, always returns an @IntFlag@ member with a positive value:
    1617 \begin{python}
    1618 >>> (~Perm.X).value == (Perm.R|Perm.W).value == 6
    1619 True
    1620 \end{python}
    1621 @IntFlag@ members can also be iterated over:
    1622 \begin{python}
    1623 >>> list(RW)
    1624 [<Perm.R: 4>, <Perm.W: 2>]
    1625 \end{python}
    1626 New in version 3.11.
    1627 
    1628 \subsection{Flag}
    1629 
    1630 The last variation is @Flag@.
    1631 Like @IntFlag@, @Flag@ members can be combined using the bitwise operators (@&, |, ^, ~@).
    1632 Unlike @IntFlag@, they cannot be combined with, nor compared against, any other @Flag@ enumeration, nor @int@.
    1633 While it is possible to specify the values directly it is recommended to use @auto@ as the value and let @Flag@ select an appropriate value.
    1634 
    1635 New in version 3.6.
    1636 
    1637 Like @IntFlag@, if a combination of @Flag@ members results in no flags being set, the boolean evaluation is @False@:
    1638 \begin{python}
    1639 >>> from enum import Flag, auto
    1640 >>> class Color(Flag):
    1641 ...     RED = auto()
    1642 ...     BLUE = auto()
    1643 ...     GREEN = auto()
    1644 ...
    1645 >>> Color.RED & Color.GREEN
    1646 <Color: 0>
    1647 >>> bool(Color.RED & Color.GREEN)
    1648 False
    1649 \end{python}
    1650 Individual flags should have values that are powers of two (1, 2, 4, 8, ...), while combinations of flags will not:
    1651 \begin{python}
    1652 >>> class Color(Flag):
    1653 ...     RED = auto()
    1654 ...     BLUE = auto()
    1655 ...     GREEN = auto()
    1656 ...     WHITE = RED | BLUE | GREEN
    1657 ...
    1658 >>> Color.WHITE
    1659 <Color.WHITE: 7>
    1660 \end{python}
    1661 Giving a name to the ``no flags set'' condition does not change its boolean value:
    1662 \begin{python}
    1663 >>> class Color(Flag):
    1664 ...     BLACK = 0
    1665 ...     RED = auto()
    1666 ...     BLUE = auto()
    1667 ...     GREEN = auto()
    1668 ...
    1669 >>> Color.BLACK
    1670 <Color.BLACK: 0>
    1671 >>> bool(Color.BLACK)
    1672 False
    1673 \end{python}
    1674 @Flag@ members can also be iterated over:
    1675 \begin{python}
    1676 >>> purple = Color.RED | Color.BLUE
    1677 >>> list(purple)
    1678 [<Color.RED: 1>, <Color.BLUE: 2>]
    1679 \end{python}
    1680 New in version 3.11.
    1681 
    1682 Note: 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).
    1683 @IntEnum@ and @IntFlag@ should be used only in cases where @Enum@ and @Flag@ will not do;
    1684 for example, when integer constants are replaced with enumerations, or for interoperability with other systems.
    1685 
    1686 \subsection{Others}
    1687 
    1688 While @IntEnum@ is part of the enum module, it would be very simple to implement independently:
    1689 \begin{python}
    1690 class IntEnum(int, Enum):
    1691         pass
    1692 \end{python}
    1693 This demonstrates how similar derived enumerations can be defined;
    1694 for example a @FloatEnum@ that mixes in float instead of @int@.
    1695 
    1696 Some rules:
    1697 \begin{itemize}
    1698 \item
    1699 When subclassing @Enum@, mix-in types must appear before @Enum@ itself in the sequence of bases, as in the @IntEnum@ example above.
    1700 \item
    1701 Mix-in types must be subclassable.
    1702 For example, @bool@ and @range@ are not subclassable and will throw an error during Enum creation if used as the mix-in type.
    1703 \item
    1704 While @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.
    1705 This restriction does not apply to mix-ins which only add methods and don't specify another type.
    1706 \item
    1707 When 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.
    1708 \item
    1709 A data type is a mixin that defines @__new__()@, or a @dataclass@
    1710 \item
    1711 \%-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.
    1712 \item
    1713 Formatted string literals, @str.format()@, and format() will use the enum's @__str__()@ method.
    1714 \end{itemize}
    1715 Note: 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.
    1716 
    1717 \subsection{When to use \lstinline{__new__()} vs. \lstinline{__init__()}}
    1718 
    1719 @__new__()@ must be used whenever you want to customize the actual value of the @Enum@ member.
    1720 Any other modifications may go in either @__new__()@ or @__init__()@, with @__init__()@ being preferred.
    1721 
    1722 For example, if you want to pass several items to the constructor, but only want one of them to be the value:
    1723 \begin{python}
    1724 >>> class Coordinate(bytes, Enum):
    1725 ...     """
    1726 ...     Coordinate with binary codes that can be indexed by the int code.
    1727 ...     """
    1728 ...     def __new__(cls, value, label, unit):
    1729 ...         obj = bytes.__new__(cls, [value])
    1730 ...         obj._value_ = value
    1731 ...         obj.label = label
    1732 ...         obj.unit = unit
    1733 ...         return obj
    1734 ...     PX = (0, 'P.X', 'km')
    1735 ...     PY = (1, 'P.Y', 'km')
    1736 ...     VX = (2, 'V.X', 'km/s')
    1737 ...     VY = (3, 'V.Y', 'km/s')
    1738 
    1739 >>> print(Coordinate['PY'])
    1740 Coordinate.PY
    1741 
    1742 >>> print(Coordinate(3))
    1743 Coordinate.VY
    1744 \end{python}
    1745 Warning: Do not call @super().__new__()@, as the lookup-only @__new__@ is the one that is found; instead, use the data type directly.
    1746 
    1747 \subsection{Finer Points}
    1748 
    1749 Supported @__dunder__@ names
    1750 
    1751 @__members__@ is a read-only ordered mapping of member\_name:member items. It is only available on the class.
    1752 
    1753 @__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.
    1754 Supported @_sunder_@ names
    1755 \begin{itemize}
    1756 \item
    1757 @_name_@ -- name of the member
    1758 \item
    1759 @_value_@ -- value of the member; can be set / modified in @__new__@
    1760 \item
    1761 @_missing_@ -- a lookup function used when a value is not found; may be overridden
    1762 \item
    1763 @_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
    1764 \item
    1765 @_order_@ -- used in Python 2/3 code to ensure member order is consistent (class attribute, removed during class creation)
    1766 \item
    1767 @_generate_@next@_value_@ -- used by the Functional API and by @auto@ to get an appropriate value for an enum member; may be overridden
    1768 \end{itemize}
    1769 Note: For standard @Enum@ classes the next value chosen is the last value seen incremented by one.
    1770 
    1771 For @Flag@ classes the next value chosen will be the next highest power-of-two, regardless of the last value seen.
    1772 
    1773 New in version 3.6: @_missing_@, @_order_@, @_generate_@next@_value_@
    1774 
    1775 New in version 3.7: @_ignore_@
    1776 
    1777 To help keep Python 2 / Python 3 code in sync an @_order_@ attribute can be provided.
    1778 It will be checked against the actual order of the enumeration and raise an error if the two do not match:
    1779 \begin{python}
    1780 >>> class Color(Enum):
    1781 ...     _order_ = 'RED GREEN BLUE'
    1782 ...     RED = 1
    1783 ...     BLUE = 3
    1784 ...     GREEN = 2
    1785 ...
    1786 Traceback (most recent call last):
    1787 ...
    1788 TypeError: member order does not match _order_:
    1789   ['RED', 'BLUE', 'GREEN']
    1790   ['RED', 'GREEN', 'BLUE']
    1791 \end{python}
    1792 Note: In Python 2 code the @_order_@ attribute is necessary as definition order is lost before it can be recorded.
    1793 
    1794 \subsection{\lstinline{_Private__names}}
    1795 
    1796 Private names are not converted to enum members, but remain normal attributes.
    1797 
    1798 Changed in version 3.11.
    1799 
    1800 \subsection{\lstinline{Enum} member type}
    1801 
    1802 @Enum@ members are instances of their enum class, and are normally accessed as @EnumClass.member@.
    1803 In certain situations, such as writing custom enum behavior, being able to access one member directly from another is useful, and is supported;
    1804 however, in order to avoid name clashes between member names and attributes/methods from mixed-in classes, upper-case names are strongly recommended.
    1805 
    1806 Changed in version 3.5.
    1807 
    1808 \subsection{Creating members that are mixed with other data types}
    1809 
    1810 When 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:
    1811 \begin{python}
    1812 >>> class MyEnum(IntEnum):      # help(int) -> int(x, base=10) -> integer
    1813 ...     example = '11', 16      # so x='11' and base=16
    1814 ...
    1815 MyEnum.example.value        # and hex(11) is...
    1816 17
    1817 \end{python}
    1818 
    1819 \subsection{\lstinline{Boolean} value of \lstinline{Enum} classes and members}
    1820 
    1821 Enum classes that are mixed with non-@Enum@ types (such as @int@, @str@, etc.) are evaluated according to the mixed-in type's rules;
    1822 otherwise, all members evaluate as @True@.
    1823 To make your own enum's boolean evaluation depend on the member's value add the following to your class:
    1824 \begin{python}
    1825 def __bool__(self):
    1826         return bool(self.value)
    1827 \end{python}
    1828 Plain @Enum@ classes always evaluate as @True@.
    1829 
    1830 \subsection{\lstinline{Enum} classes with methods}
    1831 
    1832 If 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:
    1833 \begin{python}
    1834 >>> dir(Planet)                         
    1835 ['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS',
    1836  '__class__', '__doc__', '__members__', '__module__']
    1837 >>> dir(Planet.EARTH)                   
    1838 ['__class__', '__doc__', '__module__', 'mass', 'name', 'radius', 'surface_gravity', 'value']
    1839 \end{python}
    1840 
    1841 \subsection{Combining members of \lstinline{Flag}}
    1842 
    1843 Iterating over a combination of @Flag@ members will only return the members that are comprised of a single bit:
    1844 \begin{python}
    1845 >>> class Color(Flag):
    1846 ...     RED = auto()
    1847 ...     GREEN = auto()
    1848 ...     BLUE = auto()
    1849 ...     MAGENTA = RED | BLUE
    1850 ...     YELLOW = RED | GREEN
    1851 ...     CYAN = GREEN | BLUE
    1852 ...
    1853 >>> Color(3)  # named combination
    1854 <Color.YELLOW: 3>
    1855 >>> Color(7)      # not named combination
    1856 <Color.RED|GREEN|BLUE: 7>
    1857 \end{python}
    1858 
    1859 \subsection{\lstinline{Flag} and \lstinline{IntFlag} minutia}
    1860 
    1861 Using the following snippet for our examples:
    1862 \begin{python}
    1863 >>> class Color(IntFlag):
    1864 ...     BLACK = 0
    1865 ...     RED = 1
    1866 ...     GREEN = 2
    1867 ...     BLUE = 4
    1868 ...     PURPLE = RED | BLUE
    1869 ...     WHITE = RED | GREEN | BLUE
    1870 ...
    1871 \end{python}
    1872 the following are true:
    1873 \begin{itemize}
    1874 \item
    1875 single-bit flags are canonical
    1876 \item
    1877 multi-bit and zero-bit flags are aliases
    1878 \item
    1879 only canonical flags are returned during iteration:
    1880 \begin{python}
    1881 >>> list(Color.WHITE)
    1882 [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
    1883 \end{python}
    1884 negating a flag or flag set returns a new flag/flag set with the corresponding positive integer value:
    1885 \begin{python}
    1886 >>> Color.BLUE
    1887 <Color.BLUE: 4>
    1888 
    1889 >>> ~Color.BLUE
    1890 <Color.RED|GREEN: 3>
    1891 \end{python}
    1892 \item
    1893 names of pseudo-flags are constructed from their members' names:
    1894 \begin{python}
    1895 >>> (Color.RED | Color.GREEN).name
    1896 'RED|GREEN'
    1897 \end{python}
    1898 \item
    1899 multi-bit flags, aka aliases, can be returned from operations:
    1900 \begin{python}
    1901 >>> Color.RED | Color.BLUE
    1902 <Color.PURPLE: 5>
    1903 
    1904 >>> Color(7)  # or Color(-1)
    1905 <Color.WHITE: 7>
    1906 
    1907 >>> Color(0)
    1908 <Color.BLACK: 0>
    1909 \end{python}
    1910 \item
    1911 membership / containment checking: zero-valued flags are always considered to be contained:
    1912 \begin{python}
    1913 >>> Color.BLACK in Color.WHITE
    1914 True
    1915 \end{python}
    1916 otherwise, only if all bits of one flag are in the other flag will True be returned:
    1917 \begin{python}
    1918 >>> Color.PURPLE in Color.WHITE
    1919 True
    1920 
    1921 >>> Color.GREEN in Color.PURPLE
    1922 False
    1923 \end{python}
    1924 \end{itemize}
    1925 There is a new boundary mechanism that controls how out-of-range / invalid bits are handled: @STRICT@, @CONFORM@, @EJECT@, and @KEEP@:
    1926 \begin{itemize}
    1927 \item
    1928 @STRICT@ --> raises an exception when presented with invalid values
    1929 \item
    1930 @CONFORM@ --> discards any invalid bits
    1931 \item
    1932 @EJECT@ --> lose Flag status and become a normal int with the given value
    1933 \item
    1934 @KEEP@ --> keep the extra bits
    1935 \begin{itemize}
    1936 \item
    1937 keeps Flag status and extra bits
    1938 \item
    1939 extra bits do not show up in iteration
    1940 \item
    1941 extra bits do show up in repr() and str()
    1942 \end{itemize}
    1943 \end{itemize}
    1944 The 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).
    1945 
    1946 \section{How are Enums and Flags different?}
    1947 
    1948 Enums have a custom metaclass that affects many aspects of both derived @Enum@ classes and their instances (members).
    1949 
    1950 \subsection{Enum Classes}
    1951 
    1952 The @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@.
    1953 @EnumType@ is responsible for ensuring that various other methods on the final @Enum@ class are correct (such as @__new__()@, @__getnewargs__()@, @__str__()@ and @__repr__()@).
    1954 
    1955 \subsection{Flag Classes}
    1956 
    1957 Flags 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.
    1958 So, 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.
    1959 
    1960 \subsection{Enum Members (aka instances)}
    1961 
    1962 The most interesting thing about enum members is that they are singletons.
    1963 @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.
    1964 
    1965 \subsection{Flag Members}
    1966 
    1967 Flag members can be iterated over just like the @Flag@ class, and only the canonical members will be returned.
    1968 For example:
    1969 \begin{python}
    1970 >>> list(Color)
    1971 [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 4>]
    1972 \end{python}
    1973 (Note that BLACK, PURPLE, and WHITE do not show up.)
    1974 
    1975 Inverting a flag member returns the corresponding positive value, rather than a negative value -- for example:
    1976 \begin{python}
    1977 >>> ~Color.RED
    1978 <Color.GREEN|BLUE: 6>
    1979 \end{python}
    1980 Flag members have a length corresponding to the number of power-of-two values they contain. For example:
    1981 \begin{python}
    1982 >>> len(Color.PURPLE)
    1983 2
    1984 \end{python}
    1985 
    1986 \subsection{Enum Cookbook}
    1987 
    1988 While @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.
    1989 
    1990 \subsection{Omitting values}
    1991 
    1992 In 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:
    1993 \begin{itemize}
    1994 \item
    1995 use instances of auto for the value
    1996 \item
    1997 use instances of object as the value
    1998 \item
    1999 use a descriptive string as the value
    2000 \item
    2001 use a tuple as the value and a custom @__new__()@ to replace the tuple with an @int@ value
    2002 \end{itemize}
    2003 Using 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.
    2004 
    2005 \subsection{Using \lstinline{auto}}
    2006 
    2007 Using @auto@ would look like:
    2008 \begin{python}
    2009 >>> class Color(Enum):
    2010 ...     RED = auto()
    2011 ...     BLUE = auto()
    2012 ...     GREEN = auto()
    2013 ...
    2014 >>> Color.GREEN
    2015 <Color.GREEN: 3>
    2016 \end{python}
    2017 
    2018 \subsection{Using \lstinline{object}}
    2019 
    2020 Using @object@ would look like:
    2021 \begin{python}
    2022 >>> class Color(Enum):
    2023 ...     RED = object()
    2024 ...     GREEN = object()
    2025 ...     BLUE = object()
    2026 ...
    2027 >>> Color.GREEN                         
    2028 <Color.GREEN: <object object at 0x...>>
    2029 \end{python}
    2030 This is also a good example of why you might want to write your own @__repr__()@:
    2031 \begin{python}
    2032 >>> class Color(Enum):
    2033 ...     RED = object()
    2034 ...     GREEN = object()
    2035 ...     BLUE = object()
    2036 ...     def __repr__(self):
    2037 ...         return "<%s.%s>" % (self.__class__.__name__, self._name_)
    2038 ...
    2039 >>> Color.GREEN
    2040 <Color.GREEN>
    2041 \end{python}
    2042 
    2043 \subsection{Using a descriptive string}
    2044 
    2045 Using a string as the value would look like:
    2046 \begin{python}
    2047 >>> class Color(Enum):
    2048 ...     RED = 'stop'
    2049 ...     GREEN = 'go'
    2050 ...     BLUE = 'too fast!'
    2051 ...
    2052 >>> Color.GREEN
    2053 <Color.GREEN: 'go'>
    2054 \end{python}
    2055 
    2056 \subsection{Using a custom \lstinline{__new__()}}
    2057 
    2058 Using an auto-numbering @__new__()@ would look like:
    2059 \begin{python}
    2060 >>> class AutoNumber(Enum):
    2061 ...     def __new__(cls):
    2062 ...         value = len(cls.__members__) + 1
    2063 ...         obj = object.__new__(cls)
    2064 ...         obj._value_ = value
    2065 ...         return obj
    2066 ...
    2067 >>> class Color(AutoNumber):
    2068 ...     RED = ()
    2069 ...     GREEN = ()
    2070 ...     BLUE = ()
    2071 ...
    2072 >>> Color.GREEN
    2073 <Color.GREEN: 2>
    2074 \end{python}
    2075 To make a more general purpose @AutoNumber@, add @*args@ to the signature:
    2076 \begin{python}
    2077 >>> class AutoNumber(Enum):
    2078 ...     def __new__(cls, *args):      # this is the only change from above
    2079 ...         value = len(cls.__members__) + 1
    2080 ...         obj = object.__new__(cls)
    2081 ...         obj._value_ = value
    2082 ...         return obj
    2083 \end{python}
    2084 Then when you inherit from @AutoNumber@ you can write your own @__init__@ to handle any extra arguments:
    2085 \begin{python}
    2086 >>> class Swatch(AutoNumber):
    2087 ...     def __init__(self, pantone='unknown'):
    2088 ...         self.pantone = pantone
    2089 ...     AUBURN = '3497'
    2090 ...     SEA_GREEN = '1246'
    2091 ...     BLEACHED_CORAL = () # New color, no Pantone code yet!
    2092 ...
    2093 >>> Swatch.SEA_GREEN
    2094 <Swatch.SEA_GREEN: 2>
    2095 >>> Swatch.SEA_GREEN.pantone
    2096 '1246'
    2097 >>> Swatch.BLEACHED_CORAL.pantone
    2098 'unknown'
    2099 \end{python}
    2100 Note: The @__new__()@ method, if defined, is used during creation of the Enum members;
    2101 it is then replaced by Enum's @__new__()@ which is used after class creation for lookup of existing members.
    2102 
    2103 Warning: Do not call @super().__new__()@, as the lookup-only @__new__@ is the one that is found;
    2104 instead, use the data type directly -- e.g.:
    2105 \begin{python}
    2106 obj = int.__new__(cls, value)
    2107 \end{python}
    2108 
    2109 \subsection{OrderedEnum}
    2110 
    2111 An ordered enumeration that is not based on @IntEnum@ and so maintains the normal @Enum@ invariants (such as not being comparable to other enumerations):
    2112 \begin{python}
    2113 >>> class OrderedEnum(Enum):
    2114 ...     def __ge__(self, other):
    2115 ...         if self.__class__ is other.__class__:
    2116 ...             return self.value >= other.value
    2117 ...         return NotImplemented
    2118 ...     def __gt__(self, other):
    2119 ...         if self.__class__ is other.__class__:
    2120 ...             return self.value > other.value
    2121 ...         return NotImplemented
    2122 ...     def __le__(self, other):
    2123 ...         if self.__class__ is other.__class__:
    2124 ...             return self.value <= other.value
    2125 ...         return NotImplemented
    2126 ...     def __lt__(self, other):
    2127 ...         if self.__class__ is other.__class__:
    2128 ...             return self.value < other.value
    2129 ...         return NotImplemented
    2130 ...
    2131 >>> class Grade(OrderedEnum):
    2132 ...     A = 5
    2133 ...     B = 4
    2134 ...     C = 3
    2135 ...     D = 2
    2136 ...     F = 1
    2137 >>> Grade.C < Grade.A
    2138 True
    2139 \end{python}
    2140 
    2141 \subsection{DuplicateFreeEnum}
    2142 
    2143 Raises an error if a duplicate member value is found instead of creating an alias:
    2144 \begin{python}
    2145 >>> class DuplicateFreeEnum(Enum):
    2146 ...     def __init__(self, *args):
    2147 ...         cls = self.__class__
    2148 ...         if any(self.value == e.value for e in cls):
    2149 ...             a = self.name
    2150 ...             e = cls(self.value).name
    2151 ...             raise ValueError(
    2152 ...                 "aliases not allowed in DuplicateFreeEnum:  %r --> %r"
    2153 ...                 % (a, e))
    2154 >>> class Color(DuplicateFreeEnum):
    2155 ...     RED = 1
    2156 ...     GREEN = 2
    2157 ...     BLUE = 3
    2158 ...     GRENE = 2
    2159 ...
    2160 Traceback (most recent call last):
    2161   ...
    2162 ValueError: aliases not allowed in DuplicateFreeEnum:  'GRENE' --> 'GREEN'
    2163 \end{python}
    2164 Note: This is a useful example for subclassing Enum to add or change other behaviors as well as disallowing aliases.
    2165 If the only desired change is disallowing aliases, the @unique()@ decorator can be used instead.
    2166 
    2167 \subsection{Planet}
    2168 
    2169 If @__new__()@ or @__init__()@ is defined, the value of the enum member will be passed to those methods:
    2170 \begin{figure}
    2171 \begin{python}
    2172 from enum import Enum
    2173 class Planet(Enum):
    2174         MERCURY = ( 3.303E23, 2.4397E6 )
    2175         VENUS       = ( 4.869E24, 6.0518E6 )
    2176         EARTH       = (5.976E24, 6.37814E6)
    2177         MARS         = (6.421E23, 3.3972E6)
    2178         JUPITER    = (1.9E27,   7.1492E7)
    2179         SATURN     = (5.688E26, 6.0268E7)
    2180         URANUS    = (8.686E25, 2.5559E7)
    2181         NEPTUNE  = (1.024E26, 2.4746E7)
    2182         def __init__( self, mass, radius ):
    2183                 self.mass = mass                # in kilograms
    2184                 self.radius = radius    # in meters
    2185         def surface_gravity( self ):
    2186                 # universal gravitational constant  (m3 kg-1 s-2)
    2187                 G = 6.67300E-11
    2188                 return G * self.mass / (self.radius * self.radius)
    2189 for p in Planet:
    2190         print( f"{p.name}: {p.value}" )
    2191 
    2192 MERCURY: (3.303e+23, 2439700.0)
    2193 VENUS: (4.869e+24, 6051800.0)
    2194 EARTH: (5.976e+24, 6378140.0)
    2195 MARS: (6.421e+23, 3397200.0)
    2196 JUPITER: (1.9e+27, 71492000.0)
    2197 SATURN: (5.688e+26, 60268000.0)
    2198 URANUS: (8.686e+25, 25559000.0)
    2199 NEPTUNE: (1.024e+26, 24746000.0)
    2200 \end{python}
    2201 \caption{Python Planet Example}
    2202 \label{f:PythonPlanetExample}
    2203 \end{figure}
    2204 
    2205 
    2206 \subsection{TimePeriod}
    2207 
    2208 An example to show the @_ignore_@ attribute in use:
    2209 \begin{python}
    2210 >>> from datetime import timedelta
    2211 >>> class Period(timedelta, Enum):
    2212 ...     "different lengths of time"
    2213 ...     _ignore_ = 'Period i'
    2214 ...     Period = vars()
    2215 ...     for i in range(367):
    2216 ...         Period['day_%d' % i] = i
    2217 ...
    2218 >>> list(Period)[:2]
    2219 [<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]
    2220 >>> list(Period)[-2:]
    2221 [<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]
    2222 \end{python}
    2223 
    2224 \subsection{Subclassing EnumType}
    2225 
    2226 While 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.
     1087        print( f"{day.name}:"
     1088                   f" {day.value}", end=" " )
     1089Sat: 32 Sun: 64
     1090\end{python}
     1091\end{tabular}
     1092\end{cquote}
    22271093
    22281094
     
    22941160In summary, an OCaml variant is a singleton value rather than a set of possibly ordered values, and hence, has no notion of enumerabilty.
    22951161Therefore it is not an enumeration, except for the simple opaque (nullary) case.
     1162
     1163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    22961164
    22971165\begin{comment}
     
    24421310To: Gregor Richards <gregor.richards@uwaterloo.ca>, Peter Buhr <pabuhr@uwaterloo.ca>
    24431311CC: Michael Leslie Brooks <mlbrooks@uwaterloo.ca>, Fangren Yu <f37yu@uwaterloo.ca>,
    2444     Jiada Liang <j82liang@uwaterloo.ca>
     1312        Jiada Liang <j82liang@uwaterloo.ca>
    24451313Subject: Re: Re:
    24461314Date: Thu, 21 Mar 2024 14:26:36 +0000
     
    24501318
    24511319enum Example {
    2452     Label,
    2453     Name = 10,
    2454     Tag = 3,
     1320        Label,
     1321        Name = 10,
     1322        Tag = 3,
    24551323};
    24561324
     
    25421410auto-init               &               &               &               &               &               &               &               &               &               &               & \CM   & \CM   & \CM   \\
    25431411\hline
    2544 (un)scoped              &               &               &               &               &               &               &               &               &               &               & U             & U/S   & U/S   \\
     1412(Un)Scoped              &               &               &               &               &               &               &               &               &               &               & U             & U/S   & U/S   \\
    25451413\hline
    25461414overload                &               & \CM   &               &               &               &               &               &               &               &               &               & \CM   & \CM   \\
Note: See TracChangeset for help on using the changeset viewer.