Changeset 486caad for doc/theses/jiada_liang_MMath/relatedwork.tex
- Timestamp:
- Mar 25, 2024, 7:15:30 PM (6 months ago)
- Branches:
- master
- Children:
- d734fa1
- Parents:
- df78cce (diff), bf050c5 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/theses/jiada_liang_MMath/relatedwork.tex
rdf78cce r486caad 2 2 \label{s:RelatedWork} 3 3 4 \begin{comment} 4 5 An algebraic data type (ADT) can be viewed as a recursive sum of product types. 5 6 A sum type lists values as members. … … 15 16 Enumerated types are a special case of product/sum types with non-mutable fields, \ie initialized (constructed) once at the type's declaration, possible restricted to compile-time initialization. 16 17 Values of algebraic types are access by subscripting, field qualification, or type (pattern) matching. 18 \end{comment} 17 19 18 20 Enumeration types exist in many popular programming languages, both past and present, \eg Pascal~\cite{Pascal}, Ada~\cite{Ada}, \Csharp~\cite{Csharp}, OCaml~\cite{OCaml} \CC, Go~\cite{Go}, Java~\cite{Java}, Modula-3~\cite{Modula-3}, Rust~\cite{Rust}, Swift~\cite{Swift}, Python~\cite{Python}. … … 20 22 21 23 \section{Pascal} 24 \label{s:Pascal} 22 25 \lstnewenvironment{pascal}[1][]{\lstset{language=pascal,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{} 23 26 … … 27 30 PI = 3.14159; Plus = '+'; Fred = 'Fred'; 28 31 \end{pascal} 29 Here, there is noenumeration because there is no specific type (pseudo enumeration).32 This mechanism is not an enumeration because there is no specific type (pseudo enumeration). 30 33 Hence, there is no notion of a (possibly ordered) set, modulo the \lstinline[language=pascal]{set of} type. 31 34 The type of each constant name (enumerator) is inferred from the constant-expression type. … … 81 84 with Ada.Text_IO; use Ada.Text_IO; 82 85 procedure test is 83 84 85 86 87 88 89 90 86 type RGB is ( @Red@, Green, Blue ); 87 type Traffic_Light is ( @Red@, Yellow, Green ); -- overload 88 procedure @Red@( Colour : RGB ) is begin -- overload 89 Put_Line( "Colour is " & RGB'Image( Colour ) ); 90 end Red; 91 procedure @Red@( TL : Traffic_Light ) is begin -- overload 92 Put_Line( "Light is " & Traffic_Light'Image( TL ) ); 93 end Red; 91 94 begin 92 93 94 95 @Red@( Blue ); -- RGB 96 @Red@( Yellow ); -- Traffic_Light 97 @Red@( @RGB'(Red)@ ); -- ambiguous without cast 95 98 end test; 96 99 \end{ada} … … 224 227 \lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{} 225 228 226 \CC is largely backwards compatible with C, so it inherited C's enumerations. 227 However, the following non-backwards compatible changes have been made. 229 \CC has the equivalent of Pascal typed @const@ declarations \see{\VRef{s:Pascal}}, with static and dynamic initialization. 230 \begin{c++} 231 const auto one = 0 + 1; $\C{// static intialization}$ 232 const auto NULL = nullptr; 233 const auto PI = 3.14159; 234 const auto Plus = '+'; 235 const auto Fred = "Fred"; 236 const auto Mon = 0, Tue = Mon + 1, Wed = Tue + 1, Thu = Wed + 1, Fri = Thu + 1, 237 Sat = Fri + 1, Sun = Sat + 1; 238 int sa[Sun]; 239 const auto r = random(); $\C{// dynamic intialization}$ 240 int da[r]; $\C{// VLA}$ 241 \end{c++} 242 Statically initialized identifiers may appear in any constant-expression context, \eg @case@. 243 Dynamically intialized identifiers may appear as array dimensions in @g++@, which allows variable-sized arrays. 244 Interestingly, global \CC @const@ declarations are implicitly marked @static@ (@r@ rather than @R@). 245 \begin{c++} 246 $\$$ nm test.o 247 0000000000000018 @r@ Mon 248 \end{c++} 249 250 \CC enumeration is largely backwards compatible with C, so it inherited C's enumerations. 251 However, the following non-backwards compatible changes are made. 228 252 229 253 \begin{cquote} … … 423 447 \begin{Go} 424 448 const ( Mon = iota; Tue; Wed; // 0, 1, 2 425 449 @Thu = 10@; Fri; Sat; Sun ) // 10, 10, 10, 10 426 450 \end{Go} 427 451 Auto-incrementing can be restarted with an expression containing \emph{one} \lstinline[language=Go]{iota}. … … 429 453 const ( V1 = iota; V2; @V3 = 7;@ V4 = @iota@; V5 ) // 0 1 7 3 4 430 454 const ( Mon = iota; Tue; Wed; // 0, 1, 2 431 455 @Thu = 10;@ Fri = @iota - Wed + Thu - 1@; Sat; Sun ) // 10, 11, 12, 13 432 456 \end{Go} 433 457 Note, \lstinline[language=Go]{iota} is advanced for an explicitly initialized enumerator, like the underscore @_@ identifier. … … 584 608 \lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{} 585 609 586 Enumerations 610 Rust provides a scoped enumeration based on variant types. 611 % An enumeration, also referred to as an enum, is a simultaneous definition of a nominal enumerated type as well as a set of constructors, that can be used to create or pattern-match values of the corresponding enumerated type. 612 An enumeration without constructors is called field-less. 587 613 \begin{rust} 588 Syntax 589 Enumeration : 590 enum IDENTIFIER GenericParams? WhereClause? { EnumItems? } 591 592 EnumItems : 593 EnumItem ( , EnumItem )* ,? 594 595 EnumItem : 596 OuterAttribute* Visibility? 597 IDENTIFIER ( EnumItemTuple | EnumItemStruct )? EnumItemDiscriminant? 598 599 EnumItemTuple : 600 ( TupleFields? ) 601 602 EnumItemStruct : 603 { StructFields? } 604 605 EnumItemDiscriminant : 606 = Expression 614 enum Week { Mon, Tues, Wed, Thu, Fri, Sat, Sun@,@ } 615 let mut week: Week = Week::Mon; 616 week = Week::Fri; 607 617 \end{rust} 608 An enumeration, also referred to as an enum, is a simultaneous definition of a nominal enumerated type as well as a set of constructors, that can be used to create or pattern-match values of the corresponding enumerated type. 609 610 Enumerations are declared with the keyword enum. 611 612 An example of an enum item and its use: 618 A field-less enumeration with only unit variants is called unit-only. 613 619 \begin{rust} 614 enum Animal { 615 Dog, 616 Cat, 617 } 618 619 let mut a: Animal = Animal::Dog; 620 a = Animal::Cat; 620 enum Week { Mon = 0, Tues = 1, Wed = 2, Thu = 3, Fri = 4, Sat = 5, Sun = 6 } 621 621 \end{rust} 622 622 Enum constructors can have either named or unnamed fields: 623 623 \begin{rust} 624 624 enum Animal { 625 Dog(String, f64), 626 Cat { name: String, weight: f64 }, 627 } 628 625 Dog( String, f64 ), 626 Cat{ name: String, weight: f64 }, 627 } 629 628 let mut a: Animal = Animal::Dog("Cocoa".to_string(), 37.2); 630 629 a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 }; 631 630 \end{rust} 632 In this example, Cat is a struct-like enum variant, whereas Dog is simply called an enum variant. 633 634 An enum where no constructors contain fields are called a field-less enum. For example, this is a fieldless enum: 631 Here, @Dog@ is an @enum@ variant, whereas @Cat@ is a struct-like variant. 632 633 Each @enum@ type has an implicit integer tag (discriminant), with a unique value for each variant type. 634 Like a C enumeration, the tag values for the variant types start at 0 with auto incrementing. 635 The tag is re-purposed for enumeration by allowing it to be explicitly set, and auto incrmenting continues from that value. 636 \begin{cquote} 637 \sf\setlength{\tabcolsep}{3pt} 638 \begin{tabular}{rcccccccr} 639 @enum@ Week \{ & Mon, & Tue, & Wed = 2, & Thu = 10, & Fri, & Sat = 5, & Sun & \}; \\ 640 \rm tags & 0 & 1 & 2 & 10 & 11 & 5 & 6 & \\ 641 \end{tabular} 642 \end{cquote} 643 In general, the tag can only be read as an opaque reference for comparison. 635 644 \begin{rust} 636 enum Fieldless { 637 Tuple(), 638 Struct{}, 639 Unit, 640 } 645 if mem::discriminant(&week) == mem::discriminant(&Week::Mon) ... 641 646 \end{rust} 642 If a field-less enum only contains unit variants, the enum is called an unit-only enum. For example:647 If the enumeration is unit-only, or field-less with no explicit discriminants and where only unit variants are explicit, then the discriminant is accessible with a numeric cast. 643 648 \begin{rust} 644 enum Enum { 645 Foo = 3, 646 Bar = 2, 647 Baz = 1, 648 } 649 \end{rust} 650 651 \subsection{Discriminants} 652 653 Each enum instance has a discriminant: an integer logically associated to it that is used to determine which variant it holds. 654 655 Under the default representation, the discriminant is interpreted as an isize value. However, the compiler is allowed to use a smaller type (or another means of distinguishing variants) in its actual memory layout. 656 657 \subsection{Assigning discriminant values} 658 659 \subsection{Explicit discriminants} 660 661 In two circumstances, the discriminant of a variant may be explicitly set by following the variant name with = and a constant expression: 662 663 if the enumeration is "unit-only". 664 665 if a primitive representation is used. For example: 666 \begin{rust} 667 #[repr(u8)] 668 enum Enum { 669 Unit = 3, 670 Tuple(u16), 671 Struct { 672 a: u8, 673 b: u16, 674 } = 1, 675 } 676 \end{rust} 677 678 \subsection{Implicit discriminants} 679 680 If a discriminant for a variant is not specified, then it is set to one higher than the discriminant of the previous variant in the declaration. If the discriminant of the first variant in the declaration is unspecified, then it is set to zero. 681 \begin{rust} 682 enum Foo { 683 Bar, // 0 684 Baz = 123, // 123 685 Quux, // 124 686 } 687 688 let baz_discriminant = Foo::Baz as u32; 689 assert_eq!(baz_discriminant, 123); 690 \end{rust} 691 692 \subsection{Restrictions} 693 694 It is an error when two variants share the same discriminant. 695 \begin{rust} 696 enum SharedDiscriminantError { 697 SharedA = 1, 698 SharedB = 1 699 } 700 701 enum SharedDiscriminantError2 { 702 Zero, // 0 703 One, // 1 704 OneToo = 1 // 1 (collision with previous!) 705 } 706 \end{rust} 707 It is also an error to have an unspecified discriminant where the previous discriminant is the maximum value for the size of the discriminant. 708 \begin{rust} 709 #[repr(u8)] 710 enum OverflowingDiscriminantError { 711 Max = 255, 712 MaxPlusOne // Would be 256, but that overflows the enum. 713 } 714 715 #[repr(u8)] 716 enum OverflowingDiscriminantError2 { 717 MaxMinusOne = 254, // 254 718 Max, // 255 719 MaxPlusOne // Would be 256, but that overflows the enum. 720 } 721 \end{rust} 722 723 \subsection{Accessing discriminant} 724 725 \begin{rust} 726 Via mem::discriminant 727 \end{rust} 728 @mem::discriminant@ returns an opaque reference to the discriminant of an enum value which can be compared. This cannot be used to get the value of the discriminant. 729 730 \subsection{Casting} 731 732 If an enumeration is unit-only (with no tuple and struct variants), then its discriminant can be directly accessed with a numeric cast; e.g.: 733 \begin{rust} 734 enum Enum { 735 Foo, 736 Bar, 737 Baz, 738 } 739 740 assert_eq!(0, Enum::Foo as isize); 741 assert_eq!(1, Enum::Bar as isize); 742 assert_eq!(2, Enum::Baz as isize); 743 \end{rust} 744 Field-less enums can be casted if they do not have explicit discriminants, or where only unit variants are explicit. 745 \begin{rust} 746 enum Fieldless { 747 Tuple(), 748 Struct{}, 749 Unit, 750 } 751 752 assert_eq!(0, Fieldless::Tuple() as isize); 753 assert_eq!(1, Fieldless::Struct{} as isize); 754 assert_eq!(2, Fieldless::Unit as isize); 755 \end{rust} 756 \begin{rust} 757 #[repr(u8)] 758 enum FieldlessWithDiscrimants { 759 First = 10, 760 Tuple(), 761 Second = 20, 762 Struct{}, 763 Unit, 764 } 765 766 assert_eq!(10, FieldlessWithDiscrimants::First as u8); 767 assert_eq!(11, FieldlessWithDiscrimants::Tuple() as u8); 768 assert_eq!(20, FieldlessWithDiscrimants::Second as u8); 769 assert_eq!(21, FieldlessWithDiscrimants::Struct{} as u8); 770 assert_eq!(22, FieldlessWithDiscrimants::Unit as u8); 771 \end{rust} 772 773 \subsection{Pointer casting} 774 775 If the enumeration specifies a primitive representation, then the discriminant may be reliably accessed via unsafe pointer casting: 776 \begin{rust} 777 #[repr(u8)] 778 enum Enum { 779 Unit, 780 Tuple(bool), 781 Struct{a: bool}, 782 } 783 784 impl Enum { 785 fn discriminant(&self) -> u8 { 786 unsafe { *(self as *const Self as *const u8) } 787 } 788 } 789 790 let unit_like = Enum::Unit; 791 let tuple_like = Enum::Tuple(true); 792 let struct_like = Enum::Struct{a: false}; 793 794 assert_eq!(0, unit_like.discriminant()); 795 assert_eq!(1, tuple_like.discriminant()); 796 assert_eq!(2, struct_like.discriminant()); 797 \end{rust} 798 799 \subsection{Zero-variant enums} 800 801 Enums with zero variants are known as zero-variant enums. As they have no valid values, they cannot be instantiated. 802 \begin{rust} 803 enum ZeroVariants {} 804 \end{rust} 805 Zero-variant enums are equivalent to the never type, but they cannot be coerced into other types. 806 \begin{rust} 807 let x: ZeroVariants = panic!(); 808 let y: u32 = x; // mismatched type error 809 \end{rust} 810 811 \subsection{Variant visibility} 812 813 Enum variants syntactically allow a Visibility annotation, but this is rejected when the enum is validated. This allows items to be parsed with a unified syntax across different contexts where they are used. 814 \begin{rust} 815 macro_rules! mac_variant { 816 ($vis:vis $name:ident) => { 817 enum $name { 818 $vis Unit, 819 820 $vis Tuple(u8, u16), 821 822 $vis Struct { f: u8 }, 823 } 824 } 825 } 826 827 // Empty `vis` is allowed. 828 mac_variant! { E } 829 830 // This is allowed, since it is removed before being validated. 831 #[cfg(FALSE)] 832 enum E { 833 pub U, 834 pub(crate) T(u8), 835 pub(super) T { f: String } 836 } 649 if week as isize == Week::Mon as isize ... 837 650 \end{rust} 838 651 … … 1200 1013 \lstnewenvironment{python}[1][]{\lstset{language=Python,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{} 1201 1014 1202 An @Enum@ is a set of symbolic names bound to unique values. 1203 They are similar to global variables, but they offer a more useful @repr()@, grouping, type-safety, and a few other features. 1204 1205 They are most useful when you have a variable that can take one of a limited selection of values. For example, the days of the week: 1206 \begin{python} 1207 >>> from enum import Enum 1208 >>> class Weekday(Enum): 1209 ... MONDAY = 1 1210 ... TUESDAY = 2 1211 ... WEDNESDAY = 3 1212 ... THURSDAY = 4 1213 ... FRIDAY = 5 1214 ... SATURDAY = 6 1215 ... SUNDAY = 7 1216 \end{python} 1217 Or perhaps the RGB primary colors: 1218 \begin{python} 1219 >>> from enum import Enum 1220 >>> class Color(Enum): 1221 ... RED = 1 1222 ... GREEN = 2 1223 ... BLUE = 3 1224 \end{python} 1225 As you can see, creating an @Enum@ is as simple as writing a class that inherits from @Enum@ itself. 1226 1227 Note: Case of Enum Members 1228 1229 Because Enums are used to represent constants, and to help avoid issues with name clashes between mixin-class methods/attributes and enum names, we strongly recommend using @UPPER_CASE@ names for members, and will be using that style in our examples. 1015 A Python enumeration is a set of symbolic names bound to \emph{unique} values. 1016 They are similar to global variables, but offer a more useful @repr()@, grouping, type-safety, and additional features. 1017 Enumerations inherits from the @Enum@ class, \eg: 1018 \begin{python} 1019 class Weekday(@Enum@): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7 1020 class RGB(@Enum@): Red = 1; Green = 2; Blue = 3 1021 \end{python} 1230 1022 1231 1023 Depending on the nature of the enum a member's value may or may not be important, but either way that value can be used to get the corresponding member: 1232 1024 \begin{python} 1233 >>> Weekday(3)1234 <Weekday.W EDNESDAY: 3>1025 print( repr( Weekday( 3 ) ) ) 1026 <Weekday.Wed: 3> 1235 1027 \end{python} 1236 1028 As you can see, the @repr()@ of a member shows the enum name, the member name, and the value. 1237 1029 The @str()@ of a member shows only the enum name and member name: 1238 1030 \begin{python} 1239 print( Weekday.THURSDAY)1240 Weekday.T HURSDAY1031 print( str( Weekday.Thu ), Weekday.Thu ) 1032 Weekday.Thu Weekday.Thu 1241 1033 \end{python} 1242 1034 The type of an enumeration member is the enum it belongs to: 1243 1035 \begin{python} 1244 >>> type(Weekday.MONDAY)1036 print( type( Weekday.Thu ) ) 1245 1037 <enum 'Weekday'> 1246 isinstance(Weekday.FRIDAY, Weekday)1038 print( isinstance(Weekday.Fri, Weekday) ) 1247 1039 True 1248 1040 \end{python} 1249 1041 Enum members have an attribute that contains just their name: 1250 1042 \begin{python} 1251 >>>print(Weekday.TUESDAY.name)1043 print(Weekday.TUESDAY.name) 1252 1044 TUESDAY 1253 1045 \end{python} 1254 1046 Likewise, they have an attribute for their value: 1255 1047 \begin{python} 1256 >>>Weekday.WEDNESDAY.value1048 Weekday.WEDNESDAY.value 1257 1049 3 1258 1050 \end{python} 1051 1259 1052 Unlike many languages that treat enumerations solely as name/value pairs, Python @Enum@s can have behavior added. 1260 1053 For example, @datetime.date@ has two methods for returning the weekday: @weekday()@ and @isoweekday()@. … … 1262 1055 Rather than keep track of that ourselves we can add a method to the @Weekday@ enum to extract the day from the date instance and return the matching enum member: 1263 1056 \begin{python} 1057 class Weekday(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = 15; Sat = 16; Sun = 17 1264 1058 $@$classmethod 1265 1059 def from_date(cls, date): 1266 return cls(date.isoweekday()) 1267 \end{python} 1268 The complete Weekday enum now looks like this: 1269 \begin{python} 1270 >>> class Weekday(Enum): 1271 ... MONDAY = 1 1272 ... TUESDAY = 2 1273 ... WEDNESDAY = 3 1274 ... THURSDAY = 4 1275 ... FRIDAY = 5 1276 ... SATURDAY = 6 1277 ... SUNDAY = 7 1278 ... # 1279 ... $@$classmethod 1280 ... def from_date(cls, date): 1281 ... return cls(date.isoweekday()) 1060 return cls(date.isoweekday()) 1282 1061 \end{python} 1283 1062 Now we can find out what today is! Observe: … … 1291 1070 This Weekday enum is great if our variable only needs one day, but what if we need several? Maybe we're writing a function to plot chores during a week, and don't want to use a @list@ -- we could use a different type of @Enum@: 1292 1071 \begin{python} 1293 >>> from enum import Flag 1294 >>> class Weekday(Flag): 1295 ... MONDAY = 1 1296 ... TUESDAY = 2 1297 ... WEDNESDAY = 4 1298 ... THURSDAY = 8 1299 ... FRIDAY = 16 1300 ... SATURDAY = 32 1301 ... SUNDAY = 64 1072 from enum import Flag 1073 class WeekdayF(@Flag@): Mon = @1@; Tue = @2@; Wed = @4@; Thu = @8@; Fri = @16@; Sat = @32@; Sun = @64@ 1302 1074 \end{python} 1303 1075 We've changed two things: we're inherited from @Flag@, and the values are all powers of 2. 1304 1076 1305 Just like the original @Weekday@ enum above, we can have a single selection: 1306 \begin{python} 1307 >>> first_week_day = Weekday.MONDAY 1308 >>> first_week_day 1309 <Weekday.MONDAY: 1> 1310 \end{python} 1311 But @Flag@ also allows us to combine several members into a single variable: 1312 \begin{python} 1313 >>> weekend = Weekday.SATURDAY | Weekday.SUNDAY 1314 >>> weekend 1315 <Weekday.SATURDAY|SUNDAY: 96> 1077 @Flag@ allows combining several members into a single variable: 1078 \begin{python} 1079 print( repr(WeekdayF.Sat | WeekdayF.Sun) ) 1080 <WeekdayF.Sun|Sat: 96> 1316 1081 \end{python} 1317 1082 You can even iterate over a @Flag@ variable: 1318 1083 \begin{python} 1319 >>>for day in weekend:1320 ...print(day)1084 for day in weekend: 1085 print(day) 1321 1086 Weekday.SATURDAY 1322 1087 Weekday.SUNDAY … … 1382 1147 \subsection{Duplicating enum members and values} 1383 1148 1384 Having two enum members with the same name is invalid: 1385 \begin{python} 1386 >>> class Shape(Enum): 1387 ... SQUARE = 2 1388 ... SQUARE = 3 1389 ... 1390 Traceback (most recent call last): 1391 ... 1392 TypeError: 'SQUARE' already defined as 2 1393 \end{python} 1394 However, an enum member can have other names associated with it. 1149 An enum member can have other names associated with it. 1395 1150 Given two entries @A@ and @B@ with the same value (and @A@ defined first), @B@ is an alias for the member @A@. 1396 1151 By-value lookup of the value of @A@ will return the member @A@. … … 1398 1153 By-name lookup of @B@ will also return the member @A@: 1399 1154 \begin{python} 1400 >>> class Shape(Enum): 1401 ... SQUARE = 2 1402 ... DIAMOND = 1 1403 ... CIRCLE = 3 1404 ... ALIAS_FOR_SQUARE = 2 1405 ... 1155 class Shape(Enum): SQUARE = 2; DIAMOND = 1; CIRCLE = 3; ALIAS_FOR_SQUARE = 2 1406 1156 >>> Shape.SQUARE 1407 1157 <Shape.SQUARE: 2> … … 1419 1169 When this behavior isn't desired, you can use the @unique()@ decorator: 1420 1170 \begin{python} 1421 >>> from enum import Enum, unique 1422 >>> $@$unique 1423 ... class Mistake(Enum): 1424 ... ONE = 1 1425 ... TWO = 2 1426 ... THREE = 3 1427 ... FOUR = 3 1428 ... 1429 Traceback (most recent call last): 1430 ... 1171 from enum import Enum, unique 1172 $@$unique 1173 class DupVal(Enum): ONE = 1; TWO = 2; THREE = 3; FOUR = 3 1431 1174 ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE 1432 1175 \end{python} … … 1436 1179 If the exact value is unimportant you can use @auto@: 1437 1180 \begin{python} 1438 >>> from enum import Enum, auto 1439 >>> class Color(Enum): 1440 ... RED = auto() 1441 ... BLUE = auto() 1442 ... GREEN = auto() 1443 ... 1444 >>> [member.value for member in Color] 1445 [1, 2, 3] 1446 \end{python} 1447 The values are chosen by \_generate\_next\_value\_(), which can be overridden: 1181 from enum import Enum, auto 1182 class RGBa(Enum): RED = auto(); BLUE = auto(); GREEN = auto() 1183 \end{python} 1184 (Like Golang @iota@.) 1185 The values are chosen by @_generate_next_value_()@, which can be overridden: 1448 1186 \begin{python} 1449 1187 >>> class AutoName(Enum): … … 1582 1320 \begin{python} 1583 1321 class EnumName([mix-in, ...,] [data-type,] base-enum): 1584 1322 pass 1585 1323 \end{python} 1586 1324 Also, subclassing an enumeration is allowed only if the enumeration does not define any members. … … 1699 1437 \begin{python} 1700 1438 Enum( 1701 1702 1703 1704 1705 1706 1707 1708 1439 value='NewEnumName', 1440 names=<...>, 1441 *, 1442 module='...', 1443 qualname='...', 1444 type=<mixed-in class>, 1445 start=1, 1446 ) 1709 1447 \end{python} 1710 1448 \begin{itemize} … … 1935 1673 \begin{python} 1936 1674 class IntEnum(int, Enum): 1937 1675 pass 1938 1676 \end{python} 1939 1677 This demonstrates how similar derived enumerations can be defined; … … 2070 1808 \begin{python} 2071 1809 def __bool__(self): 2072 1810 return bool(self.value) 2073 1811 \end{python} 2074 1812 Plain @Enum@ classes always evaluate as @True@. … … 2414 2152 2415 2153 If @__new__()@ or @__init__()@ is defined, the value of the enum member will be passed to those methods: 2416 \begin{python} 2417 >>> class Planet(Enum): 2418 ... MERCURY = (3.303e+23, 2.4397e6) 2419 ... VENUS = (4.869e+24, 6.0518e6) 2420 ... EARTH = (5.976e+24, 6.37814e6) 2421 ... MARS = (6.421e+23, 3.3972e6) 2422 ... JUPITER = (1.9e+27, 7.1492e7) 2423 ... SATURN = (5.688e+26, 6.0268e7) 2424 ... URANUS = (8.686e+25, 2.5559e7) 2425 ... NEPTUNE = (1.024e+26, 2.4746e7) 2426 ... def __init__(self, mass, radius): 2427 ... self.mass = mass # in kilograms 2428 ... self.radius = radius # in meters 2429 ... $\@$property 2430 ... def surface_gravity(self): 2431 ... # universal gravitational constant (m3 kg-1 s-2) 2432 ... G = 6.67300E-11 2433 ... return G * self.mass / (self.radius * self.radius) 2434 ... 2435 >>> Planet.EARTH.value 2436 (5.976e+24, 6378140.0) 2437 >>> Planet.EARTH.surface_gravity 2438 9.802652743337129 2439 \end{python} 2154 \begin{figure} 2155 \begin{python} 2156 from enum import Enum 2157 class Planet(Enum): 2158 MERCURY = ( 3.303E23, 2.4397E6 ) 2159 VENUS = ( 4.869E24, 6.0518E6 ) 2160 EARTH = (5.976E24, 6.37814E6) 2161 MARS = (6.421E23, 3.3972E6) 2162 JUPITER = (1.9E27, 7.1492E7) 2163 SATURN = (5.688E26, 6.0268E7) 2164 URANUS = (8.686E25, 2.5559E7) 2165 NEPTUNE = (1.024E26, 2.4746E7) 2166 def __init__( self, mass, radius ): 2167 self.mass = mass # in kilograms 2168 self.radius = radius # in meters 2169 def surface_gravity( self ): 2170 # universal gravitational constant (m3 kg-1 s-2) 2171 G = 6.67300E-11 2172 return G * self.mass / (self.radius * self.radius) 2173 for p in Planet: 2174 print( f"{p.name}: {p.value}" ) 2175 2176 MERCURY: (3.303e+23, 2439700.0) 2177 VENUS: (4.869e+24, 6051800.0) 2178 EARTH: (5.976e+24, 6378140.0) 2179 MARS: (6.421e+23, 3397200.0) 2180 JUPITER: (1.9e+27, 71492000.0) 2181 SATURN: (5.688e+26, 60268000.0) 2182 URANUS: (8.686e+25, 25559000.0) 2183 NEPTUNE: (1.024e+26, 24746000.0) 2184 \end{python} 2185 \caption{Python Planet Example} 2186 \label{f:PythonPlanetExample} 2187 \end{figure} 2188 2440 2189 2441 2190 \subsection{TimePeriod} … … 2464 2213 \section{OCaml} 2465 2214 \lstnewenvironment{ocaml}[1][]{\lstset{language=OCaml,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{} 2215 2216 % https://ocaml.org/docs/basic-data-types#enumerated-data-types 2466 2217 2467 2218 OCaml provides a variant (union) type, where multiple heterogeneously-typed objects share the same storage. … … 2553 2304 With valediction, 2554 2305 - Gregor Richards 2306 2307 2308 Date: Thu, 14 Mar 2024 21:45:52 -0400 2309 Subject: Re: OCaml "enums" do come with ordering 2310 To: "Peter A. Buhr" <pabuhr@uwaterloo.ca> 2311 From: Gregor Richards <gregor.richards@uwaterloo.ca> 2312 2313 On 3/14/24 21:30, Peter A. Buhr wrote: 2314 > I've marked 3 places with your name to shows places with enum ordering. 2315 > 2316 > type weekday = Mon | Tue | Wed | Thu | Fri | Sat | Sun 2317 > let day : weekday = Mon 2318 > let take_class( d : weekday ) = 2319 > if d <= Fri then (* Gregor *) 2320 > Printf.printf "weekday\n" 2321 > else if d >= Sat then (* Gregor *) 2322 > Printf.printf "weekend\n"; 2323 > match d with 2324 > Mon | Wed -> Printf.printf "CS442\n" | 2325 > Tue | Thu -> Printf.printf "CS343\n" | 2326 > Fri -> Printf.printf "Tutorial\n" | 2327 > _ -> Printf.printf "Take a break\n" 2328 > 2329 > let _ = take_class( Mon ); take_class( Sat ); 2330 > 2331 > type colour = Red | Green of string | Blue of int * float 2332 > let c = Red 2333 > let _ = match c with Red -> Printf.printf "Red, " 2334 > let c = Green( "abc" ) 2335 > let _ = match c with Green g -> Printf.printf "%s, " g 2336 > let c = Blue( 1, 1.5 ) 2337 > let _ = match c with Blue( i, f ) -> Printf.printf "%d %g\n" i f 2338 > 2339 > let check_colour(c: colour): string = 2340 > if c < Green( "xyz" ) then (* Gregor *) 2341 > Printf.printf "green\n"; 2342 > match c with 2343 > Red -> "Red" | 2344 > Green g -> g | 2345 > Blue(i, f) -> string_of_int i ^ string_of_float f 2346 > let _ = check_colour( Red ); check_colour( Green( "xyz" ) ); 2347 > 2348 > type stringList = Empty | Pair of string * stringList 2349 > let rec len_of_string_list(l: stringList): int = 2350 > match l with 2351 > Empty -> 0 | 2352 > Pair(_ , r) -> 1 + len_of_string_list r 2353 > 2354 > let _ = for i = 1 to 10 do 2355 > Printf.printf "%d, " i 2356 > done 2357 > 2358 > (* Local Variables: *) 2359 > (* tab-width: 4 *) 2360 > (* compile-command: "ocaml test.ml" *) 2361 > (* End: *) 2362 2363 My functional-language familiarity is far more with Haskell than OCaml. I 2364 mostly view OCaml through a lens of "it's Haskell but with cheating". Haskell 2365 "enums" (ADTs) aren't ordered unless you specifically and manually put them in 2366 the Ord typeclass by defining the comparators. Apparently, OCaml has some 2367 other rule, which I would guess is something like "sort by tag then by order of 2368 parameter". Having a default behavior for comparators is *bizarre*; my guess 2369 would be that it gained this behavior in its flirtation with object 2370 orientation, but that's just a guess (and irrelevant). 2371 2372 This gives a total order, but not enumerability (which would still be 2373 effectively impossible or even meaningless since enums are just a special case 2374 of ADTs). 2375 2376 With valediction, 2377 - Gregor Richards 2378 2379 Date: Wed, 20 Mar 2024 18:16:44 -0400 2380 Subject: Re: 2381 To: "Peter A. Buhr" <pabuhr@uwaterloo.ca> 2382 From: Gregor Richards <gregor.richards@uwaterloo.ca> 2383 2384 2385 On 3/20/24 17:26, Peter A. Buhr wrote: 2386 > Gregor, everyone at this end would like a definition of "enumerability". Can 2387 > you formulate one? 2388 2389 According to the OED (emphasis added to the meaning I'm after): 2390 2391 enumerate (verb, transitive). To count, ascertain the number of; **more 2392 usually, to mention (a number of things or persons) separately, as if for the 2393 purpose of counting**; to specify as in a list or catalogue. 2394 2395 With C enums, if you know the lowest and highest value, you can simply loop 2396 over them in a for loop (this is, of course, why so many enums come with an 2397 ENUM_WHATEVER_LAST value). But, I would be hesitant to use the word "loop" to 2398 describe enumerability, since in functional languages, you would recurse for 2399 such a purpose. 2400 2401 In Haskell, in order to do something with every member of an "enumeration", you 2402 would have to explicitly list them all. The type system will help a bit since 2403 it knows if you haven't listed them all, but you would have to statically have 2404 every element in the enumeration. If somebody added new elements to the 2405 enumeration later, your code to enumerate over them would no longer work 2406 correctly, because you can't simply say "for each member of this enumeration do 2407 X". In Haskell that's because there aren't actually enumerations; what they use 2408 as enumerations are a degenerate form of algebraic datatypes, and ADTs are 2409 certainly not enumerable. In OCaml, you've demonstrated that they impose 2410 comparability, but I would still assume that you can't make a loop over every 2411 member of an enumeration. (But, who knows!) 2412 2413 Since that's literally what "enumerate" means, it seems like a rather important 2414 property for enumerations to have ;) 2415 2416 With valediction, 2417 - Gregor Richards 2418 2419 2420 From: Andrew James Beach <ajbeach@uwaterloo.ca> 2421 To: Gregor Richards <gregor.richards@uwaterloo.ca>, Peter Buhr <pabuhr@uwaterloo.ca> 2422 CC: Michael Leslie Brooks <mlbrooks@uwaterloo.ca>, Fangren Yu <f37yu@uwaterloo.ca>, 2423 Jiada Liang <j82liang@uwaterloo.ca> 2424 Subject: Re: Re: 2425 Date: Thu, 21 Mar 2024 14:26:36 +0000 2426 2427 Does this mean that not all enum declarations in C create enumerations? If you 2428 declare an enumeration like: 2429 2430 enum Example { 2431 Label, 2432 Name = 10, 2433 Tag = 3, 2434 }; 2435 2436 I don't think there is any way to enumerate (iterate, loop, recurse) over these 2437 values without listing all of them. 2438 2439 2440 Date: Thu, 21 Mar 2024 10:31:49 -0400 2441 Subject: Re: 2442 To: Andrew James Beach <ajbeach@uwaterloo.ca>, Peter Buhr <pabuhr@uwaterloo.ca> 2443 CC: Michael Leslie Brooks <mlbrooks@uwaterloo.ca>, Fangren Yu <f37yu@uwaterloo.ca>, 2444 Jiada Liang <j82liang@uwaterloo.ca> 2445 From: Gregor Richards <gregor.richards@uwaterloo.ca> 2446 2447 I consider this conclusion reasonable. C enums can be nothing more than const 2448 ints, and if used in that way, I personally wouldn't consider them as 2449 enumerations in any meaningful sense, particularly since the type checker 2450 essentially does nothing for you there. Then they're a way of writing consts 2451 repeatedly with some textual indicator that these definitions are related; more 2452 namespace, less enum. 2453 2454 When somebody writes bitfield members as an enum, is that *really* an 2455 enumeration, or just a use of the syntax for enums to keep related definitions 2456 together? 2457 2458 With valediction, 2459 - Gregor Richards 2555 2460 \end{comment} 2556 2461 … … 2558 2463 \section{Comparison} 2559 2464 2560 \begin{tabular}{r|ccccccccc} 2561 feat. / lang. & Pascal & Ada & \Csharp & OCaml & Java & Modula-3 & Rust & Swift & Python \\ 2465 \VRef[Table]{t:FeatureLanguageComparison} shows a comparison of enumeration features and programming languages. 2466 The features are high level and may not capture nuances within a particular language 2467 The @const@ feature is simple macros substitution and not a typed enumeration. 2468 2469 \begin{table} 2470 \caption{Enumeration Feature / Language Comparison} 2471 \label{t:FeatureLanguageComparison} 2472 \small 2473 \setlength{\tabcolsep}{3pt} 2474 \newcommand{\CM}{\checkmark} 2475 \begin{tabular}{r|c|c|c|c|c|c|c|c|c|c|c|c|c} 2476 &Pascal & Ada &\Csharp& OCaml & Java &Modula-3&Golang& Rust & Swift & Python& C & \CC & \CFA \\ 2562 2477 \hline 2563 pure & & & & & & & & & \\ 2564 ordered & & & & & & & & & \\ 2565 setable & & & & & & & & & \\ 2566 auto-init & & & & & & & & & \\ 2567 scoped & & & & & & & & & \\ 2568 typed & & & & & & & & & \\ 2569 switch & & & & & & & & & \\ 2570 loop & & & & & & & & & \\ 2571 array & & & & & & & & & \\ 2478 @const@ & \CM & & & & & & \CM & & & & & \CM & \\ 2479 \hline 2480 \hline 2481 pure & & & & & & & & & & & & & \CM \\ 2482 \hline 2483 typed & & & & & & & & & & & @int@ & integral & @T@ \\ 2484 \hline 2485 safe & & & & & & & & & & & & \CM & \CM \\ 2486 \hline 2487 ordered & & & & & & & & & & & \CM & \CM & \CM \\ 2488 \hline 2489 dup. values & & & & & & & & & & alias & \CM & \CM & \CM \\ 2490 \hline 2491 setable & & & & & & & & & & & \CM & \CM & \CM \\ 2492 \hline 2493 auto-init & & & & & & & & & & & \CM & \CM & \CM \\ 2494 \hline 2495 (un)scoped & & & & & & & & & & & U & U/S & U/S \\ 2496 \hline 2497 overload & & \CM & & & & & & & & & & \CM & \CM \\ 2498 \hline 2499 switch & & & & & & & & & & & \CM & \CM & \CM \\ 2500 \hline 2501 loop & & & & & & & & & & & & & \CM \\ 2502 \hline 2503 array & & & & & & & & & & & \CM & & \CM \\ 2504 \hline 2505 subtype & & & & & & & & & & & & & \CM \\ 2506 \hline 2507 inheritance & & & & & & & & & & & & & \CM \\ 2572 2508 \end{tabular} 2509 \end{table}
Note: See TracChangeset
for help on using the changeset viewer.