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

Last change on this file since 2810700 was 7bb516f, checked in by Peter A. Buhr <pabuhr@…>, 9 months ago

more proofreading on enumeration thesis

  • Property mode set to 100644
File size: 45.5 KB
Line 
1\chapter{Related Work}
2\label{s:RelatedWork}
3
4An enumeration type 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 the algebraic data-type 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
10\lstnewenvironment{pascal}[1][]{% necessary
11\lstset{
12language=pascal,
13escapechar=\$,                                                  % LaTeX escape in code
14moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
15}% lstset
16\lstset{#1}% necessary
17}{}
18
19Classic Pascal has the \lstinline[language=pascal]{const} declaration binding a name to a constant literal/expression.
20\begin{pascal}
21const one = 0 + 1;   Vowels = set of (A,E,I,O,U);   NULL = NIL;
22                 PI = 3.14159;   Plus = '+';   Fred = 'Fred';
23\end{pascal}
24The enumerator type is inferred from the constant-expression type.
25There is no notion of an ordered set, modulo the \lstinline[language=pascal]{set of} type.
26
27Free Pascal is a modern, object-oriented version of classic Pascal, with a C-style enumeration type.
28Enumerators must be in assigned in ascending numerical order with a constant expression and the range can be non-consecutive.
29\begin{pascal}
30Type EnumType = ( one, two, three, forty @= 40@, fortyone );
31\end{pascal}
32Pseudo-functions @Pred@ and @Succ@ can only be used if the range is consecutive.
33The 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.
34The size underlying integral type can be explicitly specified using compiler directive @$PACKENUM@~$N$, where $N$ is the number of bytes, \eg:
35\begin{pascal}
36Type @{$\color{red}\$$PACKENUM 1}@ SmallEnum = ( one, two, three );
37            @{$\color{red}\$$PACKENUM 4}@ LargeEnum = ( BigOne, BigTwo, BigThree );
38Var S : SmallEnum; { 1 byte }
39          L : LargeEnum; { 4 bytes}
40\end{pascal}
41
42
43\section{Ada}
44
45\lstnewenvironment{ada}[1][]{% necessary
46\lstset{
47language=[2005]Ada,
48escapechar=\$,                                                  % LaTeX escape in code
49moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
50literate={'}{\ttfamily'\!}1                             % remove '-' literate as comment
51}% lstset
52\lstset{#1}% necessary
53}{}
54
55An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators).
56\begin{ada}
57type RGB is ( @Red@, @Green@, Blue ); -- 3 literals (enumerators)
58\end{ada}
59No other enumerators are assignable to objects of this type.
60Enumerators 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.
61To explicitly set enumerator values, \emph{all} enumerators must be set in \emph{ascending} order, \ie there is no auto-initialization.
62\begin{ada}
63type RGB is ( Red, Green, Blue );
64@for RGB use ( Red => 10, Green => 20, Blue => 30 );@ -- ascending order
65\end{ada}
66
67Like C, Ada enumerators are unscoped, \ie enumerators declared inside of an enum are visible (projected) into the enclosing scope.
68Note, Ada is case-\emph{insensitive} so names may appear in multiple forms and still be the same name (a questionable design decision).
69The enumeration operators are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relation is given implicitly by the sequence of enumerators, which is always ascending.
70
71Ada enumerators are overloadable.
72\begin{ada}
73type Traffic_Light is ( @Red@, Yellow, @Green@ );
74\end{ada}
75Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded names.
76Figure~\VRef{f:AdaEnumeration} shows how ambiguities are handled using a cast, \eg \lstinline[language=ada]{RGB'(Red)}.
77
78\begin{figure}
79\begin{ada}
80with Ada.Text_IO; use Ada.Text_IO;
81procedure test is
82   type RGB is ( @Red@, Green, Blue );
83   type Traffic_Light is ( @Red@, Yellow, Green );
84   procedure @Red@( Colour : RGB ) is begin
85       Put_Line( "Colour is " & RGB'Image( Colour ) );
86   end Red;
87   procedure @Red@( TL : Traffic_Light ) is begin
88       Put_Line( "Light is " & Traffic_Light'Image( TL ) );
89   end Red;
90begin
91    @Red@( Blue );                               -- RGB
92    @Red@( Yellow );                            -- Traffic_Light
93    @Red@( @RGB'(Red)@ );               -- ambiguous without cast
94end test;
95\end{ada}
96\caption{Ada Enumeration Overload Resolution}
97\label{f:AdaEnumeration}
98\end{figure}
99
100Ada provides an alias mechanism called \lstinline[language=ada]{renames} for aliasing types, especially to shorten package type names.
101\begin{ada}
102OtherRed : RGB renames Red;
103\end{ada}
104which suggests the \CFA extension to @typedef@.
105\begin{cfa}
106typedef RGB.Red OtherRed;
107\end{cfa}
108
109There are four enumeration pseudo functions (attributes): @'Pos@, @'Val@, @'Image@, and @'Value@.
110Function @Pos@ returns the enumerator position; the inverse function @Val@ returns the corresponding enumerator.
111\begin{ada}
112RGB'Pos(Red) = 0  -- '=' => equality
113RGB'Val(0) = Red
114\end{ada}
115Funcion @Image@ returns the enumerator label (in capital letters); the inverse function @Value@ returns the corresponding enumerator.
116\begin{ada}
117RGB'Image( Red ) = "RED"
118RGB'Value("Red") =  Red
119\end{ada}
120These attributes are important for simple IO (there are more elaborate IO facilities in @Ada.Text_IO@ for enumeration types).
121As well, an enumeration type @T@ has the additional 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.
122
123Ada leverages enumerations as the bases for character and boolean types.
124Rather unique to Ada is the use of character literals as enumeration literals:
125\begin{ada}
126type ABC is ('A', 'B', 'C');
127\end{ada}
128This literal @'A'@ has nothing in common with the literal @'A'@ of the predefined type @Character@ (or @Wide_Character@).
129
130Every type that has at least one character literal is a character type.
131For every character type, string literals and the concatenation operator @"&"@ are also implicitly defined.
132\begin{ada}
133type My_Character is (No_Character, 'a', Literal, 'z');
134type My_String is array (Positive range <>) of My_Character;
135
136S: My_String := "aa" & Literal & "za" & 'z';
137T: My_String := ('a', 'a', Literal, 'z', 'a', 'z');
138\end{ada}
139In this example, @S@ and @T@ have the same value.
140
141Ada's @Character@ type is defined that way.
142See Ada Programming/Libraries/Standard.
143
144The boolean type is defined as an enumeration:
145\begin{ada}
146type Boolean is (False, True); -- False / True not keywords
147@Flag@ : Boolean;
148\end{ada}
149which can be used in conditions.
150\begin{ada}
151if @Flag@ then ...
152\end{ada}
153Since only types derived from @Boolean@ can be a conditional, @Boolean@ is essentially  a builtin type.
154
155Ada provides a simple \emph{consecutive} subset (subtype) of an enumeration using \lstinline[language=ada]{range}.
156\begin{ada}
157type BW  is ( Cyan, Megenta, Yellow, Red, Green, Blue );
158type CMY is new BW @range@ Cyan .. Yellow;
159type RGB is new BW @range@ Red .. Blue;
160\end{ada}
161Hence, the ordering of the enumerators is crucial to provide the necessary ranges.
162
163\begin{ada}
164type Subtype_Name is (Id1, Id2, Id3 ... );
165\end{ada}
166where @Id1@, @Id2@, etc. are identifiers or characters literals.
167In either case, the legal values of the type are referred to as "enumeration literals."
168Each of these values has a "position number" corresponding to its position in the list such that @Id1@ has position 0, @Id2@ has position 1, and the Nth value has position N-1.
169
170The enumeration attributes @First@ and @Succ@ allow stepping through a subsequence of the values.
171\begin{ada}
172case Day_Of_Week'First is
173        when Sunday =>
174           ISO (False);
175        when Day_Of_Week'Succ(Sunday) =>
176           ISO (True);
177        when Tuesday .. Saturday =>
178           raise Program_Error;
179end case;
180\end{ada}
181A loop will automatically step through the values of the subtype's range.
182Filtering week days to include only working days with an even position number:
183\begin{ada}
184        for Day in Working_Day loop
185                if Day_Of_Week'Pos(Day) mod 2 = 0 then
186                        Work_In_Backyard;
187                end if;
188        end loop;
189\end{ada}
190Enumeration types can be used as array index subtypes, yielding a table feature:
191\begin{ada}
192type Officer_ID is range 0 .. 50;
193type Schedule is array (Working_Day) of Officer_ID;
194\end{ada}
195
196
197\section{\CC}
198\label{s:C++RelatedWork}
199
200\lstnewenvironment{c++}[1][]{% necessary
201\lstset{
202language=[GNU]C++,
203escapechar=\$,                                                  % LaTeX escape in code
204moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
205}% lstset
206\lstset{#1}% necessary
207}{}
208
209\CC is largely backwards compatible with C, so it inherited C's enumerations.
210However, the following non-backwards compatible changes have been made.
211
212\begin{cquote}
2137.2 Change: \CC objects of enumeration type can only be assigned values of the same enumeration type.
214In C, objects of enumeration type can be assigned values of any integral type. \\
215Example:
216\begin{c++}
217enum color { red, blue, green };
218color c = 1;                                                    $\C{// valid C, invalid C++}$
219\end{c++}
220\textbf{Rationale}: The type-safe nature of \CC. \\
221\textbf{Effect on original feature}: Deletion of semantically well-defined feature. \\
222\textbf{Difficulty of converting}: Syntactic transformation. (The type error produced by the assignment can be automatically corrected by applying an explicit cast.) \\
223\textbf{How widely used}: Common.
224\end{cquote}
225
226\begin{cquote}
2277.2 Change: In \CC, the type of an enumerator is its enumeration.
228In C, the type of an enumerator is @int@. \\
229Example:
230\begin{c++}
231enum e { A };
232sizeof(A) == sizeof(int)                                $\C{// in C}$
233sizeof(A) == sizeof(e)                                  $\C{// in C++}$
234/* and sizeof(int) is not necessary equal to sizeof(e) */
235\end{c++}
236\textbf{Rationale}: In \CC, an enumeration is a distinct type. \\
237\textbf{Effect on original feature}: Change to semantics of well-defined feature. \\
238\textbf{Difficulty of converting}: Semantic transformation. \\
239\textbf{How widely used}: Seldom. The only time this affects existing C code is when the size of an enumerator is taken.
240Taking the size of an enumerator is not a common C coding practice.
241\end{cquote}
242
243Hence, the values in a \CC enumeration can only be its enumerators (without a cast).
244While the storage size of an enumerator is up to the compiler, there is still an implicit cast to @int@.
245\begin{c++}
246enum E { A, B, C };
247E e = A;
248int i = A;   i = e;                                             $\C{// implicit casts to int}$
249\end{c++}
250\CC{11} added a scoped enumeration, \lstinline[language=c++]{enum class} (or \lstinline[language=c++]{enum struct}), so the enumerators are local to the enumeration and must be accessed using type qualification.
251\begin{c++}
252enum class E { A, B, C };
253E e = @E::@A;                                                   $\C{// qualified enumerator}$
254e = B;                                                                  $\C{// B not in scope}$
255\end{c++}
256\CC{20} supports unscoped access with a \lstinline[language=c++]{using enum} declaration.
257\begin{c++}
258enum class E { A, B, C };
259@using enum E;@
260E e = A;                                                                $\C{// direct access}$
261e = B;                                                                  $\C{// direct access}$
262\end{c++}
263\CC{11} added the ability to explicitly declare the underlying integral type for \lstinline[language=c++]{enum class}.
264\begin{c++}
265enum class RGB @: long@ { Red, Green, Blue };
266enum class rgb @: char@ { Red = 'r', Green = 'g', Blue = 'b' };
267enum class srgb @: signed char@ { Red = -1, Green = 0, Blue = 1 };
268\end{c++}
269There is no implicit conversion from the \lstinline[language=c++]{enum class} type and to its type.
270\begin{c++}
271rgb crgb = rgb::Red;
272char ch = rgb::Red;   ch = crgb;                $\C{// disallowed}$
273\end{c++}
274Finally, there is no mechanism to iterate through an enumeration nor use the enumeration type to declare an array dimension.
275
276
277\section{C\raisebox{-0.7ex}{\LARGE$^\sharp$}\xspace} % latex bug: cannot use \relsize{2} so use \LARGE
278
279\lstnewenvironment{csharp}[1][]{% necessary
280\lstset{
281language=[Sharp]C,
282escapechar=\$,                                                  % LaTeX escape in code
283moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
284}% lstset
285\lstset{#1}% necessary
286}{}
287
288% https://www.tutorialsteacher.com/codeeditor?cid=cs-mk8Ojx
289
290\Csharp is a dynamically-typed programming-language with a scoped, integral enumeration-type similar to C/\CC enumeration.
291\begin{csharp}
292enum Weekday : byte { Monday, Tuesday, Wednesday, Thursday@ = 10@, Friday, Saturday, Sunday@,@ };
293\end{csharp}
294The default underlying type is @int@, with auto-incrementing, implicit/explicit intialization, terminator comma, and optional integral typing (default @int@)
295A method cannot be defined in an enumeration type.
296As 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.
297\begin{csharp}
298int day = (int)Weekday.Friday;                  $\C{// day == 10}$
299Weekday weekday = (Weekdays)42;                 $\C{// weekday == 42}$
300Console.WriteLine( Weekday.Friday );    $\C{// print Friday}$
301string mon = Weekday.Monday.ToString();
302\end{csharp}
303
304The @Enum.GetValues@ pseudo-method retrieves an array of the enumeration constants for looping over an enumeration type or variable.
305\begin{csharp}
306foreach ( Weekday constant in @Enum.GetValues@( typeof(Weekday) ) ) {
307        Console.WriteLine( constant + " " + (int)constant ); // label, position
308}
309\end{csharp}
310
311The @Flags@ attribute creates a bit-flags enumeration, allowing bitwise operators @&@, @|@, @~@ (complement), @^@ (xor).
312\begin{csharp}
313@[Flags]@ public enum Weekday {
314        None = 0x0, Monday = 0x1, Tuesday = 0x2, Wednesday = 0x4,
315        Thursday = 0x8, Friday = 0x10, Saturday = 0x20, Sunday = 0x40,
316        Weekend = @Saturday | Sunday@,
317        Weekdays = @Monday | Tuesday | Wednesday | Thursday | Friday@
318}
319Weekday meetings = @Weekday.Monday | Weekday.Wednesday@; // 0x5
320\end{csharp}
321
322\Csharp supports an enumeration class to embed enumeration operations, where the enumerators are objects.
323\begin{csharp}
324public class PaymentType : Enumeration {
325    public static readonly PaymentType DebitCard = new PaymentType(0);
326    public static readonly PaymentType CreditCard = new PaymentType(1);
327    private PaymentType(int value, [CallerMemberName] string name = null) : base(value, name) { }
328}
329\end{csharp}
330Find a meaningful example and test it.
331
332
333\section{Golang}
334
335\lstnewenvironment{Go}[1][]{% necessary
336\lstset{
337language=Go,
338escapechar=\$,                                                  % LaTeX escape in code
339moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
340}% lstset
341\lstset{#1}% necessary
342}{}
343
344The Golang enumeration is similar to classic Pascal \lstinline[language=pascal]{const}, binding a name to a constant literal/expression.
345\begin{Go}
346const ( R = 0; G; B )                                   $\C{// implicit: 0 0 0}$
347const ( Fred = "Fred"; Mary = "Mary"; Jane = "Jane" ) $\C{// explicit: Fred Mary Jane}$
348const ( S = 0; T; USA = "USA"; U; V = 3.1; W ) $\C{// type change, implicit/explicit: 0 0 USA USA 3.1 3.1}$
349\end{Go}
350Constant names are unscoped and must be unique (no overloading).
351The first enumerator \emph{must} be explicitly initialized;
352subsequent enumerators can be implicitly or explicitly initialized.
353Implicit initialization is the previous (predecessor) enumerator value.
354
355Auto-incrementing is supported by the keyword \lstinline[language=Go]{iota}, available only in the \lstinline[language=Go]{const} declaration.
356The \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).
357\begin{Go}
358const ( R = @iota@; G; B )                              $\C{// implicit: 0 1 2}$
359const ( C = @iota + B + 1@; G; Y )              $\C{// implicit: 3 4 5}$
360\end{Go}
361An underscore \lstinline[language=golang]{const} identifier advances \lstinline[language=Go]{iota}.
362\begin{Go}
363const ( O1 = iota + 1; @_@; O3; @_@; O5 ) // 1, 3, 5 
364\end{Go}
365Auto-incrementing stops after an explicit initialization.
366\begin{Go}
367const ( Monday = iota; Tuesday; Wednesday; // 0, 1, 2
368         @Thursday = 10@; Friday; Saturday; Sunday ) // 10, 10, 10, 10
369\end{Go}
370Auto-incrementing can be restarted with an expression containing \emph{one} \lstinline[language=Go]{iota}.
371\begin{Go}
372const ( V1 = iota; V2; @V3 = 7;@ V4 = @iota@; V5 ) // 0 1 7 3 4
373const ( Monday = iota; Tuesday; Wednesday; // 0, 1, 2
374         @Thursday = 10;@ Friday = @iota - Wednesday + Thursday - 1@; Saturday; Sunday ) // 10, 11, 12, 13
375\end{Go}
376Note, \lstinline[language=Go]{iota} is advanced for an explicitly initialized enumerator, like the underscore @_@ identifier.
377
378
379\section{Java}
380
381\lstnewenvironment{Java}[1][]{% necessary
382\lstset{
383language=Java,
384escapechar=\$,                                                  % LaTeX escape in code
385moredelim=**[is][\color{red}]{`}{`},    % red highlighting @...@
386}% lstset
387\lstset{#1}% necessary
388}{}
389
390Here's a quick and simple example of an enum that defines the status of a pizza order; the order status can be ORDERED, READY or DELIVERED:
391\begin{Java}
392public enum PizzaStatus {
393    ORDERED,
394    READY,
395    DELIVERED;
396}
397\end{Java}
398Additionally, enums come with many useful methods that we would otherwise need to write if we were using traditional public static final constants.
399
400\paragraph{Custom Enum Methods}
401
402Now that we have a basic understanding of what enums are and how we can use them, we'll take our previous example to the next level by defining some extra API methods on the enum:
403\begin{Java}
404public class Pizza {
405    private PizzaStatus status;
406    public enum PizzaStatus {
407        ORDERED,
408        READY,
409        DELIVERED;
410    }
411    public boolean isDeliverable() {
412        if (getStatus() == PizzaStatus.READY) {
413            return true;
414        }
415        return false;
416    }
417    // Methods that set and get the status variable.
418}
419\end{Java}
420
421\paragraph{Comparing Enum Types Using "==" Operator}
422
423Since enum types ensure that only one instance of the constants exist in the JVM, we can safely use the "==" operator to compare two variables, like we did in the above example.
424Furthermore, the "==" operator provides compile-time and run-time safety.
425
426First, we'll look at run-time safety in the following snippet, where we'll use the "==" operator to compare statuses.
427Either value can be null and we won't get a NullPointerException. Conversely, if we use the equals method, we will get a NullPointerException:
428\begin{Java}
429if(testPz.getStatus().equals(Pizza.PizzaStatus.DELIVERED));
430if(testPz.getStatus() == Pizza.PizzaStatus.DELIVERED);
431\end{Java}
432As for compile-time safety, let's look at an example where we'll determine that an enum of a different type is equal by comparing it using the equals method.
433This is because the values of the enum and the getStatus method coincidentally are the same;
434however, logically the comparison should be false. We avoid this issue by using the "==" operator.
435
436The compiler will flag the comparison as an incompatibility error:
437\begin{Java}
438if(testPz.getStatus().equals(TestColor.GREEN));
439if(testPz.getStatus() == TestColor.GREEN);
440\end{Java}
441
442\paragraph{Using Enum Types in Switch Statements}
443
444We can use enum types in switch statements also:
445\begin{Java}
446public int getDeliveryTimeInDays() {
447    switch (status) {
448        case ORDERED: return 5;
449        case READY: return 2;
450        case DELIVERED: return 0;
451    }
452    return 0;
453}
454\end{Java}
455
456\paragraph{Fields, Methods and Constructors in Enums}
457
458We can define constructors, methods, and fields inside enum types, which makes them very powerful.
459
460Next, let's extend the example above by implementing the transition from one stage of a pizza order to another.
461We'll see how we can get rid of the if and switch statements used before:
462\begin{Java}
463public class Pizza {
464    private PizzaStatus status;
465    public enum PizzaStatus {
466        ORDERED (5){
467            @Override
468            public boolean isOrdered() {
469                return true;
470            }
471        },
472        READY (2){
473            @Override
474            public boolean isReady() {
475                return true;
476            }
477        },
478        DELIVERED (0){
479            @Override
480            public boolean isDelivered() {
481                return true;
482            }
483        };
484
485        private int timeToDelivery;
486        public boolean isOrdered() {return false;}
487        public boolean isReady() {return false;}
488        public boolean isDelivered(){return false;}
489        public int getTimeToDelivery() {
490            return timeToDelivery;
491        }
492        PizzaStatus (int timeToDelivery) {
493            this.timeToDelivery = timeToDelivery;
494        }
495    }
496    public boolean isDeliverable() {
497        return this.status.isReady();
498    }
499    public void printTimeToDeliver() {
500        System.out.println("Time to delivery is " + 
501          this.getStatus().getTimeToDelivery());
502    }
503    // Methods that set and get the status variable.
504}
505\end{Java}
506The test snippet below demonstrates how this works:
507\begin{Java}
508@Test
509public void givenPizaOrder_whenReady_thenDeliverable() {
510    Pizza testPz = new Pizza();
511    testPz.setStatus(Pizza.PizzaStatus.READY);
512    assertTrue(testPz.isDeliverable());
513}
514\end{Java}
515
516\paragraph{EnumSet and EnumMap}
517
518\paragraph{EnumSet}
519
520The EnumSet is a specialized Set implementation that's meant to be used with Enum types.
521
522Compared to a HashSet, it's a very efficient and compact representation of a particular Set of Enum constants, owing to the internal Bit Vector Representation that's used.
523It also provides a type-safe alternative to traditional int-based "bit flags," allowing us to write concise code that's more readable and maintainable.
524
525The EnumSet is an abstract class that has two implementations, RegularEnumSet and JumboEnumSet, one of which is chosen depending on the number of constants in the enum at the time of instantiation.
526
527Therefore, it's a good idea to use this set whenever we want to work with a collection of enum constants in most scenarios (like subsetting, adding, removing, and bulk operations like containsAll and removeAll), and use Enum.values() if we just want to iterate over all possible constants.
528
529In the code snippet below, we can see how to use EnumSet to create a subset of constants:
530\begin{Java}
531public class Pizza {
532    private static EnumSet<PizzaStatus> undeliveredPizzaStatuses =
533      EnumSet.of(PizzaStatus.ORDERED, PizzaStatus.READY);
534    private PizzaStatus status;
535    public enum PizzaStatus {
536        ...
537    }
538    public boolean isDeliverable() {
539        return this.status.isReady();
540    }
541    public void printTimeToDeliver() {
542        System.out.println("Time to delivery is " + 
543          this.getStatus().getTimeToDelivery() + " days");
544    }
545    public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) {
546        return input.stream().filter(
547          (s) -> undeliveredPizzaStatuses.contains(s.getStatus()))
548            .collect(Collectors.toList());
549    }
550    public void deliver() {
551        if (isDeliverable()) {
552            PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy()
553              .deliver(this);
554            this.setStatus(PizzaStatus.DELIVERED);
555        }
556    }
557    // Methods that set and get the status variable.
558}
559\end{Java}
560
561Executing the following test demonstrates the power of the EnumSet implementation of the Set interface:
562\begin{Java}
563@Test
564public void givenPizaOrders_whenRetrievingUnDeliveredPzs_thenCorrectlyRetrieved() {
565    List<Pizza> pzList = new ArrayList<>();
566    Pizza pz1 = new Pizza();
567    pz1.setStatus(Pizza.PizzaStatus.DELIVERED);
568
569    Pizza pz2 = new Pizza();
570    pz2.setStatus(Pizza.PizzaStatus.ORDERED);
571
572    Pizza pz3 = new Pizza();
573    pz3.setStatus(Pizza.PizzaStatus.ORDERED);
574
575    Pizza pz4 = new Pizza();
576    pz4.setStatus(Pizza.PizzaStatus.READY);
577
578    pzList.add(pz1);
579    pzList.add(pz2);
580    pzList.add(pz3);
581    pzList.add(pz4);
582
583    List<Pizza> undeliveredPzs = Pizza.getAllUndeliveredPizzas(pzList);
584    assertTrue(undeliveredPzs.size() == 3);
585}
586\end{Java}
587
588\paragraph{EnumMap}
589
590EnumMap is a specialized Map implementation meant to be used with enum constants as keys.
591Compared to its counterpart HashMap, it's an efficient and compact implementation that's internally represented as an array:
592\begin{Java}
593EnumMap<Pizza.PizzaStatus, Pizza> map;
594\end{Java}
595Let's look at an example of how we can use it in practice:
596\begin{Java}
597public static EnumMap<PizzaStatus, List<Pizza>>
598  groupPizzaByStatus(List<Pizza> pizzaList) {
599    EnumMap<PizzaStatus, List<Pizza>> pzByStatus = 
600      new EnumMap<PizzaStatus, List<Pizza>>(PizzaStatus.class);
601   
602    for (Pizza pz : pizzaList) {
603        PizzaStatus status = pz.getStatus();
604        if (pzByStatus.containsKey(status)) {
605            pzByStatus.get(status).add(pz);
606        } else {
607            List<Pizza> newPzList = new ArrayList<Pizza>();
608            newPzList.add(pz);
609            pzByStatus.put(status, newPzList);
610        }
611    }
612    return pzByStatus;
613}
614\end{Java}
615Executing the following test demonstrates the power of the EnumMap implementation of the Map interface:
616\begin{Java}
617@Test
618public void givenPizaOrders_whenGroupByStatusCalled_thenCorrectlyGrouped() {
619    List<Pizza> pzList = new ArrayList<>();
620    Pizza pz1 = new Pizza();
621    pz1.setStatus(Pizza.PizzaStatus.DELIVERED);
622
623    Pizza pz2 = new Pizza();
624    pz2.setStatus(Pizza.PizzaStatus.ORDERED);
625
626    Pizza pz3 = new Pizza();
627    pz3.setStatus(Pizza.PizzaStatus.ORDERED);
628
629    Pizza pz4 = new Pizza();
630    pz4.setStatus(Pizza.PizzaStatus.READY);
631
632    pzList.add(pz1);
633    pzList.add(pz2);
634    pzList.add(pz3);
635    pzList.add(pz4);
636
637    EnumMap<Pizza.PizzaStatus,List<Pizza>> map = Pizza.groupPizzaByStatus(pzList);
638    assertTrue(map.get(Pizza.PizzaStatus.DELIVERED).size() == 1);
639    assertTrue(map.get(Pizza.PizzaStatus.ORDERED).size() == 2);
640    assertTrue(map.get(Pizza.PizzaStatus.READY).size() == 1);
641}
642\end{Java}
643
644\paragraph{Singleton Pattern}
645
646Normally, implementing a class using the Singleton pattern is quite non-trivial.
647Enums provide a quick and easy way of implementing singletons.
648
649In addition, since the enum class implements the Serializable interface under the hood, the class is guaranteed to be a singleton by the JVM.
650This is unlike the conventional implementation, where we have to ensure that no new instances are created during deserialization.
651
652In the code snippet below, we see how we can implement a singleton pattern:
653\begin{Java}
654public enum PizzaDeliverySystemConfiguration {
655    INSTANCE;
656    PizzaDeliverySystemConfiguration() {
657        // Initialization configuration which involves
658        // overriding defaults like delivery strategy
659    }
660
661    private PizzaDeliveryStrategy deliveryStrategy = PizzaDeliveryStrategy.NORMAL;
662
663    public static PizzaDeliverySystemConfiguration getInstance() {
664        return INSTANCE;
665    }
666
667    public PizzaDeliveryStrategy getDeliveryStrategy() {
668        return deliveryStrategy;
669    }
670}
671\end{Java}
672
673\paragraph{Strategy Pattern}
674
675Conventionally, the Strategy pattern is written by having an interface that is implemented by different classes.
676
677Adding a new strategy means adding a new implementation class.
678With enums, we can achieve this with less effort, and adding a new implementation means simply defining another instance with some implementation.
679
680The code snippet below shows how to implement the Strategy pattern:
681\begin{Java}
682public enum PizzaDeliveryStrategy {
683    EXPRESS {
684        @Override
685        public void deliver(Pizza pz) {
686            System.out.println("Pizza will be delivered in express mode");
687        }
688    },
689    NORMAL {
690        @Override
691        public void deliver(Pizza pz) {
692            System.out.println("Pizza will be delivered in normal mode");
693        }
694    };
695
696    public abstract void deliver(Pizza pz);
697}
698\end{Java}
699Then we add the following method to the Pizza class:
700\begin{Java}
701public void deliver() {
702    if (isDeliverable()) {
703        PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy()
704          .deliver(this);
705        this.setStatus(PizzaStatus.DELIVERED);
706    }
707}
708
709@Test
710public void givenPizaOrder_whenDelivered_thenPizzaGetsDeliveredAndStatusChanges() {
711    Pizza pz = new Pizza();
712    pz.setStatus(Pizza.PizzaStatus.READY);
713    pz.deliver();
714    assertTrue(pz.getStatus() == Pizza.PizzaStatus.DELIVERED);
715}
716\end{Java}
717
7188. Java 8 and Enums
719
720We can rewrite the Pizza class in Java 8, and see how the methods getAllUndeliveredPizzas() and groupPizzaByStatus() become so concise with the use of lambdas and the Stream APIs:
721\begin{Java}
722public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) {
723    return input.stream().filter(
724      (s) -> !deliveredPizzaStatuses.contains(s.getStatus()))
725        .collect(Collectors.toList());
726}
727
728public static EnumMap<PizzaStatus, List<Pizza>>
729  groupPizzaByStatus(List<Pizza> pzList) {
730    EnumMap<PizzaStatus, List<Pizza>> map = pzList.stream().collect(
731      Collectors.groupingBy(Pizza::getStatus,
732      () -> new EnumMap<>(PizzaStatus.class), Collectors.toList()));
733    return map;
734}
735\end{Java}
736
737
738\section{Modula-3}
739
740\section{Rust}
741
742
743\section{Swift}
744
745\lstnewenvironment{swift}[1][]{% necessary
746\lstset{
747language=Swift,
748escapechar=\$,                                                  % LaTeX escape in code
749moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
750}% lstset
751\lstset{#1}% necessary
752}{}
753
754Model custom types that define a list of possible values.
755
756An 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.
757
758If you are familiar with C, you will know that C enumerations assign related names to a set of integer values.
759Enumerations in Swift are much more flexible, and don't have to provide a value for each case of the enumeration.
760If 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.
761
762Alternatively, 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.
763You 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.
764
765Enumerations in Swift are first-class types in their own right.
766They 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.
767Enumerations can also define initializers to provide an initial case value;
768can be extended to expand their functionality beyond their original implementation; and can conform to protocols to provide standard functionality.
769
770For more about these capabilities, see Properties, Methods, Initialization, Extensions, and Protocols.
771
772\paragraph{Enumeration Syntax}
773
774You introduce enumerations with the @enum@ keyword and place their entire definition within a pair of braces:
775\begin{swift}
776enum SomeEnumeration {
777        // enumeration definition goes here
778}
779\end{swift}
780Here's an example for the four main points of a compass:
781\begin{swift}
782enum CompassPoint {
783        case north
784        case south
785        case east
786        case west
787}
788\end{swift}
789The values defined in an enumeration (such as @north@, @south@, @east@, and @west@) are its enumeration cases.
790You use the @case@ keyword to introduce new enumeration cases.
791
792Note:
793Swift enumeration cases don't have an integer value set by default, unlike languages like C and Objective-C.
794In the CompassPoint example above, @north@, @south@, @east@ and @west@ don't implicitly equal 0, 1, 2 and 3.
795Instead, the different enumeration cases are values in their own right, with an explicitly defined type of CompassPoint.
796
797Multiple cases can appear on a single line, separated by commas:
798\begin{swift}
799enum Planet {
800        case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
801}
802\end{swift}
803Each enumeration definition defines a new type.
804Like other types in Swift, their names (such as @CompassPoint@ and @Planet@) start with a capital letter.
805Give enumeration types singular rather than plural names, so that they read as self-evident:
806\begin{swift}
807var directionToHead = CompassPoint.west
808\end{swift}
809The type of @directionToHead@ is inferred when it's initialized with one of the possible values of @CompassPoint@.
810Once @directionToHead@ is declared as a @CompassPoint@, you can set it to a different @CompassPoint@ value using a shorter dot syntax:
811\begin{swift}
812directionToHead = .east
813\end{swift}
814The type of @directionToHead@ is already known, and so you can drop the type when setting its value.
815This makes for highly readable code when working with explicitly typed enumeration values.
816
817\paragraph{Matching Enumeration Values with a Switch Statement}
818
819You can match individual enumeration values with a switch statement:
820\begin{swift}
821directionToHead = .south
822switch directionToHead {
823case .north:
824        print("Lots of planets have a north")
825case .south:
826        print("Watch out for penguins")
827case .east:
828        print("Where the sun rises")
829case .west:
830        print("Where the skies are blue")
831}
832// Prints "Watch out for penguins"
833\end{swift}
834You can read this code as:
835\begin{quote}
836"Consider the value of directionToHead.
837In the case where it equals @.north@, print "Lots of planets have a north".
838In the case where it equals @.south@, print "Watch out for penguins"."
839
840...and so on.
841\end{quote}
842As described in Control Flow, a switch statement must be exhaustive when considering an enumeration's cases.
843If the case for @.west@ is omitted, this code doesn't compile, because it doesn't consider the complete list of @CompassPoint@ cases.
844Requiring exhaustiveness ensures that enumeration cases aren't accidentally omitted.
845
846When 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:
847\begin{swift}
848let somePlanet = Planet.earth
849switch somePlanet {
850case .earth:
851        print("Mostly harmless")
852default:
853        print("Not a safe place for humans")
854}
855// Prints "Mostly harmless"
856\end{swift}
857
858\paragraph{Iterating over Enumeration Cases}
859
860For some enumerations, it's useful to have a collection of all of that enumeration's cases.
861You enable this by writing @CaseIterable@ after the enumeration's name.
862Swift exposes a collection of all the cases as an allCases property of the enumeration type.
863Here's an example:
864\begin{swift}
865enum Beverage: CaseIterable {
866        case coffee, tea, juice
867}
868let numberOfChoices = Beverage.allCases.count
869print("\(numberOfChoices) beverages available")
870// Prints "3 beverages available"
871\end{swift}
872In the example above, you write @Beverage.allCases@ to access a collection that contains all of the cases of the @Beverage@ enumeration.
873You 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.
874The example above counts how many cases there are, and the example below uses a for-in loop to iterate over all the cases.
875\begin{swift}
876for beverage in Beverage.allCases {
877        print(beverage)
878}
879// coffee
880// tea
881// juice
882\end{swift}
883The syntax used in the examples above marks the enumeration as conforming to the @CaseIterable@ protocol.
884For information about protocols, see Protocols.
885
886\paragraph{Associated Values}
887The examples in the previous section show how the cases of an enumeration are a defined (and typed) value in their own right.
888You can set a constant or variable to Planet.earth, and check for this value later.
889However, it's sometimes useful to be able to store values of other types alongside these case values.
890This additional information is called an associated value, and it varies each time you use that case as a value in your code.
891
892You 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.
893Enumerations similar to these are known as discriminated unions, tagged unions, or variants in other programming languages.
894
895For example, suppose an inventory tracking system needs to track products by two different types of barcode.
896Some products are labeled with 1D barcodes in UPC format, which uses the numbers 0 to 9.
897Each barcode has a number system digit, followed by five manufacturer code digits and five product code digits.
898These are followed by a check digit to verify that the code has been scanned correctly:
899
900Other 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:
901
902It'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.
903
904In Swift, an enumeration to define product barcodes of either type might look like this:
905\begin{swift}
906enum Barcode {
907        case upc(Int, Int, Int, Int)
908        case qrCode(String)
909}
910\end{swift}
911This can be read as:
912\begin{quote}
913"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@."
914\end{quote}
915This 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@.
916
917You can then create new barcodes using either type:
918\begin{swift}
919var productBarcode = Barcode.upc(8, 85909, 51226, 3)
920\end{swift}
921This 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)@.
922
923You can assign the same product a different type of barcode:
924\begin{swift}
925productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
926\end{swift}
927At this point, the original @Barcode.upc@ and its integer values are replaced by the new @Barcode.qrCode@ and its string value.
928Constants 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.
929
930You can check the different barcode types using a switch statement, similar to the example in Matching Enumeration Values with a Switch Statement.
931This time, however, the associated values are extracted as part of the switch statement.
932You 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:
933\begin{swift}
934switch productBarcode {
935case .upc(let numberSystem, let manufacturer, let product, let check):
936        print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
937case .qrCode(let productCode):
938        print("QR code: \(productCode).")
939}
940// Prints "QR code: ABCDEFGHIJKLMNOP."
941\end{swift}
942If 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:
943\begin{swift}
944switch productBarcode {
945case let .upc(numberSystem, manufacturer, product, check):
946        print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
947case let .qrCode(productCode):
948        print("QR code: \(productCode).")
949}
950// Prints "QR code: ABCDEFGHIJKLMNOP."
951\end{swift}
952
953\paragraph{Raw Values}
954
955The barcode example in Associated Values shows how cases of an enumeration can declare that they store associated values of different types.
956As an alternative to associated values, enumeration cases can come prepopulated with default values (called raw values), which are all of the same type.
957
958Here's an example that stores raw ASCII values alongside named enumeration cases:
959\begin{swift}
960enum ASCIIControlCharacter: Character {
961        case tab = "\t"
962        case lineFeed = "\n"
963        case carriageReturn = "\r"
964}
965\end{swift}
966Here, 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.
967Character values are described in Strings and Characters.
968
969Raw values can be strings, characters, or any of the integer or floating-point number types.
970Each raw value must be unique within its enumeration declaration.
971
972Note
973
974Raw values are not the same as associated values.
975Raw values are set to prepopulated values when you first define the enumeration in your code, like the three ASCII codes above.
976The raw value for a particular enumeration case is always the same.
977Associated 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.
978Implicitly Assigned Raw Values
979
980When 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.
981When you don't, Swift automatically assigns the values for you.
982
983For example, when integers are used for raw values, the implicit value for each case is one more than the previous case.
984If the first case doesn't have a value set, its value is 0.
985
986The enumeration below is a refinement of the earlier Planet enumeration, with integer raw values to represent each planet's order from the sun:
987
988\begin{swift}
989enum Planet: Int {
990        case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
991}
992\end{swift}
993In the example above, Planet.mercury has an explicit raw value of 1, Planet.venus has an implicit raw value of 2, and so on.
994
995When strings are used for raw values, the implicit value for each case is the text of that case's name.
996
997The enumeration below is a refinement of the earlier CompassPoint enumeration, with string raw values to represent each direction's name:
998\begin{swift}
999enum CompassPoint: String {
1000        case north, south, east, west
1001}
1002\end{swift}
1003In the example above, CompassPoint.south has an implicit raw value of "south", and so on.
1004
1005You access the raw value of an enumeration case with its rawValue property:
1006\begin{swift}
1007let earthsOrder = Planet.earth.rawValue
1008// earthsOrder is 3
1009
1010let sunsetDirection = CompassPoint.west.rawValue
1011// sunsetDirection is "west"
1012\end{swift}
1013
1014\paragraph{Initializing from a Raw Value}
1015
1016If 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.
1017You can use this initializer to try to create a new instance of the enumeration.
1018
1019This example identifies Uranus from its raw value of 7:
1020\begin{swift}
1021let possiblePlanet = Planet(rawValue: 7)
1022// possiblePlanet is of type Planet? and equals Planet.uranus
1023\end{swift}
1024Not all possible Int values will find a matching planet, however.
1025Because of this, the raw value initializer always returns an optional enumeration case.
1026In the example above, possiblePlanet is of type Planet?, or "optional Planet."
1027Note
1028
1029The raw value initializer is a failable initializer, because not every raw value will return an enumeration case.
1030For more information, see Failable Initializers.
1031
1032If you try to find a planet with a position of 11, the optional Planet value returned by the raw value initializer will be nil:
1033\begin{swift}
1034let positionToFind = 11
1035if let somePlanet = Planet(rawValue: positionToFind) {
1036        switch somePlanet {
1037        case .earth:
1038                print("Mostly harmless")
1039        default:
1040                print("Not a safe place for humans")
1041        }
1042} else {
1043        print("There isn't a planet at position \(positionToFind)")
1044}
1045// Prints "There isn't a planet at position 11"
1046\end{swift}
1047This example uses optional binding to try to access a planet with a raw value of 11.
1048The 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.
1049In this case, it isn't possible to retrieve a planet with a position of 11, and so the else branch is executed instead.
1050
1051\paragraph{Recursive Enumerations}
1052
1053A recursive enumeration is an enumeration that has another instance of the enumeration as the associated value for one or more of the enumeration cases.
1054You indicate that an enumeration case is recursive by writing indirect before it, which tells the compiler to insert the necessary layer of indirection.
1055
1056For example, here is an enumeration that stores simple arithmetic expressions:
1057\begin{swift}
1058enum ArithmeticExpression {
1059        case number(Int)
1060        indirect case addition(ArithmeticExpression, ArithmeticExpression)
1061        indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
1062}
1063\end{swift}
1064You 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:
1065\begin{swift}
1066indirect enum ArithmeticExpression {
1067        case number(Int)
1068        case addition(ArithmeticExpression, ArithmeticExpression)
1069        case multiplication(ArithmeticExpression, ArithmeticExpression)
1070}
1071\end{swift}
1072This enumeration can store three kinds of arithmetic expressions: a plain number, the addition of two expressions, and the multiplication of two expressions.
1073The addition and multiplication cases have associated values that are also arithmetic expressions -- these associated values make it possible to nest expressions.
1074For 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.
1075Because the data is nested, the enumeration used to store the data also needs to support nesting -- this means the enumeration needs to be recursive.
1076The code below shows the ArithmeticExpression recursive enumeration being created for (5 + 4) * 2:
1077\begin{swift}
1078let five = ArithmeticExpression.number(5)
1079let four = ArithmeticExpression.number(4)
1080let sum = ArithmeticExpression.addition(five, four)
1081let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
1082\end{swift}
1083A recursive function is a straightforward way to work with data that has a recursive structure.
1084For example, here's a function that evaluates an arithmetic expression:
1085\begin{swift}
1086func evaluate(_ expression: ArithmeticExpression) -> Int {
1087        switch expression {
1088        case let .number(value):
1089                return value
1090        case let .addition(left, right):
1091                return evaluate(left) + evaluate(right)
1092        case let .multiplication(left, right):
1093                return evaluate(left) * evaluate(right)
1094        }
1095}
1096
1097print(evaluate(product))
1098// Prints "18"
1099\end{swift}
1100This function evaluates a plain number by simply returning the associated value.
1101It 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.
1102
1103
1104\section{Python}
1105
1106\section{Algebraic Data Type}
Note: See TracBrowser for help on using the repository browser.