source: doc/theses/jiada_liang_MMath/relatedwork.tex @ 647e2ea

Last change on this file since 647e2ea was 1d5e5601, checked in by Peter A. Buhr <pabuhr@…>, 7 months ago

more proofreading on the enumeration related-work section

  • Property mode set to 100644
File size: 45.1 KB
Line 
1\chapter{Related Work}
2\label{s:RelatedWork}
3
4Enumeration types exist in many popular programming languages, both past and present, \eg Pascal~\cite{Pascal}, Ada~\cite{Ada}, \Csharp~\cite{Csharp}, \CC, Go~\cite{Go}, Java~\cite{Java}, Modula-3~\cite{Modula-3}, Rust~\cite{Rust}, Swift~\cite{Swift}, Python~\cite{Python}, and algebraic data-types in functional programming.
5Among theses languages, there are a large set of overlapping features, but each language has its own unique extensions and restrictions.
6
7
8\section{Pascal}
9\lstnewenvironment{pascal}[1][]{\lstset{language=pascal,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
10
11Classic Pascal has the \lstinline[language=pascal]{const} declaration binding a name to a constant literal/expression.
12\begin{pascal}
13const one = 0 + 1;   Vowels = set of (A,E,I,O,U);   NULL = NIL;
14                 PI = 3.14159;   Plus = '+';   Fred = 'Fred';
15\end{pascal}
16Here, there is no enumeration because there is no specific type (pseudo enumeration).
17Hence, there is no notion of a (possibly ordered) set, modulo the \lstinline[language=pascal]{set of} type.
18The type of each constant name (enumerator) is inferred from the constant-expression type.
19
20Free Pascal~\cite[\S~3.1.1]{FreePascal} is a modern, object-oriented version of classic Pascal, with a C-style enumeration type.
21Enumerators must be assigned in ascending numerical order with a constant expression and the range can be non-consecutive.
22\begin{pascal}
23Type EnumType = ( one, two, three, forty @= 40@, fortyone );
24\end{pascal}
25Pseudo-functions @Pred@ and @Succ@ can only be used if the range is consecutive.
26The underlying type is an implementation-defined integral-type large enough to hold all enumerated values; it does not have to be the smallest possible type.
27The integral size can be explicitly specified using compiler directive @$PACKENUM@~$N$, where $N$ is the number of bytes, \eg:
28\begin{pascal}
29Type @{$\color{red}\$$PACKENUM 1}@ SmallEnum = ( one, two, three );
30            @{$\color{red}\$$PACKENUM 4}@ LargeEnum = ( BigOne, BigTwo, BigThree );
31Var S : SmallEnum; { 1 byte }
32          L : LargeEnum; { 4 bytes}
33\end{pascal}
34
35
36\section{Ada}
37\lstnewenvironment{ada}[1][]{\lstset{language=[2005]Ada,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},literate={'}{\ttfamily'\!}1}\lstset{#1}}{}
38
39An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators).
40\begin{ada}
41type RGB is ( Red, Green, Blue ); -- 3 literals (enumerators)
42\end{ada}
43Object initialization and assignment are restricted to the enumerators of this type.
44Enumerators without an explicitly designated constant value are auto-initialized: from left to right, starting at zero or the next explicitly initialized constant, incrementing by 1.
45To explicitly set enumerator values, \emph{all} enumerators must be set in \emph{ascending} order, \ie there is no auto-initialization.
46\begin{ada}
47type RGB is ( Red, Green, Blue );
48@for RGB use ( Red => 10, Green => 20, Blue => 30 );@ -- ascending order
49\end{ada}
50Hence, the position, value, label tuples are:
51\begin{ada}
52(0, 10, RED)  (1, 20, GREEN)  (2, 30, BLUE) 
53\end{ada}
54Note, Ada is case-\emph{insensitive} so names may appear in multiple forms and still be the same, \eg @Red@ and @RED@ (a questionable design decision).
55
56Like C, Ada enumerators are unscoped, \ie enumerators declared inside of an enum are visible (projected) into the enclosing scope.
57The enumeration operators are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of enumerators, which is always ascending.
58
59Ada enumerators are overloadable.
60\begin{ada}
61type Traffic_Light is ( @Red@, Yellow, @Green@ );
62\end{ada}
63Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded names.
64\VRef[Figure]{f:AdaEnumeration} shows how ambiguity is handled using a cast, \eg \lstinline[language=ada]{RGB'(Red)}.
65
66\begin{figure}
67\begin{ada}
68with Ada.Text_IO; use Ada.Text_IO;
69procedure test is
70   type RGB is ( @Red@, Green, Blue );
71   type Traffic_Light is ( @Red@, Yellow, Green );         -- overload
72   procedure @Red@( Colour : RGB ) is begin            -- overload
73       Put_Line( "Colour is " & RGB'Image( Colour ) );
74   end Red;
75   procedure @Red@( TL : Traffic_Light ) is begin       -- overload
76       Put_Line( "Light is " & Traffic_Light'Image( TL ) );
77   end Red;
78begin
79    @Red@( Blue );                               -- RGB
80    @Red@( Yellow );                            -- Traffic_Light
81    @Red@( @RGB'(Red)@ );               -- ambiguous without cast
82end test;
83\end{ada}
84\caption{Ada Enumeration Overload Resolution}
85\label{f:AdaEnumeration}
86\end{figure}
87
88Ada provides an alias mechanism, \lstinline[language=ada]{renames}, for aliasing types, which is useful to shorten package names.
89\begin{ada}
90OtherRed : RGB renames Red;
91\end{ada}
92which suggests a possible \CFA extension to @typedef@.
93\begin{cfa}
94typedef RGB.Red OtherRed;
95\end{cfa}
96
97There are three pairs of inverse enumeration pseudo-functions (attributes): @'Pos@ and @'Val@, @'Enum_Rep@ and @'Enum_Val@, and @'Image@ and @'Value@,
98\begin{cquote}
99\lstDeleteShortInline@
100\setlength{\tabcolsep}{15pt}
101\begin{tabular}{@{}ll@{}}
102\begin{ada}
103RGB'Pos( Red ) = 0;
104RGB'Enum_Rep( Red ) = 10;
105RGB'Image( Red ) = "RED";
106\end{ada}
107&
108\begin{ada}
109RGB'Val( 0 ) = Red
110RGB'Enum_Val( 10 ) =  Red
111RGB'Value( "Red" ) =  Red
112\end{ada}
113\end{tabular}
114\lstMakeShortInline@
115\end{cquote}
116These attributes are important for IO.
117An enumeration type @T@ also has the following attributes: @T'First@, @T'Last@, @T'Range@, @T'Pred@, @T'Succ@, @T'Min@, and @T'Max@, producing an intuitive result based on the attribute name.
118
119Ada allows the enumerator label to be a character constant.
120\begin{ada}
121type Operator is ( '+', '-', '*', '/' );
122\end{ada}
123which is syntactic sugar for the label and not character literals from the predefined type @Character@.
124The purpose is strictly readability using character literals rather than names.
125\begin{ada}
126Op : Operator := '+';
127if Op = '+' or else Op = '-' then ... ;
128elsif Op = '*' or else Op = '/' then ... ; end if;
129\end{ada}
130Interestingly, arrays of character enumerators can be treated as strings.
131\begin{ada}
132Ops : array( 0..3 ) of Operator;
133Ops := @"+-*/"@;            -- string assignment to array elements
134Ops := @"+-" & "*/"@;   -- string concatenation and assignment
135\end{ada}
136Ada's @Character@ type is defined as a character enumeration across all Latin-1 characters.
137
138Ada's boolean type is also a special enumeration, which can be used in conditions.
139\begin{ada}
140type Boolean is (False, True); -- False / True not keywords
141@Flag@ : Boolean;
142if @Flag@ then ...    -- conditional
143\end{ada}
144Since only types derived from @Boolean@ can be a conditional, @Boolean@ is essentially  a builtin type.
145
146Ada provides \emph{consecutive} subtyping of an enumeration using \lstinline[language=ada]{range}.
147\begin{ada}
148type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun );
149subtype Weekday is Week @range Mon .. Fri@;
150subtype Weekend is Week @range Sat .. Sun@;
151Day : Week;
152\end{ada}
153Hence, the ordering of the enumerators is crucial to provide the necessary ranges.
154
155An enumeration type can be used in the Ada \lstinline[language=ada]{case} (all enumerators must appear or a default) or iterating constructs.
156\begin{cquote}
157\lstDeleteShortInline@
158\setlength{\tabcolsep}{15pt}
159\begin{tabular}{@{}ll@{}}
160\begin{ada}
161case Day is
162        when @Mon .. Fri@ => ... ;
163        when @Sat .. Sun@ => ... ;
164end case;
165\end{ada}
166&
167\begin{ada}
168case Day is
169        when @Weekday@ => ... ;  -- subtype ranges
170        when @Weekend@ => ... ;
171end case;
172\end{ada}
173\end{tabular}
174\end{cquote}
175
176\begin{cquote}
177\setlength{\tabcolsep}{12pt}
178\begin{tabular}{@{}lll@{}}
179\begin{ada}
180for Day in @Mon .. Sun@ loop
181        ...
182end loop;
183\end{ada}
184&
185\begin{ada}
186for Day in @Weekday@ loop
187        ...
188end loop;
189\end{ada}
190&
191\begin{ada}
192for Day in @Weekend@ loop
193        ...
194end loop;
195\end{ada}
196\end{tabular}
197\lstMakeShortInline@
198\end{cquote}
199
200An enumeration type can be used as an array dimension and subscript.
201\begin{ada}
202Lunch : array( @Week@ ) of Time;
203for Day in Week loop
204        Lunch( @Day@ ) := ... ;       -- set lunch time
205end loop;
206\end{ada}
207
208
209\section{\CC}
210\label{s:C++RelatedWork}
211\lstnewenvironment{c++}[1][]{\lstset{language=[GNU]C++,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
212
213\CC is largely backwards compatible with C, so it inherited C's enumerations.
214However, the following non-backwards compatible changes have been made.
215
216\begin{cquote}
2177.2 Change: \CC objects of enumeration type can only be assigned values of the same enumeration type.
218In C, objects of enumeration type can be assigned values of any integral type. \\
219Example:
220\begin{c++}
221enum color { red, blue, green };
222color c = 1;                                                    $\C{// valid C, invalid C++}$
223\end{c++}
224\textbf{Rationale}: The type-safe nature of \CC. \\
225\textbf{Effect on original feature}: Deletion of semantically well-defined feature. \\
226\textbf{Difficulty of converting}: Syntactic transformation. (The type error produced by the assignment can be automatically corrected by applying an explicit cast.) \\
227\textbf{How widely used}: Common.
228\end{cquote}
229
230\begin{cquote}
2317.2 Change: In \CC, the type of an enumerator is its enumeration.
232In C, the type of an enumerator is @int@. \\
233Example:
234\begin{c++}
235enum e { A };
236sizeof(A) == sizeof(int)                                $\C{// in C}$
237sizeof(A) == sizeof(e)                                  $\C{// in C++}$
238/* and sizeof(int) is not necessary equal to sizeof(e) */
239\end{c++}
240\textbf{Rationale}: In \CC, an enumeration is a distinct type. \\
241\textbf{Effect on original feature}: Change to semantics of well-defined feature. \\
242\textbf{Difficulty of converting}: Semantic transformation. \\
243\textbf{How widely used}: Seldom. The only time this affects existing C code is when the size of an enumerator is taken.
244Taking the size of an enumerator is not a common C coding practice.
245\end{cquote}
246
247Hence, the values in a \CC enumeration can only be its enumerators (without a cast).
248While the storage size of an enumerator is up to the compiler, there is still an implicit cast to @int@.
249\begin{c++}
250enum E { A, B, C };
251E e = A;
252int i = A;   i = e;                                             $\C{// implicit casts to int}$
253\end{c++}
254\CC{11} added a scoped enumeration, \lstinline[language=c++]{enum class} (or \lstinline[language=c++]{enum struct}), where the enumerators are accessed using type qualification.
255\begin{c++}
256enum class E { A, B, C };
257E e = @E::@A;                                                   $\C{// qualified enumerator}$
258e = B;                                                                  $\C{// error: B not in scope}$
259\end{c++}
260\CC{20} supports explicit unscoping with a \lstinline[language=c++]{using enum} declaration.
261\begin{c++}
262enum class E { A, B, C };
263@using enum E;@
264E e = A;                                                                $\C{// direct access}$
265e = B;                                                                  $\C{// direct access}$
266\end{c++}
267\CC{11} added the ability to explicitly declare the underlying \emph{integral} type for \lstinline[language=c++]{enum class}.
268\begin{c++}
269enum class RGB @: long@ { Red, Green, Blue };
270enum class rgb @: char@ { Red = 'r', Green = 'g', Blue = 'b' };
271enum class srgb @: signed char@ { Red = -1, Green = 0, Blue = 1 };
272\end{c++}
273There is no implicit conversion from the \lstinline[language=c++]{enum class} type to its declared type.
274\begin{c++}
275rgb crgb = rgb::Red;
276char ch = rgb::Red;   ch = crgb;                $\C{// error}$
277\end{c++}
278Finally, enumerations can be used in the @switch@ statement but there is no mechanism to iterate through an enumeration.
279An enumeration type cannot declare an array dimension but can be used as a subscript.
280There is no mechanism to subtype or inherit from enumerations.
281
282
283\section{C\raisebox{-0.7ex}{\LARGE$^\sharp$}\xspace} % latex bug: cannot use \relsize{2} so use \LARGE
284\label{s:Csharp}
285\lstnewenvironment{csharp}[1][]{\lstset{language=[Sharp]C,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
286
287% https://www.tutorialsteacher.com/codeeditor?cid=cs-mk8Ojx
288
289\Csharp is a dynamically-typed programming-language with a scoped, integral enumeration-type similar to the C/\CC enumeration.
290\begin{csharp}
291enum Weekday : byte { Mon, Tue, Wed, Thu@ = 10@, Fri, Sat, Sun@,@ };
292\end{csharp}
293The default underlying type is @int@, with auto-incrementing, implicit/explicit initialization, terminator comma, and optional integral typing (default @int@).
294A method cannot be defined in an enumeration type.
295As well, there is an explicit bidirectional conversion between an enumeration and its integral type, and an implicit conversion to the enumerator label in display contexts.
296\begin{csharp}
297int day = (int)Weekday.Fri;             $\C{// day == 10}$
298Weekday weekday = (Weekdays)42;         $\C{// weekday == 42, logically invalid}$
299Console.WriteLine( Weekday.Fri ); $\C{// print Fri}$
300string mon = Weekday.Mon.ToString(); $\C{// mon == "Mon"}$
301\end{csharp}
302
303The @Enum.GetValues@ pseudo-method retrieves an array of the enumeration constants for looping over an enumeration type or variable (expensive operation).
304\begin{csharp}
305foreach ( Weekday constant in @Enum.GetValues@( typeof(Weekday) ) ) {
306        Console.WriteLine( constant + " " + (int)constant ); // label, position
307}
308\end{csharp}
309
310The @Flags@ attribute creates a bit-flags enumeration, allowing bitwise operators @&@, @|@, @~@ (complement), @^@ (xor).
311\begin{csharp}
312@[Flags]@ public enum Weekday {
313        None = 0x0, Mon = 0x1, Tue = 0x2, Wed = 0x4,
314        Thu = 0x8, Fri = 0x10, Sat = 0x20, Sun = 0x40,
315        Weekend = @Sat | Sun@,
316        Weekdays = @Mon | Tue | Wed | Thu | Fri@
317}
318Weekday meetings = @Weekday.Mon | Weekday.Wed@; // 0x5
319\end{csharp}
320
321\VRef[Figure]{CsharpFreeVersusClass} shows an enumeration with free routines for manipulation, and embedding the enumeration and operations into an enumeration class.
322The key observation is that an enumeration class is just a structuring mechanism without any additional semantics.
323
324% https://learn.microsoft.com/en-us/dotnet/api/system.enum?view=net-8.0
325
326\begin{figure}
327\centering
328\lstDeleteShortInline@
329\begin{tabular}{@{}l|l@{}}
330\multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
331\hline
332\begin{csharp}
333public class Program {
334
335        enum Weekday {
336                Mon, Tue, Wed, Thu, Fri, Sat, Sun };
337
338        static bool isWeekday( Weekday wd ) {
339                return wd <= Weekday.Fri;
340        }
341        static bool isWeekend( Weekday wd ) {
342                return Weekday.Sat <= wd;
343        }
344
345
346        public static void Main() {
347                Weekday day = Weekday.Sat;
348
349                Console.WriteLine( isWeekday( day ) );
350                Console.WriteLine( isWeekend( day ) );
351        }
352}
353\end{csharp}
354&
355\begin{csharp}
356public class Program {
357        public @class@ WeekDay : Enumeration {
358                public enum Day {
359                                Mon, Tue, Wed, Thu, Fri, Sat, Sun };
360                public enum Day2 : Day {
361                                XXX, YYY };
362                Day day;
363                public bool isWeekday() {
364                        return day <= Day.Fri;
365                }
366                public bool isWeekend() {
367                        return day > Day.Fri;
368                }
369                public WeekDay( Day d ) { day = d; }
370        }
371        public static void Main() {
372                WeekDay cday = new
373                                WeekDay( WeekDay.Day.Sat );
374                Console.WriteLine( cday.isWeekday() );
375                Console.WriteLine( cday.isWeekend() );
376        }
377}
378\end{csharp}
379\end{tabular}
380\lstMakeShortInline@
381\caption{\Csharp: Free Routine Versus Class Enumeration}
382\label{CsharpFreeVersusClass}
383\end{figure}
384
385
386\section{Golang}
387\lstnewenvironment{Go}[1][]{\lstset{language=Go,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
388
389Golang provides pseudo-enumeration similar to classic Pascal \lstinline[language=pascal]{const}, binding a name to a constant literal/expression.
390\begin{Go}
391const ( R = 0; G; B )                                   $\C{// implicit: 0 0 0}$
392const ( Fred = "Fred"; Mary = "Mary"; Jane = "Jane" ) $\C{// explicit: Fred Mary Jane}$
393const ( S = 0; T; USA = "USA"; U; V = 3.1; W ) $\C{// type change, implicit/explicit: 0 0 USA USA 3.1 3.1}$
394\end{Go}
395Constant names are unscoped and must be unique (no overloading).
396The first enumerator \emph{must} be explicitly initialized;
397subsequent enumerators can be implicitly or explicitly initialized.
398Implicit initialization is the previous (predecessor) enumerator value.
399
400Auto-incrementing is supported by the keyword \lstinline[language=Go]{iota}, available only in the \lstinline[language=Go]{const} declaration.
401The \lstinline[language=Go]{iota} is a \emph{per \lstinline[language=golang]{const} declaration} integer counter, starting at zero and implicitly incremented by one for each \lstinline[language=golang]{const} identifier (enumerator).
402\begin{Go}
403const ( R = @iota@; G; B )                              $\C{// implicit: 0 1 2}$
404const ( C = @iota + B + 1@; G; Y )              $\C{// implicit: 3 4 5}$
405\end{Go}
406An underscore \lstinline[language=golang]{const} identifier advances \lstinline[language=Go]{iota}.
407\begin{Go}
408const ( O1 = iota + 1; @_@; O3; @_@; O5 ) // 1, 3, 5 
409\end{Go}
410Auto-incrementing stops after an explicit initialization.
411\begin{Go}
412const ( Mon = iota; Tue; Wed; // 0, 1, 2
413         @Thu = 10@; Fri; Sat; Sun ) // 10, 10, 10, 10
414\end{Go}
415Auto-incrementing can be restarted with an expression containing \emph{one} \lstinline[language=Go]{iota}.
416\begin{Go}
417const ( V1 = iota; V2; @V3 = 7;@ V4 = @iota@; V5 ) // 0 1 7 3 4
418const ( Mon = iota; Tue; Wed; // 0, 1, 2
419         @Thu = 10;@ Fri = @iota - Wed + Thu - 1@; Sat; Sun ) // 10, 11, 12, 13
420\end{Go}
421Note, \lstinline[language=Go]{iota} is advanced for an explicitly initialized enumerator, like the underscore @_@ identifier.
422
423Basic switch and looping are possible.
424\begin{cquote}
425\lstDeleteShortInline@
426\setlength{\tabcolsep}{15pt}
427\begin{tabular}{@{}ll@{}}
428\begin{Go}
429day := Mon;
430switch day {
431  case Mon, Tue, Wed, Thu, Fri:
432        fmt.Println( "weekday" );
433  case Sat, Sun:
434        fmt.Println( "weekend" );
435}
436\end{Go}
437&
438\begin{Go}
439
440for i := Mon; i <= Sun; i += 1 {
441        fmt.Println( i )
442}
443
444
445
446\end{Go}
447\end{tabular}
448\lstMakeShortInline@
449\end{cquote}
450However, the loop prints the values from 0 to 13 because there is no actual enumeration.
451
452
453\section{Java}
454\lstnewenvironment{Java}[1][]{\lstset{language=Java,morekeywords={enum,assert,strictfp},
455        escapechar=\$,moredelim=**[is][\color{red}]{!}{!},}\lstset{#1}}{}
456
457Every enumeration in Java is an enumeration class.
458For a basic enumeration
459\begin{Java}
460enum Weekday { Mon, Tue, Wed, Thu, Fri, Sat, Sun };
461Weekday day = Weekday.Sat;
462\end{Java}
463the scoped enumerators are an ordered list of @final@ methods of type integer, ordered left to right starting at 0, increasing by 1.
464The value of an enumeration instance is restricted to the enumeration's enumerators.
465There is an implicit @int@ variable in the enumeration used to store the value of an enumeration instance.
466The position (ordinal) and label are accessible, where the value is the same as the position.
467\begin{Java}
468System.out.println( day.!ordinal()! + " " + day.!name()! ); // 5 Sat
469\end{Java}
470There is an inverse function @valueOf@ from string to enumerator.
471\begin{Java}
472day = Weekday.valueOf( "Wed" );
473\end{Java}
474There are no implicit conversions to/from an enumerator and its underlying type.
475Like \Csharp, \VRef[Figure]{f:JavaFreeVersusClass} shows the same example for an enumeration with free routines for manipulation, and embedding the enumeration and operations into an enumeration class.
476
477\begin{figure}
478\centering
479\lstDeleteShortInline@
480\begin{tabular}{@{}l|l@{}}
481\multicolumn{1}{@{}c|}{non-object oriented} & \multicolumn{1}{c@{}}{object oriented} \\
482\hline
483\begin{Java}
484enum Weekday !{!
485        Mon, Tue, Wed, Thu, Fri, Sat, Sun !}!;
486
487static boolean isWeekday( Weekday wd ) {
488        return wd.ordinal() <= Weekday.Fri.ordinal();
489}
490static boolean isWeekend( Weekday wd ) {
491        return Weekday.Fri.ordinal() < wd.ordinal();
492}
493
494public static void main( String[] args ) {
495        Weekday day = Weekday.Sat;
496        System.out.println( isWeekday( day ) );
497        System.out.println( isWeekend( day ) );
498}
499\end{Java}
500&
501\begin{Java}
502enum Weekday !{!
503        Mon, Tue, Wed, Thu, Fri, Sat, Sun;
504
505        public boolean isWeekday() {
506                return ordinal() <= Weekday.Fri.ordinal();
507        }
508        public boolean isWeekend() {
509                return Weekday.Fri.ordinal() < ordinal();
510        }
511!}!
512public static void main( String[] args ) {
513        WeekDay day = WeekDay.Sat;
514        System.out.println( day.isWeekday() );
515        System.out.println( day.isWeekend() );
516}
517\end{Java}
518\end{tabular}
519\lstMakeShortInline@
520\caption{Java: Free Routine Versus Class Enumeration}
521\label{f:JavaFreeVersusClass}
522\end{figure}
523
524To explicitly assign enumerator values and/or use a non-@int@ enumeration type (any Java type may be used), the enumeration must specify an explicit type in the enumeration class and a constructor.
525\begin{Java}
526enum Weekday {
527        Mon!(1)!, Tue!(2)!, Wed!(3)!, Thu!(4)!, Fri!(5)!, Sat!(6)!, Sun!(7)!; // must appear first
528        private !long! day;                                     $\C{// underlying enumeration type}$
529        private Weekday( !long! d ) { day = d; } $\C{// used to initialize enumerators}$
530};
531Weekday day = Weekday.Sat;
532\end{Java}
533If an enumerator initialization is a runtime expression, the expression is executed once at the point the enumeration is declaraed.
534
535The position, value, and label are accessible.
536\begin{Java}
537System.out.println( !day.ordinal()! + " " + !day.day! + " " + !day.name()! )// 5 6 Sat
538\end{Java}
539The constructor is private so only initialization or assignment can be used to set an enumeration, which ensures only corresponding enumerator values are allowed.
540
541An enumeration can appear in a @switch@ statement, but no ranges.
542\begin{Java}
543switch ( day ) {
544  case Mon: case Tue: case Wed: case Thu: case Fri:
545        System.out.println( "weekday" );
546        break;
547  case Sat: case Sun:
548        System.out.println( "weekend" );
549        break;
550}
551\end{Java}
552Like \Csharp, looping over an enumeration is done using method @values@, which returns the array of enumerator values (expensive operation).
553\begin{Java}
554for ( Weekday iday : Weekday.values() ) {
555        System.out.print( iday.ordinal() + iday.day + " " +  iday.name() + ",  " );
556}
5570 1 Mon,  1 2 Tue,  2 3 Wed,  3 4 Thu,  4 5 Fri,  5 6 Sat,  6 7 Sun, 
558\end{Java}
559
560As well, Java provides an @EnumSet@ where the underlying type is an efficient set of bits, one per enumeration \see{\Csharp \lstinline{Flags}, \VRef{s:Csharp}}, providing (logical) operations on groups of enumerators.
561There is also a specialized version of @HashMap@ with enumerator keys, which has performance benefits.
562
563Enumeration inheritence is disallowed because an enumeration is @final@.
564
565
566
567\section{Modula-3}
568
569
570
571\section{Rust}
572\lstnewenvironment{rust}[1][]{\lstset{language=Rust,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
573
574Enumerations
575\begin{rust}
576        Syntax
577        Enumeration :
578           enum IDENTIFIER  GenericParams? WhereClause? { EnumItems? }
579
580        EnumItems :
581           EnumItem ( , EnumItem )* ,?
582
583        EnumItem :
584           OuterAttribute* Visibility?
585           IDENTIFIER ( EnumItemTuple | EnumItemStruct )? EnumItemDiscriminant?
586
587        EnumItemTuple :
588           ( TupleFields? )
589
590        EnumItemStruct :
591           { StructFields? }
592
593        EnumItemDiscriminant :
594           = Expression
595\end{rust}
596An 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.
597
598Enumerations are declared with the keyword enum.
599
600An example of an enum item and its use:
601\begin{rust}
602enum Animal {
603        Dog,
604        Cat,
605}
606
607let mut a: Animal = Animal::Dog;
608a = Animal::Cat;
609\end{rust}
610Enum constructors can have either named or unnamed fields:
611\begin{rust}
612enum Animal {
613        Dog(String, f64),
614        Cat { name: String, weight: f64 },
615}
616
617let mut a: Animal = Animal::Dog("Cocoa".to_string(), 37.2);
618a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 };
619\end{rust}
620In this example, Cat is a struct-like enum variant, whereas Dog is simply called an enum variant.
621
622An enum where no constructors contain fields are called a field-less enum. For example, this is a fieldless enum:
623\begin{rust}
624enum Fieldless {
625        Tuple(),
626        Struct{},
627        Unit,
628}
629\end{rust}
630If a field-less enum only contains unit variants, the enum is called an unit-only enum. For example:
631\begin{rust}
632enum Enum {
633        Foo = 3,
634        Bar = 2,
635        Baz = 1,
636}
637\end{rust}
638
639\subsection{Discriminants}
640
641Each enum instance has a discriminant: an integer logically associated to it that is used to determine which variant it holds.
642
643Under 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.
644
645\subsection{Assigning discriminant values}
646
647\subsection{Explicit discriminants}
648
649In two circumstances, the discriminant of a variant may be explicitly set by following the variant name with = and a constant expression:
650
651        if the enumeration is "unit-only".
652
653        if a primitive representation is used. For example:
654\begin{rust}
655        #[repr(u8)]
656        enum Enum {
657                Unit = 3,
658                Tuple(u16),
659                Struct {
660                        a: u8,
661                        b: u16,
662                } = 1,
663        }
664\end{rust}
665
666\subsection{Implicit discriminants}
667
668If 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.
669\begin{rust}
670enum Foo {
671        Bar,                    // 0
672        Baz = 123,        // 123
673        Quux,              // 124
674}
675
676let baz_discriminant = Foo::Baz as u32;
677assert_eq!(baz_discriminant, 123);
678\end{rust}
679
680\subsection{Restrictions}
681
682It is an error when two variants share the same discriminant.
683\begin{rust}
684enum SharedDiscriminantError {
685        SharedA = 1,
686        SharedB = 1
687}
688
689enum SharedDiscriminantError2 {
690        Zero,      // 0
691        One,            // 1
692        OneToo = 1  // 1 (collision with previous!)
693}
694\end{rust}
695It is also an error to have an unspecified discriminant where the previous discriminant is the maximum value for the size of the discriminant.
696\begin{rust}
697#[repr(u8)]
698enum OverflowingDiscriminantError {
699        Max = 255,
700        MaxPlusOne // Would be 256, but that overflows the enum.
701}
702
703#[repr(u8)]
704enum OverflowingDiscriminantError2 {
705        MaxMinusOne = 254, // 254
706        Max,                       // 255
707        MaxPlusOne               // Would be 256, but that overflows the enum.
708}
709\end{rust}
710
711\subsection{Accessing discriminant}
712
713\begin{rust}
714Via mem::discriminant
715\end{rust}
716mem::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.
717Casting
718
719If an enumeration is unit-only (with no tuple and struct variants), then its discriminant can be directly accessed with a numeric cast; e.g.:
720\begin{rust}
721enum Enum {
722        Foo,
723        Bar,
724        Baz,
725}
726
727assert_eq!(0, Enum::Foo as isize);
728assert_eq!(1, Enum::Bar as isize);
729assert_eq!(2, Enum::Baz as isize);
730\end{rust}
731Field-less enums can be casted if they do not have explicit discriminants, or where only unit variants are explicit.
732\begin{rust}
733enum Fieldless {
734        Tuple(),
735        Struct{},
736        Unit,
737}
738
739assert_eq!(0, Fieldless::Tuple() as isize);
740assert_eq!(1, Fieldless::Struct{} as isize);
741assert_eq!(2, Fieldless::Unit as isize);
742\end{rust}
743\begin{rust}
744#[repr(u8)]
745enum FieldlessWithDiscrimants {
746        First = 10,
747        Tuple(),
748        Second = 20,
749        Struct{},
750        Unit,
751}
752
753assert_eq!(10, FieldlessWithDiscrimants::First as u8);
754assert_eq!(11, FieldlessWithDiscrimants::Tuple() as u8);
755assert_eq!(20, FieldlessWithDiscrimants::Second as u8);
756assert_eq!(21, FieldlessWithDiscrimants::Struct{} as u8);
757assert_eq!(22, FieldlessWithDiscrimants::Unit as u8);
758\end{rust}
759
760\subsection{Pointer casting}
761
762If the enumeration specifies a primitive representation, then the discriminant may be reliably accessed via unsafe pointer casting:
763\begin{rust}
764#[repr(u8)]
765enum Enum {
766        Unit,
767        Tuple(bool),
768        Struct{a: bool},
769}
770
771impl Enum {
772        fn discriminant(&self) -> u8 {
773                unsafe { *(self as *const Self as *const u8) }
774        }
775}
776
777let unit_like = Enum::Unit;
778let tuple_like = Enum::Tuple(true);
779let struct_like = Enum::Struct{a: false};
780
781assert_eq!(0, unit_like.discriminant());
782assert_eq!(1, tuple_like.discriminant());
783assert_eq!(2, struct_like.discriminant());
784\end{rust}
785
786\subsection{Zero-variant enums}
787
788Enums with zero variants are known as zero-variant enums. As they have no valid values, they cannot be instantiated.
789\begin{rust}
790enum ZeroVariants {}
791\end{rust}
792Zero-variant enums are equivalent to the never type, but they cannot be coerced into other types.
793\begin{rust}
794let x: ZeroVariants = panic!();
795let y: u32 = x; // mismatched type error
796\end{rust}
797
798\subsection{Variant visibility}
799
800Enum 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.
801\begin{rust}
802macro_rules! mac_variant {
803        ($vis:vis $name:ident) => {
804                enum $name {
805                        $vis Unit,
806
807                        $vis Tuple(u8, u16),
808
809                        $vis Struct { f: u8 },
810                }
811        }
812}
813
814// Empty `vis` is allowed.
815mac_variant! { E }
816
817// This is allowed, since it is removed before being validated.
818#[cfg(FALSE)]
819enum E {
820        pub U,
821        pub(crate) T(u8),
822        pub(super) T { f: String }
823}
824\end{rust}
825
826
827\section{Swift}
828\lstnewenvironment{swift}[1][]{\lstset{language=Swift,escapechar=\$,moredelim=**[is][\color{red}]{@}{@},}\lstset{#1}}{}
829
830% https://www.programiz.com/swift/online-compiler
831
832A 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.
833\begin{swift}
834enum Many {
835        case Mon, Tue, Wed, Thu, Fri, Sat, Sun // basic enumerator
836        case code( String ) // string enumerator
837        case tuple( Int, Int, Int ) // tuple enumerator
838};
839var day = Many.Sat; // qualification to resolve type
840print( day );
841day = .Wed // no qualification after type resolved
842print( day );
843day = .code( "ABC" );
844print( day );
845day = .tuple( 1, 2, 3 );
846print( day );
847
848Sat
849Wed
850code("ABC")
851tuple(1, 2, 3)
852\end{swift}
853
854
855An 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.
856
857If you are familiar with C, you will know that C enumerations assign related names to a set of integer values.
858Enumerations in Swift are much more flexible, and don't have to provide a value for each case of the enumeration.
859If 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.
860
861Alternatively, 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.
862You 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.
863
864Enumerations in Swift are first-class types in their own right.
865They 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.
866Enumerations can also define initializers to provide an initial case value;
867can be extended to expand their functionality beyond their original implementation; and can conform to protocols to provide standard functionality.
868
869For more about these capabilities, see Properties, Methods, Initialization, Extensions, and Protocols.
870
871\paragraph{Enumeration Syntax}
872
873
874Note:
875Swift enumeration cases don't have an integer value set by default, unlike languages like C and Objective-C.
876In the CompassPoint example above, @north@, @south@, @east@ and @west@ don't implicitly equal 0, 1, 2 and 3.
877Instead, the different enumeration cases are values in their own right, with an explicitly defined type of CompassPoint.
878
879Multiple cases can appear on a single line, separated by commas:
880\begin{swift}
881enum Planet {
882        case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
883}
884\end{swift}
885Each enumeration definition defines a new type.
886Like other types in Swift, their names (such as @CompassPoint@ and @Planet@) start with a capital letter.
887Give enumeration types singular rather than plural names, so that they read as self-evident:
888\begin{swift}
889var directionToHead = CompassPoint.west
890\end{swift}
891The type of @directionToHead@ is inferred when it's initialized with one of the possible values of @CompassPoint@.
892Once @directionToHead@ is declared as a @CompassPoint@, you can set it to a different @CompassPoint@ value using a shorter dot syntax:
893\begin{swift}
894directionToHead = .east
895\end{swift}
896The type of @directionToHead@ is already known, and so you can drop the type when setting its value.
897This makes for highly readable code when working with explicitly typed enumeration values.
898
899\paragraph{Matching Enumeration Values with a Switch Statement}
900
901You can match individual enumeration values with a switch statement:
902\begin{swift}
903directionToHead = .south
904switch directionToHead {
905case .north:
906        print("Lots of planets have a north")
907case .south:
908        print("Watch out for penguins")
909case .east:
910        print("Where the sun rises")
911case .west:
912        print("Where the skies are blue")
913}
914// Prints "Watch out for penguins"
915\end{swift}
916You can read this code as:
917\begin{quote}
918"Consider the value of directionToHead.
919In the case where it equals @.north@, print "Lots of planets have a north".
920In the case where it equals @.south@, print "Watch out for penguins"."
921
922...and so on.
923\end{quote}
924As described in Control Flow, a switch statement must be exhaustive when considering an enumeration's cases.
925If the case for @.west@ is omitted, this code doesn't compile, because it doesn't consider the complete list of @CompassPoint@ cases.
926Requiring exhaustiveness ensures that enumeration cases aren't accidentally omitted.
927
928When 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:
929\begin{swift}
930let somePlanet = Planet.earth
931switch somePlanet {
932case .earth:
933        print("Mostly harmless")
934default:
935        print("Not a safe place for humans")
936}
937// Prints "Mostly harmless"
938\end{swift}
939
940\paragraph{Iterating over Enumeration Cases}
941
942For some enumerations, it's useful to have a collection of all of that enumeration's cases.
943You enable this by writing @CaseIterable@ after the enumeration's name.
944Swift exposes a collection of all the cases as an allCases property of the enumeration type.
945Here's an example:
946\begin{swift}
947enum Beverage: CaseIterable {
948        case coffee, tea, juice
949}
950let numberOfChoices = Beverage.allCases.count
951print("\(numberOfChoices) beverages available")
952// Prints "3 beverages available"
953\end{swift}
954In the example above, you write @Beverage.allCases@ to access a collection that contains all of the cases of the @Beverage@ enumeration.
955You 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.
956The example above counts how many cases there are, and the example below uses a for-in loop to iterate over all the cases.
957\begin{swift}
958for beverage in Beverage.allCases {
959        print(beverage)
960}
961// coffee
962// tea
963// juice
964\end{swift}
965The syntax used in the examples above marks the enumeration as conforming to the @CaseIterable@ protocol.
966For information about protocols, see Protocols.
967
968\paragraph{Associated Values}
969The examples in the previous section show how the cases of an enumeration are a defined (and typed) value in their own right.
970You can set a constant or variable to Planet.earth, and check for this value later.
971However, it's sometimes useful to be able to store values of other types alongside these case values.
972This additional information is called an associated value, and it varies each time you use that case as a value in your code.
973
974You 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.
975Enumerations similar to these are known as discriminated unions, tagged unions, or variants in other programming languages.
976
977For example, suppose an inventory tracking system needs to track products by two different types of barcode.
978Some products are labeled with 1D barcodes in UPC format, which uses the numbers 0 to 9.
979Each barcode has a number system digit, followed by five manufacturer code digits and five product code digits.
980These are followed by a check digit to verify that the code has been scanned correctly:
981
982Other 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:
983
984It'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.
985
986In Swift, an enumeration to define product barcodes of either type might look like this:
987\begin{swift}
988enum Barcode {
989        case upc(Int, Int, Int, Int)
990        case qrCode(String)
991}
992\end{swift}
993This can be read as:
994\begin{quote}
995"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@."
996\end{quote}
997This 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@.
998
999You can then create new barcodes using either type:
1000\begin{swift}
1001var productBarcode = Barcode.upc(8, 85909, 51226, 3)
1002\end{swift}
1003This 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)@.
1004
1005You can assign the same product a different type of barcode:
1006\begin{swift}
1007productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
1008\end{swift}
1009At this point, the original @Barcode.upc@ and its integer values are replaced by the new @Barcode.qrCode@ and its string value.
1010Constants 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.
1011
1012You can check the different barcode types using a switch statement, similar to the example in Matching Enumeration Values with a Switch Statement.
1013This time, however, the associated values are extracted as part of the switch statement.
1014You 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:
1015\begin{swift}
1016switch productBarcode {
1017case .upc(let numberSystem, let manufacturer, let product, let check):
1018        print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
1019case .qrCode(let productCode):
1020        print("QR code: \(productCode).")
1021}
1022// Prints "QR code: ABCDEFGHIJKLMNOP."
1023\end{swift}
1024If 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:
1025\begin{swift}
1026switch productBarcode {
1027case let .upc(numberSystem, manufacturer, product, check):
1028        print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
1029case let .qrCode(productCode):
1030        print("QR code: \(productCode).")
1031}
1032// Prints "QR code: ABCDEFGHIJKLMNOP."
1033\end{swift}
1034
1035\paragraph{Raw Values}
1036
1037The barcode example in Associated Values shows how cases of an enumeration can declare that they store associated values of different types.
1038As an alternative to associated values, enumeration cases can come prepopulated with default values (called raw values), which are all of the same type.
1039
1040Here's an example that stores raw ASCII values alongside named enumeration cases:
1041\begin{swift}
1042enum ASCIIControlCharacter: Character {
1043        case tab = "\t"
1044        case lineFeed = "\n"
1045        case carriageReturn = "\r"
1046}
1047\end{swift}
1048Here, 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.
1049Character values are described in Strings and Characters.
1050
1051Raw values can be strings, characters, or any of the integer or floating-point number types.
1052Each raw value must be unique within its enumeration declaration.
1053
1054Note
1055
1056Raw values are not the same as associated values.
1057Raw values are set to prepopulated values when you first define the enumeration in your code, like the three ASCII codes above.
1058The raw value for a particular enumeration case is always the same.
1059Associated 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.
1060Implicitly Assigned Raw Values
1061
1062When 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.
1063When you don't, Swift automatically assigns the values for you.
1064
1065For example, when integers are used for raw values, the implicit value for each case is one more than the previous case.
1066If the first case doesn't have a value set, its value is 0.
1067
1068The enumeration below is a refinement of the earlier Planet enumeration, with integer raw values to represent each planet's order from the sun:
1069
1070\begin{swift}
1071enum Planet: Int {
1072        case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
1073}
1074\end{swift}
1075In the example above, Planet.mercury has an explicit raw value of 1, Planet.venus has an implicit raw value of 2, and so on.
1076
1077When strings are used for raw values, the implicit value for each case is the text of that case's name.
1078
1079The enumeration below is a refinement of the earlier CompassPoint enumeration, with string raw values to represent each direction's name:
1080\begin{swift}
1081enum CompassPoint: String {
1082        case north, south, east, west
1083}
1084\end{swift}
1085In the example above, CompassPoint.south has an implicit raw value of "south", and so on.
1086
1087You access the raw value of an enumeration case with its rawValue property:
1088\begin{swift}
1089let earthsOrder = Planet.earth.rawValue
1090// earthsOrder is 3
1091
1092let sunsetDirection = CompassPoint.west.rawValue
1093// sunsetDirection is "west"
1094\end{swift}
1095
1096\paragraph{Initializing from a Raw Value}
1097
1098If 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.
1099You can use this initializer to try to create a new instance of the enumeration.
1100
1101This example identifies Uranus from its raw value of 7:
1102\begin{swift}
1103let possiblePlanet = Planet(rawValue: 7)
1104// possiblePlanet is of type Planet? and equals Planet.uranus
1105\end{swift}
1106Not all possible Int values will find a matching planet, however.
1107Because of this, the raw value initializer always returns an optional enumeration case.
1108In the example above, possiblePlanet is of type Planet?, or "optional Planet."
1109Note
1110
1111The raw value initializer is a failable initializer, because not every raw value will return an enumeration case.
1112For more information, see Failable Initializers.
1113
1114If you try to find a planet with a position of 11, the optional Planet value returned by the raw value initializer will be nil:
1115\begin{swift}
1116let positionToFind = 11
1117if let somePlanet = Planet(rawValue: positionToFind) {
1118        switch somePlanet {
1119        case .earth:
1120                print("Mostly harmless")
1121        default:
1122                print("Not a safe place for humans")
1123        }
1124} else {
1125        print("There isn't a planet at position \(positionToFind)")
1126}
1127// Prints "There isn't a planet at position 11"
1128\end{swift}
1129This example uses optional binding to try to access a planet with a raw value of 11.
1130The 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.
1131In this case, it isn't possible to retrieve a planet with a position of 11, and so the else branch is executed instead.
1132
1133\paragraph{Recursive Enumerations}
1134
1135A recursive enumeration is an enumeration that has another instance of the enumeration as the associated value for one or more of the enumeration cases.
1136You indicate that an enumeration case is recursive by writing indirect before it, which tells the compiler to insert the necessary layer of indirection.
1137
1138For example, here is an enumeration that stores simple arithmetic expressions:
1139\begin{swift}
1140enum ArithmeticExpression {
1141        case number(Int)
1142        indirect case addition(ArithmeticExpression, ArithmeticExpression)
1143        indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
1144}
1145\end{swift}
1146You 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:
1147\begin{swift}
1148indirect enum ArithmeticExpression {
1149        case number(Int)
1150        case addition(ArithmeticExpression, ArithmeticExpression)
1151        case multiplication(ArithmeticExpression, ArithmeticExpression)
1152}
1153\end{swift}
1154This enumeration can store three kinds of arithmetic expressions: a plain number, the addition of two expressions, and the multiplication of two expressions.
1155The addition and multiplication cases have associated values that are also arithmetic expressions -- these associated values make it possible to nest expressions.
1156For 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.
1157Because the data is nested, the enumeration used to store the data also needs to support nesting -- this means the enumeration needs to be recursive.
1158The code below shows the ArithmeticExpression recursive enumeration being created for (5 + 4) * 2:
1159\begin{swift}
1160let five = ArithmeticExpression.number(5)
1161let four = ArithmeticExpression.number(4)
1162let sum = ArithmeticExpression.addition(five, four)
1163let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
1164\end{swift}
1165A recursive function is a straightforward way to work with data that has a recursive structure.
1166For example, here's a function that evaluates an arithmetic expression:
1167\begin{swift}
1168func evaluate(_ expression: ArithmeticExpression) -> Int {
1169        switch expression {
1170        case let .number(value):
1171                return value
1172        case let .addition(left, right):
1173                return evaluate(left) + evaluate(right)
1174        case let .multiplication(left, right):
1175                return evaluate(left) * evaluate(right)
1176        }
1177}
1178
1179print(evaluate(product))
1180// Prints "18"
1181\end{swift}
1182This function evaluates a plain number by simply returning the associated value.
1183It 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.
1184
1185
1186\section{Python}
1187
1188\section{Algebraic Data Type}
Note: See TracBrowser for help on using the repository browser.