Ignore:
Timestamp:
Feb 22, 2024, 11:44:38 AM (3 months ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
master
Children:
2810700, 624ba3a5
Parents:
38f5006
Message:

more proofreading on enumeration thesis

File:
1 edited

Legend:

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

    r38f5006 r7bb516f  
    22\label{s:RelatedWork}
    33
    4 Enumerations exist in many popular programming languages, \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.
    5 There are a large set of overlapping features among these languages, but each language has its own unique extensions and restrictions.
     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.
    66
    77
     
    4848escapechar=\$,                                                  % LaTeX escape in code
    4949moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
     50literate={'}{\ttfamily'\!}1                             % remove '-' literate as comment
    5051}% lstset
    5152\lstset{#1}% necessary
    5253}{}
    5354
    54 An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators) of the type.
     55An Ada enumeration type is an ordered list of constants, called \Newterm{literals} (enumerators).
    5556\begin{ada}
    5657type RGB is ( @Red@, @Green@, Blue ); -- 3 literals (enumerators)
     
    5859No other enumerators are assignable to objects of this type.
    5960Enumerators 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
    6067Like C, Ada enumerators are unscoped, \ie enumerators declared inside of an enum are visible (projected) into the enclosing scope.
    61 Note, Ada is case-insensitive so names may appear in multiple forms and still be the same name (a questionable design decision).
    62 The only operators on enumeration types are the ordering operators, @=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relation is given implicitly by the sequence of enumerators.
     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.
    6370
    6471Ada enumerators are overloadable.
     
    6774\end{ada}
    6875Like \CFA, Ada uses an advanced type-resolution algorithm, including the left-hand side of assignment, to disambiguate among overloaded names.
    69 Figure~\VRef{f:AdaEnumeration} shows how ambiguities are handled using a cast, \eg @RGB'(Red)@.
     76Figure~\VRef{f:AdaEnumeration} shows how ambiguities are handled using a cast, \eg \lstinline[language=ada]{RGB'(Red)}.
    7077
    7178\begin{figure}
     
    7380with Ada.Text_IO; use Ada.Text_IO;
    7481procedure test is
    75    type RGB is ( Red, Green, Blue );
    76    type Traffic_Light is ( Red, Yellow, Green );
    77    procedure @Print@( Colour : RGB ) is begin
     82   type RGB is ( @Red@, Green, Blue );
     83   type Traffic_Light is ( @Red@, Yellow, Green );
     84   procedure @Red@( Colour : RGB ) is begin
    7885       Put_Line( "Colour is " & RGB'Image( Colour ) );
    79    end Print;
    80    procedure @Print@( TL : Traffic_Light ) is begin
     86   end Red;
     87   procedure @Red@( TL : Traffic_Light ) is begin
    8188       Put_Line( "Light is " & Traffic_Light'Image( TL ) );
    82    end Print;
     89   end Red;
    8390begin
    84     Print( Blue );                              $\C[2in]{-- RGB}$
    85     Print( Yellow );                    $\C{-- Traffic\_Light}$
    86     Print( @RGB'(Red)@ );               $\C{-- ambiguous without cast}\CRT$
     91    @Red@( Blue );                               -- RGB
     92    @Red@( Yellow );                            -- Traffic_Light
     93    @Red@( @RGB'(Red)@ );               -- ambiguous without cast
    8794end test;
    8895\end{ada}
     
    9198\end{figure}
    9299
    93 Like many other declarative items, enumeration literals can be renamed.
    94 In fact, such a literal is actually a function, so it has to be renamed as such:
    95 \begin{ada}
    96 function Red return P.RGB renames P.Red;
    97 \end{ada}
    98 Here, @RGB@ is assumed to be defined in package @P@, which is visible at the place of the renaming declaration.
    99 Renaming makes @Red@ directly visible without necessity to resort the use-clause.
     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}
    100108
    101109There are four enumeration pseudo functions (attributes): @'Pos@, @'Val@, @'Image@, and @'Value@.
     
    105113RGB'Val(0) = Red
    106114\end{ada}
    107 Funcion @Image@ returns enumerator label (in capital letters); the inverse function @Value@ returns the corresponding enumerator.
     115Funcion @Image@ returns the enumerator label (in capital letters); the inverse function @Value@ returns the corresponding enumerator.
    108116\begin{ada}
    109117RGB'Image( Red ) = "RED"
     
    111119\end{ada}
    112120These attributes are important for simple IO (there are more elaborate IO facilities in @Ada.Text_IO@ for enumeration types).
    113 As 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 intuitively result based on the attribute name.
    114 
    115 
    116 Note that redeclaration as a function does not affect the staticness of the literal.
    117 
    118 \paragraph{Characters as enumeration literals} ~\newline
     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.
    119124Rather unique to Ada is the use of character literals as enumeration literals:
    120125\begin{ada}
     
    156161Hence, the ordering of the enumerators is crucial to provide the necessary ranges.
    157162
    158 \paragraph{Using enumerations} ~\newline
    159 Enumeration types being scalar subtypes, type attributes such as @First@ and @Succ@ will allow stepping through a subsequence of the values.
     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.
    160171\begin{ada}
    161172case Day_Of_Week'First is
     
    183194\end{ada}
    184195
    185 \begin{ada}
    186 type Subtype_Name is (Id1, Id2, Id3 ... );
    187 \end{ada}
    188 where @Id1@, @Id2@, etc. are identifiers or characters literals.
    189 In either case, the legal values of the type are referred to as "enumeration literals."
    190 Each 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.
    191 
    192 
    193 \section{C\raisebox{-0.7ex}{\LARGE$^\sharp$}\xspace} % latex bug: cannot use \relsize{2} so use \LARGE
    194 
    195 \lstnewenvironment{csharp}[1][]{% necessary
    196 \lstset{
    197 language=[Sharp]C,
    198 escapechar=\$,                                                  % LaTeX escape in code
    199 moredelim=**[is][\color{red}]{@}{@},    % red highlighting @...@
    200 }% lstset
    201 \lstset{#1}% necessary
    202 }{}
    203 
    204 An enumeration type (or enum type) is a value type defined by a set of named constants of the underlying integral numeric type.
    205 To define an enumeration type, use the enum keyword and specify the names of enum members:
    206 \begin{csharp}
    207 enum Season {
    208         Spring,
    209         Summer,
    210         Autumn,
    211         Winter
    212 }
    213 \end{csharp}
    214 By default, the associated constant values of enum members are of type @int@;
    215 they start with zero and increase by one following the definition text order.
    216 
    217 You can explicitly specify any other integral numeric type as an underlying type of an enumeration type.
    218 You can also explicitly specify the associated constant values, as the following example shows:
    219 \begin{csharp}
    220 enum ErrorCode : ushort {
    221         None = 0,
    222         Unknown = 1,
    223         ConnectionLost = 100,
    224         OutlierReading = 200
    225 }
    226 \end{csharp}
    227 You cannot define a method inside the definition of an enumeration type.
    228 To add functionality to an enumeration type, create an extension method.
    229 
    230 The default value of an enumeration type @E@ is the value produced by expression @(E)0@, even if zero doesn't have the corresponding enum member.
    231 
    232 You use an enumeration type to represent a choice from a set of mutually exclusive values or a combination of choices.
    233 To represent a combination of choices, define an enumeration type as bit flags.
    234 
    235 \paragraph{Enumeration types as bit flags}
    236 
    237 If you want an enumeration type to represent a combination of choices, define enum members for those choices such that an individual choice is a bit field.
    238 That is, the associated values of those enum members should be the powers of two.
    239 Then, you can use the bitwise logical operators @|@ or @&@ to combine choices or intersect combinations of choices, respectively.
    240 To indicate that an enumeration type declares bit fields, apply the @Flags@ attribute to it.
    241 As the following example shows, you can also include some typical combinations in the definition of an enumeration type.
    242 \begin{csharp}
    243 [Flags]
    244 public enum Days {
    245         None      = 0b_0000_0000,  // 0
    246         Monday  = 0b_0000_0001,  // 1
    247         Tuesday   = 0b_0000_0010,  // 2
    248         Wednesday = 0b_0000_0100,  // 4
    249         Thursday  = 0b_0000_1000,  // 8
    250         Friday  = 0b_0001_0000,  // 16
    251         Saturday  = 0b_0010_0000,  // 32
    252         Sunday  = 0b_0100_0000,  // 64
    253         Weekend   = Saturday | Sunday
    254 }
    255 
    256 public class FlagsEnumExample {
    257         public static void Main() {
    258                 Days meetingDays = Days.Monday | Days.Wednesday | Days.Friday;
    259                 Console.WriteLine(meetingDays);
    260                 // Output:
    261                 // Monday, Wednesday, Friday
    262 
    263                 Days workingFromHomeDays = Days.Thursday | Days.Friday;
    264                 Console.WriteLine($\$$"Join a meeting by phone on {meetingDays & workingFromHomeDays}");
    265                 // Output:
    266                 // Join a meeting by phone on Friday
    267 
    268                 bool isMeetingOnTuesday = (meetingDays & Days.Tuesday) == Days.Tuesday;
    269                 Console.WriteLine($\$$"Is there a meeting on Tuesday: {isMeetingOnTuesday}");
    270                 // Output:
    271                 // Is there a meeting on Tuesday: False
    272 
    273                 var a = (Days)37;
    274                 Console.WriteLine(a);
    275                 // Output:
    276                 // Monday, Wednesday, Saturday
    277         }
    278 }
    279 \end{csharp}
    280 For more information and examples, see the System.FlagsAttribute API reference page and the Non-exclusive members and the Flags attribute section of the System.Enum API reference page.
    281 
    282 \paragraph{The System.Enum type and enum constraint}
    283 
    284 The System.Enum type is the abstract base class of all enumeration types.
    285 It provides a number of methods to get information about an enumeration type and its values.
    286 For more information and examples, see the System.Enum API reference page.
    287 
    288 You can use System.Enum in a base class constraint (that is known as the enum constraint) to specify that a type parameter is an enumeration type.
    289 Any enumeration type also satisfies the struct constraint, which is used to specify that a type parameter is a non-nullable value type.
    290 Conversions
    291 
    292 For any enumeration type, there exist explicit conversions between the enumeration type and its underlying integral type.
    293 If you cast an enum value to its underlying type, the result is the associated integral value of an enum member.
    294 \begin{csharp}
    295 public enum Season
    296 {
    297         Spring,
    298         Summer,
    299         Autumn,
    300         Winter
    301 }
    302 
    303 public class EnumConversionExample
    304 {
    305         public static void Main()
    306         {
    307                 Season a = Season.Autumn;
    308                 Console.WriteLine($\$$"Integral value of {a} is {(int)a}");  // output: Integral value of Autumn is 2
    309 
    310                 var b = (Season)1;
    311                 Console.WriteLine(b);  // output: Summer
    312 
    313                 var c = (Season)4;
    314                 Console.WriteLine(c);  // output: 4
    315         }
    316 }
    317 \end{csharp}
    318 
    319196
    320197\section{\CC}
     
    330207}{}
    331208
    332 \CC is backwards compatible with C, so it inherited C's enumerations.
     209\CC is largely backwards compatible with C, so it inherited C's enumerations.
    333210However, the following non-backwards compatible changes have been made.
    334211
     
    398275
    399276
     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
    400333\section{Golang}
    401334
     
    409342}{}
    410343
    411 The Golang enumeration is similar to classical Pascal \lstinline[language=pascal]{const}, where the type of a \lstinline[language=Golang]{const} name is the type of its constant.
     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}
    412350Constant names are unscoped and must be unique (no overloading).
    413351The first enumerator \emph{must} be explicitly initialized;
    414352subsequent enumerators can be implicitly or explicitly initialized.
    415 Implicit initialization is the previous (left) enumerator value.
    416 \begin{Go}
    417 const ( R = 0; G; B )                                   $\C{// implicit: 0 0 0}$
    418 const ( Fred = "Fred"; Mary = "Mary"; Jane = "Jane" ) $\C{// explicit: Fred Mary Jane}$
    419 const ( H = 0; Jack = "Jack"; J, K = 3; I )     $\C{// type change, implicit/explicit: 0 Jack Jack 3 3}$
    420 \end{Go}
     353Implicit initialization is the previous (predecessor) enumerator value.
    421354
    422355Auto-incrementing is supported by the keyword \lstinline[language=Go]{iota}, available only in the \lstinline[language=Go]{const} declaration.
    423 The \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.
     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).
    424357\begin{Go}
    425358const ( R = @iota@; G; B )                              $\C{// implicit: 0 1 2}$
     
    441374         @Thursday = 10;@ Friday = @iota - Wednesday + Thursday - 1@; Saturday; Sunday ) // 10, 11, 12, 13
    442375\end{Go}
    443 Note, \lstinline[language=Go]{iota} is advanced for the explicitly initialized enumerator, like the underscore @_@ identifier.
     376Note, \lstinline[language=Go]{iota} is advanced for an explicitly initialized enumerator, like the underscore @_@ identifier.
     377
    444378
    445379\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
    446737
    447738\section{Modula-3}
Note: See TracChangeset for help on using the changeset viewer.