source: doc/theses/jiada_liang_MMath/relatedwork.tex@ 175a750e

Last change on this file since 175a750e was 175a750e, checked in by JiadaL <j82liang@…>, 15 months ago

change the superset row as we now conclude adt form a superset

  • Property mode set to 100644
File size: 62.6 KB
RevLine 
[956299b]1\chapter{Related Work}
2\label{s:RelatedWork}
3
[c1c0efdb]4Enumeration-like features exist in many popular programming languages, both past and present, \eg Pascal~\cite{Pascal}, Ada~\cite{Ada}, \Csharp~\cite{Csharp}, OCaml~\cite{OCaml} \CC, Go~\cite{Go}, Haskell~\cite{Haskell} \see{discussion in \VRef{s:AlgebraicDataType}}, Java~\cite{Java}, Rust~\cite{Rust}, Swift~\cite{Swift}, Python~\cite{Python}.
[11cced6]5Among these languages, there is a large set of overlapping features, but each language has its own unique extensions and restrictions.
[f936e23]6
[41f4e2d]7
[38f5006]8\section{Pascal}
[7d9a805b]9\label{s:Pascal}
[f936e23]10
[41f4e2d]11Pascal introduced the \lstinline[language=Pascal]{const} aliasing declaration binding a name to a constant literal/expression.
[38f5006]12\begin{pascal}
[41f4e2d]13const Three = 2 + 1; NULL = NIL; PI = 3.14159; Plus = '+'; Fred = 'Fred';
[38f5006]14\end{pascal}
[f6321173]15As stated, this mechanism is not an enumeration because there is no specific type (pseudo enumeration).
[41f4e2d]16Hence, there is no notion of a (possibly ordered) set.
[1d5e5601]17The type of each constant name (enumerator) is inferred from the constant-expression type.
[38f5006]18
[c1c0efdb]19Pascal introduced the enumeration type characterized by a set of ordered, unscoped identifiers (enumerators), which are not overloadable.\footnote{%
[41f4e2d]20Pascal is \emph{case-insensitive} so identifiers may appear in multiple forms and still be the same, \eg \lstinline{Mon}, \lstinline{moN}, and \lstinline{MON} (a questionable design decision).}
21\begin{pascal}
22type Week = ( Mon, Tue, Wed, Thu, Fri, Sat, Sun );
23\end{pascal}
24Object initialization and assignment are restricted to the enumerators of this type.
[11cced6]25Enumerators are auto-initialized from left to right, starting at zero and incrementing by 1.
[41f4e2d]26Enumerators \emph{cannot} be explicitly initialized.
27Pascal provides a predefined type \lstinline[language=Pascal]{Boolean} defined as:
28\begin{pascal}
29type Boolean = ( false, true );
30\end{pascal}
[29c8675]31The enumeration supports the relational operators @=@, @<>@, @<@, @<=@, @>=@, and @>@, interpreted as as comparison in terms of declaration order.
[41f4e2d]32
33The following auto-generated pseudo-functions exist for all enumeration types:
34\begin{cquote}
35\begin{tabular}{@{}ll@{}}
36@succ( T )@ & @succ( Tue ) = Wed@ \\
37@pred( T )@ & @pred( Tue ) = Mon@ \\
38@ord( T )@ & @ord( Tue ) = 1@
39\end{tabular}
40\end{cquote}
41
[c1c0efdb]42Pascal provides \emph{consecutive} subsetting of an enumeration using a subrange type.
[41f4e2d]43\begin{pascal}
44type Week = ( Mon, Tue, Wed, Thu, Fri, Sat, Sun );
[c1c0efdb]45 Weekday = @Mon..Fri@; { subtype }
46 Weekend = @Sat..Sun@;
[41f4e2d]47var day : Week;
[c1c0efdb]48 wday : Weekday;
49 wend : Weekend;
[41f4e2d]50\end{pascal}
[29c8675]51Hence, declaration order of enumerators is crucial to provide the necessary ranges.
[11cced6]52There is a bidirectional assignment between the enumeration and its subranges.
[41f4e2d]53\begin{pascal}
54day := Sat;
[d96d4f0]55@wday := day;@ $\C[1.5in]{\{ check \}}$
56wend := day; $\C{\{ maybe check \}}$
[41f4e2d]57day := Mon;
[d96d4f0]58wday := day; $\C{\{ maybe check \}}$
59@wend := day;@ $\C{\{ check \}}$
60day := wday; $\C{\{ no check \}}$
61day := wend; $\C{\{ no check \}}\CRT$
[41f4e2d]62\end{pascal}
[11cced6]63A static/dynamic range check should be performed to verify the values assigned to subtypes.
[41f4e2d]64(Free Pascal does not check and aborts in certain situations, like writing an invalid enumerator.)
65
66An enumeration can be used in the @if@ and @case@ statements or iterating constructs.
67\begin{cquote}
68\setlength{\tabcolsep}{15pt}
69\begin{tabular}{@{}ll@{}}
70\begin{pascal}
[c1c0efdb]71day := Mon;
[41f4e2d]72if @day@ = wday then
73 Writeln( day );
74if @day@ <= Fri then
75 Writeln( 'weekday');
[c1c0efdb]76Mon
77weekday
[41f4e2d]78\end{pascal}
79&
80\begin{pascal}
[c1c0efdb]81
[41f4e2d]82case @day@ of
83 Mon..Fri :
84 Writeln( 'weekday');
85 Sat..Sun :
86 Writeln( 'weekend')
87end;
[c1c0efdb]88weekday
[41f4e2d]89\end{pascal}
90\end{tabular}
91\end{cquote}
92\begin{cquote}
93\setlength{\tabcolsep}{15pt}
94\begin{tabular}{@{}ll@{}}
95\begin{pascal}
[c1c0efdb]96while day <= Sun do begin
[41f4e2d]97 Write( day, ' ' );
98 day := succ( day );
99end;
[c1c0efdb]100Mon Tue Wed Thu Fri Sat Sun
[41f4e2d]101\end{pascal}
102&
103\begin{pascal}
[c1c0efdb]104for day := Mon to Sun do begin
[41f4e2d]105 Write( day, ' ' );
106
107end;
[c1c0efdb]108Mon Tue Wed Thu Fri Sat Sun
[41f4e2d]109\end{pascal}
110\end{tabular}
111\end{cquote}
[11cced6]112Note that subtypes @Weekday@ and @Weekend@ cannot be used to define a case or loop range.
[41f4e2d]113
114An enumeration type can be used as an array dimension and subscript.
[f936e23]115\begin{pascal}
[41f4e2d]116Lunch : array( @Week@ ) of Time;
117for day in Week loop
118 Lunch( @day@ ) := ... ; { set lunch time }
119end loop;
[f936e23]120\end{pascal}
[41f4e2d]121
122Free Pascal~\cite[\S~3.1.1]{FreePascal} is a modern, object-oriented version of Pascal, with a C-style enumeration type.
123Enumerators can be assigned explicit values assigned in ascending numerical order using a constant expression, and the range can be non-consecutive.
124\begin{pascal}
125type Count = ( Zero, One, Two, Ten = 10, Eleven );
126\end{pascal}
127Pseudo-functions @pred@ and @succ@ can only be used if the range is consecutive.
128Enumerating gives extraneous values.
129\begin{pascal}
130for cnt := Zero to Eleven do begin
131 Write( ord( cnt ), ' ' );
132end;
1330 1 2 @3 4 5 6 7 8 9@ 10 11
134\end{pascal}
135
[11cced6]136The 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.
[29c8675]137The integral size can be explicitly specified using compiler directive \$@PACKENUM@~$N$, where $N$ is the number of bytes, \eg:
[f936e23]138\begin{pascal}
[956299b]139Type @{$\color{red}\$$PACKENUM 1}@ SmallEnum = ( one, two, three );
[c033405]140 @{$\color{red}\$$PACKENUM 4}@ LargeEnum = ( BigOne, BigTwo, BigThree );
[956299b]141Var S : SmallEnum; { 1 byte }
142 L : LargeEnum; { 4 bytes}
[f936e23]143\end{pascal}
[956299b]144
145
146\section{Ada}
[c1c0efdb]147\label{s:Ada}
[f936e23]148
[41f4e2d]149An Ada enumeration type is a set of ordered, unscoped identifiers (enumerators) bound to \emph{unique} \newterm{literals}.\footnote{%
[4da9142]150Ada is \emph{case-insensitive} so identifiers may appear in multiple forms and still be the same, \eg \lstinline{Mon}, \lstinline{moN}, and \lstinline{MON} (a questionable design decision).}
[f936e23]151\begin{ada}
[4da9142]152type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun ); -- literals (enumerators)
[f936e23]153\end{ada}
[1d5e5601]154Object initialization and assignment are restricted to the enumerators of this type.
[c1c0efdb]155While Ada enumerators are unscoped, like C, Ada enumerators are overloadable.
[f936e23]156\begin{ada}
[4da9142]157type RGB is ( @Red@, @Green@, Blue );
[38f5006]158type Traffic_Light is ( @Red@, Yellow, @Green@ );
[f936e23]159\end{ada}
[11cced6]160Like \CFA, Ada uses a type-resolution algorithm, including the left-hand side of the assignment, to disambiguate among overloaded identifiers.
[c1c0efdb]161\VRef[Figure]{f:AdaEnumeration} shows how ambiguity is handled using a cast, \eg \lstinline[language=ada]{RGB'(Red)}.
[956299b]162
[38f5006]163\begin{figure}
[f936e23]164\begin{ada}
[38f5006]165with Ada.Text_IO; use Ada.Text_IO;
166procedure test is
[7d9a805b]167 type RGB is ( @Red@, Green, Blue );
168 type Traffic_Light is ( @Red@, Yellow, Green ); -- overload
169 procedure @Red@( Colour : RGB ) is begin -- overload
170 Put_Line( "Colour is " & RGB'Image( Colour ) );
171 end Red;
172 procedure @Red@( TL : Traffic_Light ) is begin -- overload
173 Put_Line( "Light is " & Traffic_Light'Image( TL ) );
174 end Red;
[38f5006]175begin
[7d9a805b]176 @Red@( Blue ); -- RGB
177 @Red@( Yellow ); -- Traffic_Light
178 @Red@( @RGB'(Red)@ ); -- ambiguous without cast
[38f5006]179end test;
[f936e23]180\end{ada}
[38f5006]181\caption{Ada Enumeration Overload Resolution}
[c1c0efdb]182\label{f:AdaEnumeration}
[38f5006]183\end{figure}
184
[29c8675]185Enumerators without initialization are auto-initialized from left to right, starting at zero and incrementing by 1.
[4da9142]186Enumerators with initialization must set \emph{all} enumerators in \emph{ascending} order, \ie there is no auto-initialization.
187\begin{ada}
188type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun );
[c1c0efdb]189 for Week use ( Mon => 0, Tue => 1, Wed => 2, Thu => @10@, Fri => 11, Sat => 14, Sun => 15 );
[4da9142]190\end{ada}
[11cced6]191The enumeration operators are the equality and relational operators, @=@, @/=@, @<@, @<=@, @=@, @/=@, @>=@, @>@, where the ordering relationship is given implicitly by the sequence of ascending enumerators.
[4da9142]192
193Ada provides an alias mechanism, \lstinline[language=ada]{renames}, for aliasing types, which is useful to shorten package identifiers.
[f936e23]194\begin{ada}
[ec20ab9]195@OtherRed@ : RGB renames Red;
[f936e23]196\end{ada}
[022bce0]197which suggests a possible \CFA extension to @typedef@.
[7bb516f]198\begin{cfa}
199typedef RGB.Red OtherRed;
200\end{cfa}
[956299b]201
[022bce0]202There are three pairs of inverse enumeration pseudo-functions (attributes): @'Pos@ and @'Val@, @'Enum_Rep@ and @'Enum_Val@, and @'Image@ and @'Value@,
203\begin{cquote}
204\setlength{\tabcolsep}{15pt}
205\begin{tabular}{@{}ll@{}}
[38f5006]206\begin{ada}
[022bce0]207RGB'Pos( Red ) = 0;
208RGB'Enum_Rep( Red ) = 10;
209RGB'Image( Red ) = "RED";
[38f5006]210\end{ada}
[022bce0]211&
[38f5006]212\begin{ada}
[022bce0]213RGB'Val( 0 ) = Red
214RGB'Enum_Val( 10 ) = Red
215RGB'Value( "Red" ) = Red
[38f5006]216\end{ada}
[022bce0]217\end{tabular}
218\end{cquote}
219These attributes are important for IO.
220An 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.
[956299b]221
[022bce0]222Ada allows the enumerator label to be a character constant.
[f936e23]223\begin{ada}
[022bce0]224type Operator is ( '+', '-', '*', '/' );
[f936e23]225\end{ada}
[022bce0]226which is syntactic sugar for the label and not character literals from the predefined type @Character@.
[4da9142]227The purpose is strictly readability using character literals rather than identifiers.
[f936e23]228\begin{ada}
[1d5e5601]229Op : Operator := '+';
230if Op = '+' or else Op = '-' then ... ;
231elsif Op = '*' or else Op = '/' then ... ; end if;
[f936e23]232\end{ada}
[1d5e5601]233Interestingly, arrays of character enumerators can be treated as strings.
[022bce0]234\begin{ada}
235Ops : array( 0..3 ) of Operator;
236Ops := @"+-*/"@; -- string assignment to array elements
[f6321173]237Ops := "+-" @&@ "*/"; -- string concatenation and assignment
[022bce0]238\end{ada}
239Ada's @Character@ type is defined as a character enumeration across all Latin-1 characters.
[956299b]240
[1d5e5601]241Ada's boolean type is also a special enumeration, which can be used in conditions.
[f936e23]242\begin{ada}
[38f5006]243type Boolean is (False, True); -- False / True not keywords
244@Flag@ : Boolean;
[022bce0]245if @Flag@ then ... -- conditional
[f936e23]246\end{ada}
[c1c0efdb]247Since only types derived from @Boolean@ can be conditional, @Boolean@ is essentially a builtin type.
[956299b]248
[c1c0efdb]249Ada provides \emph{consecutive} subsetting of an enumeration using \lstinline[language=ada]{range}.
[f936e23]250\begin{ada}
[022bce0]251type Week is ( Mon, Tue, Wed, Thu, Fri, Sat, Sun );
252subtype Weekday is Week @range Mon .. Fri@;
253subtype Weekend is Week @range Sat .. Sun@;
254Day : Week;
[f936e23]255\end{ada}
[38f5006]256Hence, the ordering of the enumerators is crucial to provide the necessary ranges.
[956299b]257
[ec20ab9]258An enumeration type can be used in the Ada \lstinline[language=ada]{case} (all enumerators must appear or a @default@) or iterating constructs.
[022bce0]259\begin{cquote}
260\setlength{\tabcolsep}{15pt}
261\begin{tabular}{@{}ll@{}}
[7bb516f]262\begin{ada}
[022bce0]263case Day is
264 when @Mon .. Fri@ => ... ;
265 when @Sat .. Sun@ => ... ;
266end case;
[7bb516f]267\end{ada}
[022bce0]268&
[f936e23]269\begin{ada}
[022bce0]270case Day is
271 when @Weekday@ => ... ; -- subtype ranges
272 when @Weekend@ => ... ;
[956299b]273end case;
[f936e23]274\end{ada}
[022bce0]275\end{tabular}
276\end{cquote}
277
278\begin{cquote}
279\setlength{\tabcolsep}{12pt}
280\begin{tabular}{@{}lll@{}}
281\begin{ada}
282for Day in @Mon .. Sun@ loop
283 ...
284end loop;
285\end{ada}
286&
287\begin{ada}
288for Day in @Weekday@ loop
289 ...
290end loop;
291\end{ada}
292&
[f936e23]293\begin{ada}
[022bce0]294for Day in @Weekend@ loop
295 ...
296end loop;
[f936e23]297\end{ada}
[022bce0]298\end{tabular}
299\end{cquote}
300
301An enumeration type can be used as an array dimension and subscript.
[f936e23]302\begin{ada}
[022bce0]303Lunch : array( @Week@ ) of Time;
304for Day in Week loop
305 Lunch( @Day@ ) := ... ; -- set lunch time
306end loop;
[f936e23]307\end{ada}
[956299b]308
[f936e23]309
310\section{\CC}
311\label{s:C++RelatedWork}
312
[11cced6]313\CC enumeration is largely backward compatible with C, so it inherited C's enumerations with some modifications and additions.
[f6321173]314
315\CC has aliasing using @const@ declarations, like C \see{\VRef{s:Cconst}}, with type inferencing, plus static/dynamic initialization.
[d69f7114]316(Note, a \CC @constexpr@ declaration is the same as @const@ with the restriction that the initialization is a compile-time expression.)
[7d9a805b]317\begin{c++}
[f6321173]318const @auto@ one = 0 + 1; $\C{// static initialization}$
319const @auto@ NIL = nullptr;
320const @auto@ PI = 3.14159;
321const @auto@ Plus = '+';
322const @auto@ Fred = "Fred";
323const @auto@ Mon = 0, Tue = Mon + 1, Wed = Tue + 1, Thu = Wed + 1, Fri = Thu + 1,
[7d9a805b]324 Sat = Fri + 1, Sun = Sat + 1;
[f6321173]325void foo() {
326 const @auto@ r = random(); $\C{// dynamic initialization}$
327 int va[r]; $\C{// VLA, auto scope only}$
328}
[7d9a805b]329\end{c++}
330Statically initialized identifiers may appear in any constant-expression context, \eg @case@.
[f6321173]331Dynamically initialized identifiers may appear as array dimensions in @g++@, which allows variable-sized arrays.
332Interestingly, global \CC @const@ declarations are implicitly marked @static@ (@r@, read-only local, rather than @R@, read-only external)
[7d9a805b]333\begin{c++}
334$\$$ nm test.o
3350000000000000018 @r@ Mon
336\end{c++}
[f6321173]337whereas C @const@ declarations without @static@ are marked @R@.
[dcfcf368]338This difference results from linking concerns that come from templates.
[7d9a805b]339
[508cff0]340The following \CC non-backward compatible change is made, plus the safe-assignment change shown in~\VRef{s:TypeSafety}.
341\begin{cquote}
342\begin{description}[leftmargin=*,topsep=0pt,itemsep=0pt,parsep=0pt]
[c1c0efdb]343\item[Change:] In \CC, the type of an enumerator is its enumeration.
344In C, the type of an enumerator is @int@.
[f936e23]345Example:
346\begin{c++}
347enum e { A };
348sizeof(A) == sizeof(int) $\C{// in C}$
[c1c0efdb]349sizeof(A) == sizeof(e) $\C{// in \CC}$
[f936e23]350/* and sizeof(int) is not necessary equal to sizeof(e) */
351\end{c++}
[c1c0efdb]352\item[Rationale:] In \CC, an enumeration is a distinct type.
353\item[Effect on original feature:] Change to semantics of well-defined feature.
354\item[Difficulty of converting:] Semantic transformation.
355\item[How widely used:] Seldom. The only time this affects existing C code is when the size of an enumerator is taken.
[f936e23]356Taking the size of an enumerator is not a common C coding practice.
[c1c0efdb]357\end{description}
[508cff0]358\hfill ISO/IEC 14882:1998 (\CC Programming Language Standard)~\cite[C.1.5.7.2.6]{ANSI98:C++}
359\end{cquote}
[f936e23]360Hence, the values in a \CC enumeration can only be its enumerators (without a cast).
[c1c0efdb]361
[f936e23]362While the storage size of an enumerator is up to the compiler, there is still an implicit cast to @int@.
363\begin{c++}
364enum E { A, B, C };
365E e = A;
[282061a]366int i = A; i = e; $\C{// implicit casts to int}$
[f936e23]367\end{c++}
[ec20ab9]368\CC{11} added a scoped enumeration, \lstinline[language=c++]{enum class} (or \lstinline[language=c++]{enum struct})\footnote{
[29c8675]369The use of keyword \lstinline[language=c++]{class} is reasonable because default visibility is \lstinline[language=c++]{private} (scoped).
[ec20ab9]370However, default visibility for \lstinline[language=c++]{struct} is \lstinline[language=c++]{public} (unscoped) making it an odd choice.},
371where the enumerators are accessed using type qualification.
[f936e23]372\begin{c++}
373enum class E { A, B, C };
374E e = @E::@A; $\C{// qualified enumerator}$
[1d5e5601]375e = B; $\C{// error: B not in scope}$
[f936e23]376\end{c++}
[022bce0]377\CC{20} supports explicit unscoping with a \lstinline[language=c++]{using enum} declaration.
[f936e23]378\begin{c++}
379enum class E { A, B, C };
380@using enum E;@
[282061a]381E e = A; e = B; $\C{// direct access}$
[f936e23]382\end{c++}
[29c8675]383\CC{11} added the ability to explicitly declare an underlying \emph{integral} type for \lstinline[language=c++]{enum class}.
[f936e23]384\begin{c++}
385enum class RGB @: long@ { Red, Green, Blue };
386enum class rgb @: char@ { Red = 'r', Green = 'g', Blue = 'b' };
387enum class srgb @: signed char@ { Red = -1, Green = 0, Blue = 1 };
388\end{c++}
[1d5e5601]389There is no implicit conversion from the \lstinline[language=c++]{enum class} type to its declared type.
[f936e23]390\begin{c++}
391rgb crgb = rgb::Red;
[1d5e5601]392char ch = rgb::Red; ch = crgb; $\C{// error}$
[f936e23]393\end{c++}
[ec20ab9]394An enumeration can be used in the @if@ and @switch@ statements.
395\begin{cquote}
396\setlength{\tabcolsep}{15pt}
397\begin{tabular}{@{}ll@{}}
398\begin{c++}
399if ( @day@ <= Fri )
400 cout << "weekday" << endl;
401
402
403
404
405\end{c++}
406&
407\begin{c++}
408switch ( @day@ ) {
409 case Mon: case Tue: case Wed: case Thu: case Fri:
410 cout << "weekday" << endl; break;
411 case Sat: case Sun:
412 cout << "weekend" << endl; break;
413}
414\end{c++}
415\end{tabular}
416\end{cquote}
[29c8675]417However, there is no mechanism to iterate through an enumeration.
418A common workaround is to iterate over enumerator as integral values, but it only works if
419enumerators resemble a sequence of natural, i.e., enumerators are auto-initialized.
[dcfcf368]420Otherwise, the iteration would have integers that are not enumeration values.
[ec20ab9]421\begin{c++}
422enum Week { Mon, Tue, Wed, Thu = 10, Fri, Sat, Sun };
423for ( Week d = Mon; d <= Sun; d = @(Week)(d + 1)@ ) cout << d << ' ';
4240 1 2 @3 4 5 6 7 8 9@ 10 11 12 13
425\end{c++}
[c1c0efdb]426As a consequence, there is no meaningful enumerating mechanism.
[a8f44c83]427
[ec20ab9]428An enumeration type cannot declare an array dimension but an enumerator can be used as a subscript.
[c1c0efdb]429There is no mechanism to subset or inherit from an enumeration.
[f936e23]430
431
[9d3a4cc]432\section{C\texorpdfstring{\raisebox{-0.7ex}{\LARGE$^\sharp$}\xspace}{Csharp}} % latex bug: cannot use \relsize{2} so use \LARGE
[924534e]433\label{s:Csharp}
[7bb516f]434
435% https://www.tutorialsteacher.com/codeeditor?cid=cs-mk8Ojx
[ec20ab9]436% https://learn.microsoft.com/en-us/dotnet/api/system.enum?view=net-8.0
437% https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/enums
[7bb516f]438
[29c8675]439\Csharp is a programming language with a scoped, integral enumeration similar to \CC \lstinline[language=C++]{enum class}.
[7bb516f]440\begin{csharp}
[a8f44c83]441enum Week : @long@ { Mon, Tue, Wed, Thu@ = 10@, Fri, Sat, Sun }
[ec20ab9]442enum RGB { Red, Green, Blue }
[7bb516f]443\end{csharp}
[c1c0efdb]444The default underlying integral type is @int@, with auto-incrementing and implicit/explicit initialization.
[ec20ab9]445A method cannot be defined in an enumeration type (extension methods are possible).
446There is an explicit bidirectional conversion between an enumeration and its integral type, and an implicit conversion to the enumerator label in display contexts.
[7bb516f]447\begin{csharp}
[ec20ab9]448int iday = (int)Week.Fri; $\C{// day == 11}$
449Week day = @(Week)@42; $\C{// day == 42, unsafe}$
450string mon = Week.Mon.ToString(); $\C{// mon == "Mon"}$
451RGB rgb = RGB.Red; $\C{// rgb == "Red"}$
452day = @(Week)@rgb; $\C{// day == "Mon", unsafe}$
453Console.WriteLine( Week.Fri ); $\C{// print label Fri}$
[7bb516f]454\end{csharp}
[a8f44c83]455% The majority of the integral operators (relational and arithmetic) work with enumerations, except @*@ and @/@.
456% Relational and arithmetic operators are defined in terms of its numeric value only.
457% Therefore, enumerators are not ordered and not enumerable like \CC.
[11cced6]458Like \CC, \Csharp defines enumeration relational and arithmetic operators in terms of value.
459Enumerators have no defined positional meaning.
[7bb516f]460\begin{csharp}
[c1c0efdb]461day = day++ - 5; $\C{// value manipulation}$
[ec20ab9]462day = day & day;
[7bb516f]463\end{csharp}
[a8f44c83]464\begin{csharp}
465for ( Week d = Mon; d <= Sun; @d += 1@ ) {
466 Console.Write( d + " " );
467}
468Mon Tue Wed @3 4 5 6 7 8 9@ Thu Fri Sat Sun
469\end{csharp}
[c1c0efdb]470As a consequence, there is no direct meaningful enumerating mechanism.
[a8f44c83]471
[ec20ab9]472An enumeration can be used in the @if@ and @switch@ statements.
473\begin{cquote}
474\setlength{\tabcolsep}{15pt}
475\begin{tabular}{@{}ll@{}}
[7bb516f]476\begin{csharp}
[ec20ab9]477if ( @day@ <= Week.Fri )
478 Console.WriteLine( "weekday" );
[7bb516f]479
[924534e]480
481
482
483
484\end{csharp}
485&
[7bb516f]486\begin{csharp}
[ec20ab9]487switch ( @day@ ) {
488 case Week.Mon: case Week.Tue: case Week.Wed:
489 case Week.Thu: case Week.Fri:
490 Console.WriteLine( "weekday" ); break;
491 case Week.Sat: case Week.Sun:
492 Console.WriteLine( "weekend" ); break;
[7bb516f]493}
494\end{csharp}
[924534e]495\end{tabular}
[ec20ab9]496\end{cquote}
[a8f44c83]497
[29c8675]498To indirectly enumerate, \Csharp's Enum library provides @Enum.GetValues@,
499% a pseudo-method that retrieves an array of the enumeration constants for looping over an enumeration type or variable (expensive operation).
[dcfcf368]500a static member of abstract Enum type that return a reference to an array of all enumeration constants.
501Internally, a Enum type has a static member called @fieldInfoHash@ -- a @Hashtable@ that stores enumerators information.
502The field is populated on-demand: it only contains information if a @reflection@ like @GetValues@ is called.
503As an optimization, this information is cached, so the cost of reflection is paid once throughout the lifetime of a program.
504@GetValues@ then converts a @Hashtable@ to an @Array@, which supports enumerating.
[ec20ab9]505\begin{csharp}
506foreach ( Week d in @Enum.GetValues@( typeof(Week) ) ) {
507 Console.WriteLine( d + " " + (int)d + " " ); // label, position
508}
509Mon 0, Tue 1, Wed 2, Thu 10, Fri 11, Sat 12, Sun 13,
510\end{csharp}
[dcfcf368]511Hence, enumerating is not supplied directly by the enumeration, but indirectly through the expensive $O(N)$ creation of an enumerable array type, and recreating this array for each enumerating, versus direct arithmetic.
[ec20ab9]512
513An enumeration type cannot declare an array dimension but an enumerator can be used as a subscript.
[c1c0efdb]514There is no mechanism to subset or inherit from an enumeration.
[ec20ab9]515
516The @Flags@ attribute creates a bit-flags enumeration, making bitwise operators @&@, @|@, @~@ (complement), @^@ (xor) sensible.
517\begin{csharp}
518@[Flags]@ public enum Week {
519 None = 0x0, Mon = 0x1, Tue = 0x2, Wed = 0x4,
520 Thu = 0x8, Fri = 0x10, Sat = 0x20, Sun = 0x40,
521 Weekdays = @Mon | Tue | Wed | Thu | Fri@ $\C{// Weekdays == 0x1f}$
522 Weekend = @Sat | Sun@, $\C{// Weekend == 0x60}$
523}
524Week meetings = @Week.Mon | Week.Wed@; $\C{// 0x5}$
525\end{csharp}
[7bb516f]526
527
[c1c0efdb]528\section{Go}
529\label{s:Go}
[f936e23]530
[29c8675]531Go has @const@ aliasing declarations, similar to \CC \see{\VRef{s:C++RelatedWork}}, for basic types with type inferencing and static initialization (constant expression).
532The most basic form of constant definition is a @const@ keyword, followed by the name of constant, an optional type declaration of the constant, and a mandatory initialize.
[dcfcf368]533For example:
[f936e23]534\begin{Go}
[ec20ab9]535const R @int@ = 0; const G @uint@ = 1; const B = 2; $\C{// explicit typing and type inferencing}$
536const Fred = "Fred"; const Mary = "Mary"; const Jane = "Jane";
537const S = 0; const T = 0;
538const USA = "USA"; const U = "USA";
539const V = 3.1; const W = 3.1;
540\end{Go}
[29c8675]541Since these declarations are immutable variables, they are unscoped and Go has no overloading. If no type declaration provided, Go infers
542type from the initializer expression.
[ec20ab9]543
[29c8675]544% Go provides an enumeration-like feature to group together @const@ declaration into a block and introduces a form of auto-initialization.
[dcfcf368]545These named constants can be grouped together in one @const@ declaration block to introduce a form of auto-initialization.
[ec20ab9]546\begin{Go}
547const ( R = 0; G; B ) $\C{// implicit initialization: 0 0 0}$
548const ( Fred = "Fred"; Mary = "Mary"; Jane = "Jane" ) $\C{// explicit initialization: Fred Mary Jane}$
[29c8675]549const ( S = 0; T; USA = "USA"; U; V = 3.1; W ) $\C{// implicit/explicit: 0 0 USA USA 3.1 3.1}$
[38f5006]550\end{Go}
[ec20ab9]551The first identifier \emph{must} be explicitly initialized;
552subsequent identifiers can be implicitly or explicitly initialized.
[29c8675]553Implicit initialization always uses the \emph{previous} (predecessor) constant expression initializer.
[dcfcf368]554A constant block can still use explicit declarations, and following constants inherit that type.
[ec20ab9]555\begin{Go}
[dcfcf368]556type BigInt int64
557const ( R @BigInt@ = 0; G; B )
558const ( Fred @string@ = "Fred"; Mary = "Mary"; Jane = "Jane" )
559const ( S @int@ = 0; T; USA @string@ = "USA"; U; V @float32@ = 3.1; W )
[ec20ab9]560\end{Go}
[dcfcf368]561Typing the first constant and implicit initializing is still not a enumeration because there is no unique type for the constant block;
562nothing stops other constant blocks from having the same type.
563
564Each @const@ declaration provides an implicit \emph{compile-time} integer counter starting at @0@, called \lstinline[language=Go]{iota}, which is post-incremented after each constant declaration.
565% Each @const@ declaration is often paired with a const expression \lstinline[language=Go]{iota} to re-define its implicit initialization.
566% \lstinline[language=Go]{iota} represents a sequence of natural numbers starting from zero.
567% Using \lstinline[language=Go]{iota} outside of a @const@ block always sets the identifier to zero.
568% \begin{Go}
569% const R = iota; $\C{// 0}$
570% \end{Go}
[29c8675]571% Inside a @const@ block, \lstinline[language=Go]{iota} is implicitly incremented for each \lstinline[language=golang]{const} identifier and used to initialize the next uninitialized identifier.
[dcfcf368]572% Inside a @const@ block, if a constant has \lstinline[language=Go]{iota} initializer, its successor will also use \lstinline[language=Go]{iota} initializer.
573% Inside a @const@ block, if a constant has \lstinline[language=Go]{iota} initializer, its successor will also use \lstinline[language=Go]{iota} initializer.
574% \lstinline[language=Go]{iota} is no different than other constant expression when it is used in implicit initialization, but thanks to the increment natural of \lstinline[language=Go]{iota}, the successor will have a value equal to its predecessor plus 1.
[38f5006]575\begin{Go}
[dcfcf368]576const ( R = @iota@; G; B ) $\C{// implicit: 0 1 2}$
577const ( C = @iota + B + 1@; G; Y ) $\C{// implicit: 3 4 5}$
[29c8675]578\end{Go}
[dcfcf368]579which are equivalent to:
[29c8675]580\begin{Go}
[dcfcf368]581const ( R = @iota@; G = @iota@; B = @iota@ ) $\C{// implicit: 0 1 2}$
582const ( C = @iota + B + 1@; G = @iota + B + 1@; Y = @iota + B + 1@ ) $\C{// implicit: 3 4 5}$
[f936e23]583\end{Go}
[dcfcf368]584An underscore \lstinline[language=golang]{const} identifier advances \lstinline[language=Go]{iota}.
[f936e23]585\begin{Go}
[dcfcf368]586const ( O1 = iota + 1; @_@; O3; @_@; O5 ) $\C{// 1, 3, 5}$
[f936e23]587\end{Go}
[dcfcf368]588Auto-initialization reverts from \lstinline[language=Go]{iota} to the previous value after an explicit initialization, but auto-incrementing of \lstinline[language=Go]{iota} continues.
[f936e23]589\begin{Go}
[dcfcf368]590const ( Mon = iota; Tue; Wed; $\C{// 0, 1, 2}$
591 @Thu = 10@; Fri; Sat; @Sun = iota@ ) $\C{// 10, 10, 10, {\color{red}6}}$
[f936e23]592\end{Go}
[dcfcf368]593Auto-initialization from \lstinline[language=Go]{iota} is restarted and \lstinline[language=Go]{iota} reinitialized with an expression containing at most \emph{one} \lstinline[language=Go]{iota}.
[f936e23]594\begin{Go}
[dcfcf368]595const ( V1 = iota; V2; @V3 = 7;@ V4 = @iota@ + 1; V5 ) // 0 1 7 4 5
596const ( Mon = iota; Tue; Wed; // 0, 1, 2
597 @Thu = 10;@ Fri = @iota@ - Wed + Thu - 1; Sat; Sun ) // 10, 11, 12, 13
[f936e23]598\end{Go}
[dcfcf368]599Here, @V4@ and @Fri@ restart auto-incrementing from \lstinline[language=Go]{iota} and reset \lstinline[language=Go]{iota} to 4 and 11, respectively, because of the initialization expressions containing \lstinline[language=Go]{iota}.
600Note, because \lstinline[language=Go]{iota} is incremented for an explicitly initialized identifier or @_@,
601at @Fri@ \lstinline[language=Go]{iota} is 4 requiring the minus one to compute the value for @Fri@.
[7bb516f]602
[924534e]603Basic switch and looping are possible.
604\begin{cquote}
[ec20ab9]605\setlength{\tabcolsep}{20pt}
[924534e]606\begin{tabular}{@{}ll@{}}
607\begin{Go}
[ec20ab9]608day := Mon; // := $\(\Rightarrow\)$ type inferencing
609switch @day@ {
[924534e]610 case Mon, Tue, Wed, Thu, Fri:
611 fmt.Println( "weekday" );
612 case Sat, Sun:
613 fmt.Println( "weekend" );
[7bb516f]614}
[924534e]615\end{Go}
616&
617\begin{Go}
[7bb516f]618
[ec20ab9]619for i := @Mon@; i <= @Sun@; i += 1 {
[1d5e5601]620 fmt.Println( i )
[7bb516f]621}
622
623
624
[924534e]625\end{Go}
626\end{tabular}
627\end{cquote}
[29c8675]628However, the loop in this example prints the values from 0 to 13 because there is no actual enumeration.
[7bb516f]629
[ec20ab9]630A constant variable can be used as an array dimension or a subscript.
631\begin{Go}
632var ar[@Sun@] int
633ar[@Mon@] = 3
634\end{Go}
635
[7bb516f]636
[924534e]637\section{Java}
[7bb516f]638
[ec20ab9]639Java provides an enumeration using a specialized class.
640A basic Java enumeration is an opaque enumeration, where the enumerators are constants.
[7bb516f]641\begin{Java}
[c1c0efdb]642enum Week { Mon, Tue, Wed, Thu, Fri, Sat, Sun; }
[ec20ab9]643Week day = Week.Sat;
[7bb516f]644\end{Java}
[dcfcf368]645The enumerator's members are scoped requiring qualification.
[ec20ab9]646The value of an enumeration instance is restricted to its enumerators.
647
[c1c0efdb]648The position (ordinal) and label (name) are accessible but there is no value property.
[7bb516f]649\begin{Java}
[ec20ab9]650System.out.println( day.!ordinal()! + " " + !day! + " " + day.!name()! );
6515 Sat Sat
[7bb516f]652\end{Java}
[ec20ab9]653Since @day@ has no value, it prints its label (name).
[c1c0efdb]654The member @valueOf@ is the inverse of @name@ converting a string to an enumerator.
[7bb516f]655\begin{Java}
[ec20ab9]656day = Week.valueOf( "Wed" );
[7bb516f]657\end{Java}
[ec20ab9]658Extra members can be added to provide specialized operations.
[7bb516f]659\begin{Java}
[ec20ab9]660public boolean isWeekday() { return !ordinal()! <= Fri.ordinal(); }
[c033405]661public boolean isWeekend() { return Sat.ordinal() <= !ordinal()!; }
[7bb516f]662\end{Java}
[ec20ab9]663Notice the unqualified calls to @ordinal@ in the members implying a \lstinline[language=Java]{this} to some implicit implementation variable, likely an @int@.
[7bb516f]664
[ec20ab9]665Enumerator values require an enumeration type (any Java type may be used) and implementation member.
[1d5e5601]666\begin{Java}
[ec20ab9]667enum Week {
[1d5e5601]668 Mon!(1)!, Tue!(2)!, Wed!(3)!, Thu!(4)!, Fri!(5)!, Sat!(6)!, Sun!(7)!; // must appear first
[ec20ab9]669 private !long! day; $\C{// enumeration type and implementation member}$
670 private Week( !long! d ) { day = d; } $\C{// enumerator initialization}$
[1d5e5601]671};
[ec20ab9]672Week day = Week.Sat;
[1d5e5601]673\end{Java}
674The position, value, and label are accessible.
675\begin{Java}
[ec20ab9]676System.out.println( !day.ordinal()! + " " + !day.day! + " " + !day.name()! );
6775 6 Sat
[1d5e5601]678\end{Java}
[ec20ab9]679If the implementation member is \lstinline[language=Java]{public}, the enumeration is unsafe, as any value of the underlying type can be assigned to it, \eg @day = 42@.
680The implementation constructor must be private since it is only used internally to initialize the enumerators.
[29c8675]681Initialization occurs at the enumeration-type declaration.
[1d5e5601]682
[ec20ab9]683Enumerations can be used in the @if@ and @switch@ statements but only for equality tests.
684\begin{cquote}
685\setlength{\tabcolsep}{15pt}
686\begin{tabular}{@{}ll@{}}
[7bb516f]687\begin{Java}
[ec20ab9]688if ( !day! == Week.Fri )
689 System.out.println( "Fri" );
690
691
692
693
694\end{Java}
695&
696\begin{Java}
697switch ( !day! ) {
[924534e]698 case Mon: case Tue: case Wed: case Thu: case Fri:
[ec20ab9]699 System.out.println( "weekday" ); break;
[924534e]700 case Sat: case Sun:
[ec20ab9]701 System.out.println( "weekend" ); break;
[7bb516f]702}
703\end{Java}
[ec20ab9]704\end{tabular}
705\end{cquote}
706Notice enumerators in the @switch@ statement do not require qualification.
707
[11cced6]708There are no arithmetic operations on enumerations, so there is no arithmetic way to iterate through an enumeration without making the implementation type \lstinline[language=Java]{public}.
[dcfcf368]709Like \Csharp, enumerating is supplied indirectly through another enumerable type, not via the enumeration.
710Specifically, Java supplies a static method @values@, which returns an array of enumerator values.
711Unfortunately, @values@ is an expensive @O(n)@ operation, which is recreated each time it is called.
[7bb516f]712\begin{Java}
[ec20ab9]713for ( Week d : Week.values() ) {
714 System.out.print( d.ordinal() + d.day + " " + d.name() + ", " );
[7bb516f]715}
[1d5e5601]7160 1 Mon, 1 2 Tue, 2 3 Wed, 3 4 Thu, 4 5 Fri, 5 6 Sat, 6 7 Sun,
[7bb516f]717\end{Java}
718
[29c8675]719% Java provides an @EnumSet@ where the underlying type is an efficient set of bits, one per enumeration \see{\Csharp \lstinline{Flags}, \VRef{s:Csharp}}, providing (logical) operations on groups of enumerators.
720% There is also a specialized version of @HashMap@ with enumerator keys, which has performance benefits.
[dcfcf368]721Java provides @EnumSet@, an auxiliary data structure that takes an enum @class@ as parameter (Week.class) for its construction, and it contains members only with the supplied enum type.
722@EnumSet@ is enumerable because it extends @AbstractSet@ interfaces and thus supports direct enumerating via @forEach@.
723It also has subset operation @range@ and it is possible to add to and remove from members of the set.
[29c8675]724@EnumSet@ supports more enumeration features, but it is not an enumeration type: it is a set of enumerators from a pre-define enum.
[f936e23]725
[29c8675]726An enumeration type cannot declare an array dimension nor can an enumerator be used as a subscript.
727Enumeration inheritence is disallowed because an enumeration is \lstinline[language=Java]{final}.
[1d5e5601]728
[dcfcf368]729
[f936e23]730\section{Rust}
[ec20ab9]731
[4da9142]732% https://doc.rust-lang.org/reference/items/enumerations.html
[1d5e5601]733
[c033405]734Rust @enum@ provides two largely independent mechanisms from a single language feature: an ADT and an enumeration.
[ec20ab9]735When @enum@ is an ADT, pattern matching is used to discriminate among the variant types.
736\begin{cquote}
[c033405]737\begin{tabular}{@{}l@{\hspace{30pt}}ll@{}}
[1d5e5601]738\begin{rust}
[ec20ab9]739struct S {
740 i : isize, j : isize
741}
[c033405]742let mut s = S{ i : 3, j : 4 };
[ec20ab9]743enum @ADT@ {
[c033405]744 I( isize ), $\C[1in]{// int}$
745 F( f64 ), $\C{// float}$
746 S( S ), $\C{// struct}\CRT$
[ec20ab9]747}
[1d5e5601]748\end{rust}
[ec20ab9]749&
[1d5e5601]750\begin{rust}
[ec20ab9]751let mut adt : ADT;
[c033405]752adt = ADT::I(3); println!( "{:?}", adt );
753adt = ADT::F(3.5); println!( "{:?}", adt );
754adt = ADT::S(s); println!( "{:?}", adt );
[ec20ab9]755@match@ adt {
[29c8675]756 ADT::I( i ) $=>$ println!( "{:}", i ),
757 ADT::F( f ) $=>$ println!( "{:}", f ),
758 ADT::S( s ) $=>$ println!( "{:} {:}", s.i, s.j ),
[ec20ab9]759}
[c033405]760\end{rust}
761&
762\begin{rust}
763I(3)
764F(3.5)
765S(S { i: 3, j: 4 })
7663 4
767
768
769
770
771
[1d5e5601]772\end{rust}
[ec20ab9]773\end{tabular}
774\end{cquote}
[c033405]775Even when the variant types are the unit type, the ADT is still not an enumeration because there is no enumerating \see{\VRef{s:AlgebraicDataType}}.
[1d5e5601]776\begin{rust}
[ec20ab9]777enum Week { Mon, Tues, Wed, Thu, Fri, Sat, Sun@,@ } // terminating comma
778let mut week : Week = Week::Mon;
779match week {
[29c8675]780 Week::Mon $=>$ println!( "Mon" ),
[ec20ab9]781 ...
[29c8675]782 Week::Sun $=>$ println!( "Sun" ),
[1d5e5601]783}
784\end{rust}
785
[ec20ab9]786However, Rust allows direct setting of the ADT constructor, which means it is actually a tag.
[41fb996]787\begin{cquote}
[c033405]788\setlength{\tabcolsep}{15pt}
[ec20ab9]789\begin{tabular}{@{}ll@{}}
[1d5e5601]790\begin{rust}
[ec20ab9]791enum Week {
792 Mon, Tues, Wed, // start 0
793 Thu @= 10@, Fri,
794 Sat, Sun,
795}
796
797\end{rust}
798&
799\begin{rust}
800#[repr(u8)]
801enum ADT {
[a8f44c83]802 I(isize) @= 5@,
[ec20ab9]803 F(f64) @= 10@,
804 S(S) @= 0@,
805}
[1d5e5601]806\end{rust}
[ec20ab9]807\end{tabular}
808\end{cquote}
809Through this integral tag, it is possible to enumerate, and when all tags represent the unit type, it behaves like \CC \lstinline[language=C++]{enum class}.
810When tags represent non-unit types, Rust largely precludes accessing the tag because the semantics become meaningless.
[11cced6]811Hence, the two mechanisms are largely disjoint, and only the enumeration component is discussed.
[ec20ab9]812
[11cced6]813In detail, the @enum@ type has an implicit integer tag (discriminant) with a unique value for each variant type.
814Direct initialization is achieved by a compile-time expression that generates a constant value.
[ec20ab9]815Indirect initialization (without initialization, @Fri@/@Sun@) is auto-initialized: from left to right, starting at zero or the next explicitly initialized constant, incrementing by @1@.
816There is an explicit cast from the tag to integer.
[1d5e5601]817\begin{rust}
[ec20ab9]818let mut mon : isize = Week::Mon as isize;
[1d5e5601]819\end{rust}
[ec20ab9]820An enumeration can be used in the @if@ and \lstinline[language=rust]{match} (@switch@) statements.
821\begin{cquote}
822\setlength{\tabcolsep}{8pt}
823\begin{tabular}{@{}ll@{}}
824\begin{c++}
825if @week as isize@ == Week::Mon as isize {
826 println!( "{:?}", week );
827}
828
829
830\end{c++}
831&
832\begin{c++}
833match @week@ {
834 Week::Mon | Week:: Tue | Week::Wed | Week::Thu
835 | Week::Fri => println!( "weekday" ),
[29c8675]836 Week::Sat | Week:: Sun $=>$ println!( "weekend" ),
[ec20ab9]837}
838\end{c++}
839\end{tabular}
840\end{cquote}
[29c8675]841% However, there is no mechanism to iterate through an enumeration without casting to integral and positions versus values is not handled.
[dcfcf368]842Like C/\CC, there is no mechanism to iterate through an enumeration.
843It can only be approximated by a loop over a range of enumerator and only works if the enumerator values are a sequence of natural numbers.
[ec20ab9]844\begin{c++}
845for d in Week::Mon as isize ..= Week::Sun as isize {
846 print!( "{:?} ", d );
847}
8480 1 2 @3 4 5 6 7 8 9@ 10 11 12 13
849\end{c++}
[29c8675]850% An enumeration type cannot declare an array dimension nor as a subscript.
[dcfcf368]851There is no direct way to harmonize an enumeration and another data structure.
852For example, there is no mapping from an enumerated type to an array type.
[29c8675]853In terms of extensibility, there is no mechanism to subset or inherit from an enumeration.
[f936e23]854
855
856\section{Swift}
[29c8675]857\label{s:Swift}
[1d5e5601]858% https://www.programiz.com/swift/online-compiler
[dcfcf368]859Despite being named as enumeration, a Swift @enum@ is in fact a ADT: cases (enumerators) of an @enum@ can have heterogeneous types and be recursive.
[29c8675]860% Like Rust, Swift @enum@ provides two largely independent mechanisms from a single language feature: an ADT and an enumeration.
[c033405]861When @enum@ is an ADT, pattern matching is used to discriminate among the variant types.
862\begin{cquote}
863\setlength{\tabcolsep}{20pt}
864\begin{tabular}{@{}l@{\hspace{55pt}}ll@{}}
[f936e23]865\begin{swift}
[c033405]866struct S {
867 var i : Int, j : Int
[956299b]868}
[c033405]869var s = S( i : 3, j : 5 )
870@enum@ ADT {
871 case I(Int) $\C[1.125in]{// int}$
872 case F(Float) $\C{// float}$
873 case S(S) $\C{// struct}\CRT$
[956299b]874}
[f936e23]875\end{swift}
[c033405]876&
[f936e23]877\begin{swift}
[c033405]878var adt : ADT
879adt = .I( 3 ); print( adt )
880adt = .F( 3.5 ); print( adt )
881adt = .S( s ); print( adt )
882@switch@ adt { // pattern matching
883 case .I(let i): print( i )
884 case .F(let f): print( f )
885 case .S(let s): print( s.i, s.j )
[956299b]886}
[f936e23]887\end{swift}
[c033405]888&
[f936e23]889\begin{swift}
[c033405]890I(3)
891F(3.5)
892S(S(i: 3, j: 5))
8933 5
[956299b]894
895
896
897
898
[c033405]899\end{swift}
900\end{tabular}
901\end{cquote}
[dcfcf368]902Note, after an @adt@'s type is known, the enumerator is inferred without qualification, \eg @.I(3)@.
903% Normally an enumeration case needs a type qualification.
904%However, when pattern matching @adt@ of type @ADT@, the @case@ context provides the type @ADT@ so no explicit type qualification is required.
[956299b]905
[29c8675]906% An enumeration is created when \emph{all} the enumerators are unit-type, which is like a scoped, opaque enumeration.
[dcfcf368]907Without type declaration for enumeration cases, the enumerators have unit-type, which is like a scoped, opaque enumeration.
[f936e23]908\begin{swift}
[c1c0efdb]909enum Week { case Mon, Tue, Wed, Thu, Fri, Sat, Sun }; // unit-type
[41f4e2d]910var week : Week = @Week.Mon@;
[f936e23]911\end{swift}
[29c8675]912% As well, it is possible to type \emph{all} the enumerators with a common type, and set different values for each enumerator;
913% for integral types, there is auto-incrementing.
[dcfcf368]914As well, it is possible to type associated values of enumeration cases with a common type.
[29c8675]915When enumeration cases are typed with a common integral type, Swift auto-initialize enumeration cases following the same initialization scheme as C language.
[dcfcf368]916If an enumeration is typed with @string@, its cases are auto-initialized to case names (labels).
[c033405]917\begin{cquote}
918\setlength{\tabcolsep}{15pt}
919\begin{tabular}{@{}lll@{}}
[f936e23]920\begin{swift}
[c033405]921enum WeekInt: @Int@ {
922 case Mon, Tue, Wed, Thu = 10, Fri,
923 Sat = 4, Sun // auto-incrementing
924};
[f936e23]925\end{swift}
[c033405]926&
[f936e23]927\begin{swift}
[c033405]928enum WeekStr: @String@ {
929 case Mon = "MON", Tue, Wed, Thu, Fri,
930 Sat = "SAT", Sun
931};
[f936e23]932\end{swift}
[c033405]933\end{tabular}
934\end{cquote}
935An enumeration only supports equality comparison between enumerator values, unless it inherits from @Comparable@, adding relational operators @<@, @<=@, @>@, and @>=@.
[956299b]936
[c033405]937An enumeration can have methods.
[f936e23]938\begin{swift}
[c1c0efdb]939enum Week: @Comparable@ {
[c033405]940 case Mon, Tue, Wed, Thu, Fri, Sat, Sun // unit-type
[c1c0efdb]941 func @isWeekday() -> Bool@ { return self <= .Fri } // methods
942 func @isWeekend() -> Bool@ { return .Sat <= self }
[c033405]943};
[f936e23]944\end{swift}
[c033405]945An enumeration can be used in the @if@ and @switch@ statements, where @switch@ must be exhaustive or have a @default@.
946\begin{cquote}
947\setlength{\tabcolsep}{15pt}
948\begin{tabular}{@{}ll@{}}
[f936e23]949\begin{swift}
[c033405]950if @week <= .Fri@ {
951 print( "weekday" );
[956299b]952}
953
954
[f936e23]955\end{swift}
[c033405]956&
[f936e23]957\begin{swift}
[c033405]958switch @week@ {
959 case .Mon: print( "Mon" )
960 ...
961 case .Sun: print( "Sun" )
[956299b]962}
[f936e23]963\end{swift}
[c033405]964\end{tabular}
965\end{cquote}
[dcfcf368]966Enumerating is accomplished by inheriting from @CaseIterable@ protocol, which has a static @enum.@ @allCases@ property that returns a collection of all the cases for looping over an enumeration type or variable.
[29c8675]967Like \CFA, Swift's default enumerator output is the case name (label). An enumerator of a typed enumeration has attribute
968@rawValue@ that return its case value.
[f936e23]969\begin{swift}
[c033405]970enum Week: Comparable, @CaseIterable@ {
971 case Mon, Tue, Wed, Thu, Fri, Sat, Sun // unit-type
972};
973for day in Week@.allCases@ {
974 print( day, terminator:" " )
[956299b]975}
[c033405]976Mon Tue Wed Thu Fri Sat Sun
[f936e23]977\end{swift}
[956299b]978
[29c8675]979
[c033405]980\begin{cquote}
981\setlength{\tabcolsep}{15pt}
982\begin{tabular}{@{}lll@{}}
[f936e23]983\begin{swift}
[c033405]984enum WeekInt: @Int@, CaseIterable {
985 case Mon, Tue, Wed, Thu = 10, Fri,
986 Sat = 4, Sun // auto-incrementing
987};
988for day in WeekInt.allCases {
989 print( day@.rawValue@, terminator:" " )
[956299b]990}
[c033405]9910 1 2 10 11 4 5
[f936e23]992\end{swift}
[c033405]993&
[f936e23]994\begin{swift}
[c033405]995enum WeekStr: @String@, CaseIterable {
996 case Mon = "MON", Tue, Wed, Thu, Fri,
997 Sat = "SAT", Sun
998};
999for day in WeekStr.allCases {
1000 print( day@.rawValue@, terminator:" " )
[956299b]1001}
[c033405]1002MON Tue Wed Thu Fri SAT Sun
[f936e23]1003\end{swift}
[c033405]1004\end{tabular}
1005\end{cquote}
1006
[29c8675]1007There is a safe bidirectional conversion from typed enumerator to @rawValue@ and vice versa.
[f936e23]1008\begin{swift}
[c033405]1009if let opt = WeekInt( rawValue: 0 ) { // test optional return value
[29c8675]1010 print( opt.rawValue, opt ) // 0 Mon
[c033405]1011} else {
1012 print( "invalid weekday lookup" )
[956299b]1013}
[f936e23]1014\end{swift}
[29c8675]1015% Conversion from @rawValue@ to enumerator may fail (bad lookup), so the result is an optional value.
[dcfcf368]1016In the previous example, the initialization of @opt@ fails if there is no enumeration value equal to 0, resulting in a @nil@ value.
1017Initialization from a raw value is considered a expensive operation because it requires a value lookup.
1018
[956299b]1019
[4da9142]1020\section{Python 3.13}
1021% https://docs.python.org/3/howto/enum.html
[9262fe9]1022
[c1c0efdb]1023Python is a dynamically-typed reflexive programming language with multiple incompatible versions.
[11cced6]1024The generality of the language makes it possible to extend existing or build new language features.
[c1c0efdb]1025As a result, discussing Python enumerations is a moving target, because if a feature does not exist, it can often be created with varying levels of complexity within the language.
[c033405]1026Therefore, the following discussion is (mostly) restricted to the core enumeration features in Python 3.13.
[9262fe9]1027
[c033405]1028A Python enumeration is not a basic type;
1029it is a @class@ inheriting from the @Enum@ class.
[11cced6]1030The @Enum@ class presents a set of scoped enumerators, where each enumerator is a pair object with a \emph{constant} string name and an arbitrary value.
[c033405]1031Hence, an enumeration instance is a fixed type (enumeration pair), and its value is the type of one of the enumerator pairs.
[9262fe9]1032
[c033405]1033The enumerator value fields must be explicitly initialized and be \emph{unique}.
[9262fe9]1034\begin{python}
[c033405]1035class Week(!Enum!): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
[9262fe9]1036\end{python}
[29c8675]1037and/or explicitly auto-initialized with @auto@ method, \eg:
[9262fe9]1038\begin{python}
[c033405]1039class Week(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = 10; Fri = !auto()!; Sat = 4; Sun = !auto()!
1040Mon : 1 Tue : 2 Wed : 3 Thu : 10 Fri : !11! Sat : 4 Sun : !12!
[9262fe9]1041\end{python}
[29c8675]1042@auto@ is controlled by member @_generate_next_value_()@, which by default return one plus the highest value among enumerators, and can be overridden:
[9262fe9]1043\begin{python}
[c033405]1044@staticmethod
1045def _generate_next_value_( name, start, count, last_values ):
1046 return name
[9262fe9]1047\end{python}
1048
[11cced6]1049There is no direct concept of restricting the enumerators in an enumeration \emph{instance} because dynamic typing changes the type.
[9262fe9]1050\begin{python}
[c033405]1051class RGB(Enum): Red = 1; Green = 2; Blue = 3
1052day : Week = Week.Tue; $\C{\# type is Week}$
1053!day = RGB.Red! $\C{\# type is RGB}$
1054!day : Week = RGB.Red! $\C{\# type is RGB}$
[9262fe9]1055\end{python}
[c033405]1056The enumerators are constants and cannot be reassigned.
1057Hence, while enumerators can be different types,
[9262fe9]1058\begin{python}
[c033405]1059class Diff(Enum): Int = 1; Float = 3.5; Str = "ABC"
[9262fe9]1060\end{python}
[c033405]1061it is not an ADT because the enumerator names are not constructors.
[9262fe9]1062
[c033405]1063An enumerator initialized with the same value is an alias and invisible at the enumeration level, \ie the alias is substituted for its aliasee.
[9262fe9]1064\begin{python}
[c033405]1065class WeekD(Enum): Mon = 1; Tue = 2; Wed = 3; Thu = !10!; Fri = !10!; Sat = !10!; Sun = !10!
[9262fe9]1066\end{python}
[c033405]1067Here, the enumeration has only 4 enumerators and 3 aliases.
1068An alias is only visible by dropping down to the @class@ level and asking for class members.
1069Aliasing is prevented using the @unique@ decorator.
[9262fe9]1070\begin{python}
[c033405]1071!@unique!
1072class DupVal(Enum): One = 1; Two = 2; Three = !3!; Four = !3!
1073ValueError: duplicate values found in <enum 'DupVal'>: Four -> Three
[9262fe9]1074\end{python}
1075
[c033405]1076\begin{lrbox}{\myboxA}
[9262fe9]1077\begin{python}
[c033405]1078def by_position(enum_type, position):
1079 for index, value in enumerate(enum_type):
1080 if position == index: return value
1081 raise Exception("by_position out of range")
[9262fe9]1082\end{python}
[c033405]1083\end{lrbox}
1084There are bidirectional enumeration pseudo-functions for label and value, but there is no concept of access using ordering (position).\footnote{
1085There is an $O(N)$ mechanism to access an enumerator's value by position. \newline \usebox\myboxA}
1086\begin{cquote}
1087\setlength{\tabcolsep}{15pt}
1088\begin{tabular}{@{}ll@{}}
[9262fe9]1089\begin{python}
[c033405]1090Week.Thu.value == 4;
1091Week.Thu.name == "Thu";
[9262fe9]1092\end{python}
[c033405]1093&
[9262fe9]1094\begin{python}
[c033405]1095Week( 4 ) == Week.Thu
1096Week["Thu"].value == 4
[9262fe9]1097\end{python}
[c033405]1098\end{tabular}
1099\end{cquote}
1100@Enum@ only supports equality comparison between enumerator values.
1101There are multiple library extensions to @Enum@, \eg @OrderedEnum@ recipe class, adding relational operators @<@, @<=@, @>@, and @>=@.
[9262fe9]1102
[c033405]1103An enumeration \lstinline[language=python]{class} can have methods.
[9262fe9]1104\begin{python}
[c033405]1105class Week(!OrderedEnum!):
1106 Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5; Sat = 6; Sun = 7
[c1c0efdb]1107 def !isWeekday(self)!: # methods
[c033405]1108 return Week(self.value) !<=! Week.Fri
[c1c0efdb]1109 def !isWeekend(self)!:
[c033405]1110 return Week.Sat !<=! Week(self.value)
[9262fe9]1111\end{python}
1112
[c033405]1113An enumeration can be used in the @if@ and @switch@ statements but only for equality tests, unless extended to @OrderedEnum@.
1114\begin{cquote}
1115\setlength{\tabcolsep}{12pt}
1116\begin{tabular}{@{}ll@{}}
[9262fe9]1117\begin{python}
[c033405]1118if day <= Week.Fri :
1119 print( "weekday" );
[9262fe9]1120
1121
1122
1123\end{python}
[c033405]1124&
[9262fe9]1125\begin{python}
[c033405]1126match day:
1127 case Week.Mon | Week.Tue | Week.Wed | Week.Thu | Week.Fri:
1128 print( "weekday" );
1129 case Week.Sat | Week.Sun:
1130 print( "weekend" );
[9262fe9]1131\end{python}
[c033405]1132\end{tabular}
1133\end{cquote}
1134Looping is performed using the enumeration type or @islice@ from @itertools@ based on position.
[9262fe9]1135\begin{python}
[c033405]1136for day in !Week!: $\C[2.25in]{\# Mon : 1 Tue : 2 Wed : 3 Thu : 4 Fri : 5 Sat : 6 Sun : 7}$
1137 print( day.name, ":", day.value, end=" " )
1138for day in !islice(Week, 0, 5)!: $\C{\# Mon : 1 Tue : 2 Wed : 3 Thu : 4 Fri : 5}$
1139 print( day.name, ":", day.value, end=" " )
1140for day in !islice(Week, 5, 7)!: $\C{\# Sat : 6 Sun : 7}$
1141 print( day.name, ":", day.value, end=" " )
1142for day in !islice(Week,0, 7, 2)!: $\C{\# Mon : 1 Wed : 3 Fri : 5 Sun : 7}\CRT$
1143 print( day.name, ":", day.value, end=" " )
[9262fe9]1144\end{python}
[c033405]1145Iterating that includes alias names only (strings) is done using attribute @__members__@.
[9262fe9]1146\begin{python}
[c033405]1147for day in WeekD.__members__:
1148 print( day, ":", end=" " )
1149Mon : Tue : Wed : Thu : Fri : Sat : Sun
[9262fe9]1150\end{python}
1151
[c033405]1152Enumeration subclassing is allowed only if the enumeration base-class does not define any members.
[9262fe9]1153\begin{python}
[c033405]1154class WeekE(OrderedEnum): !pass!; # no members
1155class WeekDay(WeekE): Mon = 1; Tue = 2; Wed = 3; Thu = 4; Fri = 5;
1156class WeekEnd(WeekE): Sat = 6; Sun = 7
[9262fe9]1157\end{python}
[11cced6]1158Here, type @WeekE@ is an abstract type because dynamic typing never uses it.
[c033405]1159\begin{cquote}
1160\setlength{\tabcolsep}{25pt}
1161\begin{tabular}{@{}ll@{}}
[9262fe9]1162\begin{python}
[c033405]1163print( type(WeekE) )
1164day : WeekE = WeekDay.Fri # set type
1165print( type(day), day )
1166day = WeekEnd.Sat # set type
1167print( type(day), day )
[9262fe9]1168\end{python}
[c033405]1169&
[9262fe9]1170\begin{python}
[c033405]1171<$class$ 'enum.EnumType'>
[9262fe9]1172
[c033405]1173<enum 'WeekDay'> WeekDay.Fri
[9262fe9]1174
[c033405]1175<enum 'WeekEnd'> WeekEnd.Sat
[9262fe9]1176\end{python}
[c033405]1177\end{tabular}
1178\end{cquote}
[9262fe9]1179
[c033405]1180There are a number of supplied enumeration base-types: @IntEnum@, @StrEnum@, @IntFalg@, @Flag@, which restrict the values in an enum using multi-inheritance.
1181@IntEnum@ is a subclass of @int@ and @Enum@, allowing enumerator comparison to @int@ and other enumerators of this type (like C enumerators).
1182@StrEnum@ is the same as @IntEnum@ but a subclass of the string type \lstinline[language=python]{str}.
1183@IntFlag@, is a restricted subclass of @int@ where the enumerators can be combined using the bitwise operators (@&@, @|@, @^@, @~@) and the result is an @IntFlag@ member.
1184@Flag@ is the same as @IntFlag@ but cannot be combined with, nor compared against, any other @Flag@ enumeration, nor @int@.
1185Auto increment for @IntFlag@ and @Flag@ is by powers of 2.
[11cced6]1186Enumerators that are combinations of single-bit enumerators are aliases and, hence, invisible.
[c033405]1187The following is an example for @Flag@.
[9262fe9]1188\begin{python}
[c033405]1189class WeekF(Flag): Mon = 1; Tue = 2; Wed = 4; Thu = !auto()!; Fri = 16; Sat = 32; Sun = 64; \
1190 Weekday = Mon | Tue | Wed | Thu | Fri; \
1191 Weekend = Sat | Sun
1192print( f"0x{repr(WeekF.Weekday.value)} 0x{repr(WeekF.Weekend.value)}" )
11930x31 0x96
[9262fe9]1194\end{python}
[c033405]1195It is possible to enumerate through a @Flag@ enumerator (no aliases):
[9262fe9]1196\begin{python}
[c033405]1197for day in WeekF:
1198 print( f"{day.name}: {day.value}", end=" ")
1199Mon: 1 Tue: 2 Wed: 4 Thu: 8 Fri: 16 Sat: 32 Sun: 64
[9262fe9]1200\end{python}
[c033405]1201and a combined alias enumerator for @Flag@.
1202\begin{cquote}
1203\setlength{\tabcolsep}{15pt}
1204\begin{tabular}{@{}ll@{}}
[9262fe9]1205\begin{python}
[c033405]1206weekday = WeekF.Weekday
1207for day in weekday:
1208 print( f"{day.name}:"
1209 f" {day.value}", end=" " )
1210Mon: 1 Tue: 2 Wed: 4 Thu: 8 Fri: 16
[7d9a805b]1211\end{python}
[c033405]1212&
[9262fe9]1213\begin{python}
[c033405]1214weekend = WeekF.Weekend
1215for day in weekend:
1216 print( f"{day.name}:"
1217 f" {day.value}", end=" " )
1218Sat: 32 Sun: 64
[9262fe9]1219\end{python}
[c033405]1220\end{tabular}
1221\end{cquote}
[9262fe9]1222
[956299b]1223
[282061a]1224\section{OCaml}
1225
[7d9a805b]1226% https://ocaml.org/docs/basic-data-types#enumerated-data-types
[d734fa1]1227% https://dev.realworldocaml.org/runtime-memory-layout.html
[7d9a805b]1228
[29c8675]1229Like Swift (\VRef{s:Swift}) and Haskell (\VRef{s:AlgebraicDataType}), OCaml @enum@ provides two largely independent mechanisms from a single language feature: an ADT and an enumeration.
[41f4e2d]1230When @enum@ is an ADT, pattern matching is used to discriminate among the variant types.
1231\begin{cquote}
1232\setlength{\tabcolsep}{20pt}
1233\begin{tabular}{@{}l@{\hspace{35pt}}ll@{}}
1234\begin{ocaml}
1235type s = { i : int; j : int }
1236let sv : s = { i = 3; j = 5 }
1237@type@ adt =
1238 I of int | $\C[1in]{// int}$
1239 F of float | $\C{// float}$
1240 S of s $\C{// struct}\CRT$
[d734fa1]1241
[41f4e2d]1242
1243\end{ocaml}
1244&
[282061a]1245\begin{ocaml}
[41f4e2d]1246let adtprt( adtv : adt ) =
1247 @match@ adtv with (* pattern matching *)
1248 I i -> printf "%d\n" i |
1249 F f -> printf "%g\n" f |
1250 S sv -> printf "%d %d\n" sv.i sv.j
1251let adtv : adt = I(3) let _ = adtprt( adtv )
1252let adtv : adt = F(3.5) let _ = adtprt( adtv )
1253let adtv : adt = S(sv) let _ = adtprt( adtv )
[282061a]1254\end{ocaml}
[41f4e2d]1255&
[282061a]1256\begin{ocaml}
[c1c0efdb]12573
12583.5
12593 5
[41f4e2d]1260
1261
1262
1263
1264
[282061a]1265\end{ocaml}
[41f4e2d]1266\end{tabular}
1267\end{cquote}
[29c8675]1268% (Note, after an @adtv@'s type is know, the enumerator is inferred without qualification, \eg @I(3)@.)
1269
[11cced6]1270The type names are independent of the type value and mapped to an opaque, ascending, integral tag, starting from 0, supporting relational operators @<@, @<=@, @>@, and @>=@.
[41f4e2d]1271\begin{cquote}
1272\setlength{\tabcolsep}{10pt}
1273\begin{tabular}{@{}l@{\hspace{25pt}}ll@{}}
[282061a]1274\begin{ocaml}
[41f4e2d]1275let silly( adtv : adt ) =
1276 if adtv <= F(3.5) then
1277 printf "<= F\n"
1278 else if adtv >= S(sv) then
1279 printf ">= S\n"
[282061a]1280\end{ocaml}
[41f4e2d]1281&
1282\begin{ocaml}
1283let adtv : adt = I(3) let _ = silly( adtv )
1284let adtv : adt = F(3.5) let _ = silly( adtv )
1285let adtv : adt = S(sv) let _ = silly( adtv )
[9398177]1286
[41f4e2d]1287
1288\end{ocaml}
1289&
[282061a]1290\begin{ocaml}
[41f4e2d]1291<= F
1292<= F
1293>= S
1294
1295
[282061a]1296\end{ocaml}
[41f4e2d]1297\end{tabular}
1298\end{cquote}
1299In the example, type values must be specified (any appropriate values work) but ignored in the relational comparison of the type tag.
1300
1301An enumeration is created when \emph{all} the enumerators are unit-type, which is like a scoped, opaque enumeration, where only the type tag is used.
[282061a]1302\begin{ocaml}
[41f4e2d]1303type week = Mon | Tue | Wed | Thu | Fri | Sat | Sun
1304let day : week = Mon
[282061a]1305\end{ocaml}
[41f4e2d]1306Since the type names are opaque, a type-tag value cannot be explicitly set nor can it have a type other than integral.
1307
1308As seen, a type tag can be used in the @if@ and \lstinline[language=ocaml]{match} statements, where \lstinline[language=ocaml]{match} must be exhaustive or have a default case.
[9a32903]1309
[c1c0efdb]1310While OCaml enumerators have an ordering following the definition order, they are not enumerable.
[29c8675]1311To iterate over all enumerators, an OCaml type needs to derive from the @enumerate@ PPX (Pre-Preocessor eXtension), which appends a list of all enumerators to the program abstract syntax tree (AST).
1312However, as stated in the documentation, @enumerate@ PPX does not guarantee the order of the list.
1313PPX is beyond the scope of OCaml native language and it is a preprocessor directly modifying a parsed AST. In conclusion, there is no enumerating mechanism within the scope of OCaml language.
[6337916]1314
[0c88135]1315New types can be formed as a composition of existing types.
[dcfcf368]1316\begin{ocaml}
1317type weekday = Mon | Tue | Wed | Thu | Fri
1318type weekend = Sat | Sun
1319type week = Weekday of weekday | Weekend of weekend
1320let day : week = Weekend Sun
1321\end{ocaml}
[68a7028]1322The type @week@ is the sum of @weekday@ and @weekend@, \ie @week@ has all the enumerators from the set @weekday@ and @weekend@.
1323The sum type construction resembles containment inheritance from non-functional programming discipline, with the sum type being a wrapper class that contains one of its parent types.
[4fa7096]1324The wrapper is unwrapped with pattern matching.
[68a7028]1325\begin{cquote}
1326\begin{tabular}{@{}ll@{}}
[0c88135]1327\begin{ocaml}
[68a7028]1328type weekday = Mon | Tue | Wed | Thu | Fri
1329type weekend = Sat | Sun
1330type week = Weekday of weekday |
1331 Weekend of weekend
[0c88135]1332let wd : weekday = Mon
1333let _ = match wd with
[68a7028]1334 Mon -> printf "Mon " | _ -> ()
[0c88135]1335let we : weekend = Sun
1336let _ = match we with
[68a7028]1337 Sun -> printf "Sun " | _ -> ()
[0c88135]1338let day : week = Weekend Sun
1339let _ = match day with
[68a7028]1340 Weekend Sun -> printf "Sun\n" | _ -> ()
1341
[0c88135]1342\end{ocaml}
[68a7028]1343&
1344\begin{cfa}
1345enum() weekday { Mon, Tue, Wed, Thu, Fri };
1346enum() weekend { Sat, Sun };
1347enum() week { inline weekday, inline weekend };
1348int main() {
1349 weekday wd = Mon;
1350
1351 printf( "%s ", label( wd ) );
1352 weekend we = Sun;
1353
1354 printf( "%s ", label( we ) );
1355 week day = Sun;
1356
1357 printf( "%s\n", label( day ) );
1358}
1359\end{cfa}
1360\\
1361\begin{cfa}
1362Mon Sun Sun
1363\end{cfa}
1364\end{tabular}
1365\end{cquote}
[dcfcf368]1366
[c033405]1367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1368
[6337916]1369\begin{comment}
1370Date: Wed, 13 Mar 2024 10:52:34 -0400
1371Subject: Re: OCaml
1372To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
1373From: Gregor Richards <gregor.richards@uwaterloo.ca>
1374
1375On 3/12/24 18:34, Peter A. Buhr wrote:
1376> Gregor, attached is a section Jiada wrote on OCaml (1-page).
1377> Does it reflect our discussion about functional languages and enumerations?
1378
1379Yeah, I think so. The most important part, i.e., that once they're
1380parameterized they're not really enumerations at all, is covered clearly
1381enough.
1382
1383A couple quibbles:
1384
1385<<a list of untyped tags>>
1386
1387This is true, but leaking implementation details. These are nullary datatype
1388constructors. Indeed, you later talk about "tagged variants", which are really
1389just parameterized variants, using the term "tag" differently, confusing the
1390term "tag" further.
1391
[ec20ab9]1392<<Because week is a summation of values Mon to Sun, it is a sum type in
[6337916]1393turns of the functional-programming paradigm>>
1394
1395It is a *union* of values and is a *union* type.
1396
[7d9a805b]1397With valediction,
1398 - Gregor Richards
1399
1400
1401Date: Thu, 14 Mar 2024 21:45:52 -0400
1402Subject: Re: OCaml "enums" do come with ordering
1403To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
1404From: Gregor Richards <gregor.richards@uwaterloo.ca>
1405
1406On 3/14/24 21:30, Peter A. Buhr wrote:
1407> I've marked 3 places with your name to shows places with enum ordering.
1408>
[41f4e2d]1409> open Printf
[ec20ab9]1410> type week = Mon | Tue | Wed | Thu | Fri | Sat | Sun
1411> let day : week = Mon
1412> let take_class( d : week ) =
[7d9a805b]1413> if d <= Fri then (* Gregor *)
[41f4e2d]1414> printf "week\n"
[7d9a805b]1415> else if d >= Sat then (* Gregor *)
[41f4e2d]1416> printf "weekend\n";
[7d9a805b]1417> match d with
[41f4e2d]1418> Mon | Wed -> printf "CS442\n" |
1419> Tue | Thu -> printf "CS343\n" |
1420> Fri -> printf "Tutorial\n" |
1421> _ -> printf "Take a break\n"
[7d9a805b]1422>
1423> let _ = take_class( Mon ); take_class( Sat );
1424>
1425> type colour = Red | Green of string | Blue of int * float
1426> let c = Red
[41f4e2d]1427> let _ = match c with Red -> printf "Red, "
[7d9a805b]1428> let c = Green( "abc" )
[41f4e2d]1429> let _ = match c with Green g -> printf "%s, " g
[7d9a805b]1430> let c = Blue( 1, 1.5 )
[41f4e2d]1431> let _ = match c with Blue( i, f ) -> printf "%d %g\n" i f
[7d9a805b]1432>
1433> let check_colour(c: colour): string =
1434> if c < Green( "xyz" ) then (* Gregor *)
[41f4e2d]1435> printf "green\n";
[7d9a805b]1436> match c with
1437> Red -> "Red" |
1438> Green g -> g |
1439> Blue(i, f) -> string_of_int i ^ string_of_float f
1440> let _ = check_colour( Red ); check_colour( Green( "xyz" ) );
1441>
1442> type stringList = Empty | Pair of string * stringList
1443> let rec len_of_string_list(l: stringList): int =
1444> match l with
1445> Empty -> 0 |
1446> Pair(_ , r) -> 1 + len_of_string_list r
1447>
1448> let _ = for i = 1 to 10 do
[41f4e2d]1449> printf "%d, " i
[7d9a805b]1450> done
1451>
1452> (* Local Variables: *)
1453> (* tab-width: 4 *)
1454> (* compile-command: "ocaml test.ml" *)
1455> (* End: *)
1456
1457My functional-language familiarity is far more with Haskell than OCaml. I
1458mostly view OCaml through a lens of "it's Haskell but with cheating". Haskell
1459"enums" (ADTs) aren't ordered unless you specifically and manually put them in
1460the Ord typeclass by defining the comparators. Apparently, OCaml has some
1461other rule, which I would guess is something like "sort by tag then by order of
1462parameter". Having a default behavior for comparators is *bizarre*; my guess
1463would be that it gained this behavior in its flirtation with object
1464orientation, but that's just a guess (and irrelevant).
1465
1466This gives a total order, but not enumerability (which would still be
1467effectively impossible or even meaningless since enums are just a special case
1468of ADTs).
1469
[e00b10d]1470With valediction,
1471 - Gregor Richards
1472
1473Date: Wed, 20 Mar 2024 18:16:44 -0400
1474Subject: Re:
1475To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
1476From: Gregor Richards <gregor.richards@uwaterloo.ca>
1477
1478
1479On 3/20/24 17:26, Peter A. Buhr wrote:
1480> Gregor, everyone at this end would like a definition of "enumerability". Can
1481> you formulate one?
1482
1483According to the OED (emphasis added to the meaning I'm after):
1484
1485enumerate (verb, transitive). To count, ascertain the number of; **more
1486usually, to mention (a number of things or persons) separately, as if for the
1487purpose of counting**; to specify as in a list or catalogue.
1488
1489With C enums, if you know the lowest and highest value, you can simply loop
1490over them in a for loop (this is, of course, why so many enums come with an
1491ENUM_WHATEVER_LAST value). But, I would be hesitant to use the word "loop" to
1492describe enumerability, since in functional languages, you would recurse for
1493such a purpose.
1494
1495In Haskell, in order to do something with every member of an "enumeration", you
1496would have to explicitly list them all. The type system will help a bit since
1497it knows if you haven't listed them all, but you would have to statically have
1498every element in the enumeration. If somebody added new elements to the
1499enumeration later, your code to enumerate over them would no longer work
1500correctly, because you can't simply say "for each member of this enumeration do
1501X". In Haskell that's because there aren't actually enumerations; what they use
1502as enumerations are a degenerate form of algebraic datatypes, and ADTs are
1503certainly not enumerable. In OCaml, you've demonstrated that they impose
1504comparability, but I would still assume that you can't make a loop over every
1505member of an enumeration. (But, who knows!)
1506
1507Since that's literally what "enumerate" means, it seems like a rather important
1508property for enumerations to have ;)
1509
1510With valediction,
1511 - Gregor Richards
1512
1513
1514From: Andrew James Beach <ajbeach@uwaterloo.ca>
1515To: Gregor Richards <gregor.richards@uwaterloo.ca>, Peter Buhr <pabuhr@uwaterloo.ca>
1516CC: Michael Leslie Brooks <mlbrooks@uwaterloo.ca>, Fangren Yu <f37yu@uwaterloo.ca>,
[c033405]1517 Jiada Liang <j82liang@uwaterloo.ca>
[e00b10d]1518Subject: Re: Re:
1519Date: Thu, 21 Mar 2024 14:26:36 +0000
1520
1521Does this mean that not all enum declarations in C create enumerations? If you
1522declare an enumeration like:
1523
1524enum Example {
[c033405]1525 Label,
1526 Name = 10,
1527 Tag = 3,
[e00b10d]1528};
1529
1530I don't think there is any way to enumerate (iterate, loop, recurse) over these
1531values without listing all of them.
1532
1533
1534Date: Thu, 21 Mar 2024 10:31:49 -0400
1535Subject: Re:
1536To: Andrew James Beach <ajbeach@uwaterloo.ca>, Peter Buhr <pabuhr@uwaterloo.ca>
1537CC: Michael Leslie Brooks <mlbrooks@uwaterloo.ca>, Fangren Yu <f37yu@uwaterloo.ca>,
1538 Jiada Liang <j82liang@uwaterloo.ca>
1539From: Gregor Richards <gregor.richards@uwaterloo.ca>
1540
1541I consider this conclusion reasonable. C enums can be nothing more than const
1542ints, and if used in that way, I personally wouldn't consider them as
1543enumerations in any meaningful sense, particularly since the type checker
1544essentially does nothing for you there. Then they're a way of writing consts
1545repeatedly with some textual indicator that these definitions are related; more
1546namespace, less enum.
1547
1548When somebody writes bitfield members as an enum, is that *really* an
1549enumeration, or just a use of the syntax for enums to keep related definitions
1550together?
1551
[4da9142]1552With valediction,
1553 - Gregor Richards
1554
1555
1556Date: Tue, 16 Apr 2024 11:04:51 -0400
1557Subject: Re: C unnamed enumeration
1558To: "Peter A. Buhr" <pabuhr@uwaterloo.ca>
1559CC: <ajbeach@uwaterloo.ca>, <j82liang@uwaterloo.ca>, <mlbrooks@uwaterloo.ca>,
1560 <f37yu@uwaterloo.ca>
1561From: Gregor Richards <gregor.richards@uwaterloo.ca>
1562
1563On 4/16/24 09:55, Peter A. Buhr wrote:
1564> So what is a variant? Is it a set of tag names, which might be a union or is it
1565> a union, which might have tag names?
1566
1567Your tagless variant bears no resemblance to variants in any functional
1568programming language. A variant is a tag AND a union. You might not need to put
1569anything in the union, in which case it's a pointless union, but the named tag
1570is absolutely mandatory. That's the thing that varies.
1571
1572I was unaware of std::variant. As far as functional languages are concerned,
1573std::variant IS NOT A VARIANT. Perhaps it would be best to use the term ADT for
1574the functional language concept, because that term has no other meanings.
1575
1576An ADT cannot not have a named tag. That's meaningless. The tag is the data
1577constructor, which is the thing you actually define when you define an ADT. It
1578is strictly the union that's optional.
1579
[6337916]1580With valediction,
1581 - Gregor Richards
1582\end{comment}
[223b631]1583
1584
1585\section{Comparison}
1586
[5b4c8df]1587\VRef[Table]{t:FeatureLanguageComparison} shows a comparison of enumeration features and programming languages with the explaination of categories below.
[11cced6]1588The features are high-level and may not capture nuances within a particular language.
[7d9a805b]1589
1590\begin{table}
1591\caption{Enumeration Feature / Language Comparison}
1592\label{t:FeatureLanguageComparison}
1593\small
1594\setlength{\tabcolsep}{3pt}
1595\newcommand{\CM}{\checkmark}
1596\begin{tabular}{r|c|c|c|c|c|c|c|c|c|c|c|c|c}
[5b4c8df]1597 &Pascal & Ada &\Csharp & OCaml & Java &Golang & Rust & Swift & Python& C & \CC & \CFA \\
1598\hline
1599enum &Dialect& \CM & \CM & ADT & \CM & @const@ &ADT/\CM &ADT/\CM & \CM &\CM &\CM &\CM\\
[7d9a805b]1600\hline
1601\hline
[5b4c8df]1602opaque & \CM & & & \CM & \CM & & \CM & \CM & & & & \CM \\
[7d9a805b]1603\hline
[29c8675]1604typed & Int & Int & Int & H & U & H & U/H & U/H & H & Int & Int & U \\
[7d9a805b]1605\hline
[5b4c8df]1606safety & \CM & \CM & & \CM & \CM & & \CM & \CM & & & \CM & \CM \\
[7d9a805b]1607\hline
[5b4c8df]1608posn ordered & Implied & Implied & & \CM & & & & & & & & \CM \\
[7d9a805b]1609\hline
[29c8675]1610unique values & \CM & \CM & &\CM & & & & \CM & & & & \\
[7d9a805b]1611\hline
[29c8675]1612auto-init & \CM & all or none & \CM & N/A & & \CM & \CM & \CM & \CM & \CM & \CM & \CM \\
[7d9a805b]1613\hline
[c1c0efdb]1614(Un)Scoped & U & U & S & S & S & U & S & S & S & U & U/S & U/S \\
[7d9a805b]1615\hline
[5b4c8df]1616overload & & \CM & & & & & & & & & & \CM \\
[7d9a805b]1617\hline
[5b4c8df]1618loop & \CM & \CM & & & & & & & \CM & & & \CM \\
[7d9a805b]1619\hline
[5b4c8df]1620arr. dim. & \CM & \CM & & & & & & & & & & \CM \\
[7d9a805b]1621\hline
[29c8675]1622subset & \CM & \CM & & & & & & & & & & \CM \\
[7d9a805b]1623\hline
[175a750e]1624superset & & & & \CM & & &\CM &\CM & & & & \CM \\
[223b631]1625\end{tabular}
[7d9a805b]1626\end{table}
[a8f44c83]1627
1628\begin{enumerate}
[c1c0efdb]1629\item opaque: an enumerator cannot be used as its underlying representation or implemented in terms of an ADT.
1630\item typed: H $\Rightarrow$ heterogeneous, \ie enumerator values may be different types. \\
1631U $\Rightarrow$ homogenous, \ie enumerator values have the same type.
1632\item safety: An enumeration variable can only hold a value from its defined enumerators.
1633\item posn ordered: enumerators have defined ordering based on enumerator declaration order.
1634Position ordered is implied if the enumerator values must be strictly increasingly.
1635\item unique value: enumerators must have a unique value.
[29c8675]1636\item auto-init: Values are auto-initializable by language specification. \\
1637It is not appliable to OCaml because OCaml enumeration has unit type.
[c1c0efdb]1638\item (Un)Scoped: U $\Rightarrow$ enumerators are projected into the containing scope.
1639S $\Rightarrow$ enumerators are contained in the enumeration scope and require qualification.
1640\item overload: An enumerator label can be used without type qualification in a context where multiple enumerations have defined the label.
1641\item loop: Enumerate without the need to convert an enumeration to another data structure.
1642\item arr. dim: An enumeration can be used directly as an array dimension, and enumerators can be mapped to an array element (not a conversion to integer type).
1643\item subset: Name a subset of enumerators as a new type.
1644\item superset: Create a new enumeration that contains all enumerators from pre-defined enumerations.
[a8f44c83]1645\end{enumerate}
Note: See TracBrowser for help on using the repository browser.