source: doc/theses/jiada_liang_MMath/relatedwork.tex @ 022bce0

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

more proofreading on enumeration thesis

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