|
| 1 | +--- |
| 2 | +layout: doc-page |
| 3 | +title: "Translation of Enums and ADTs" |
| 4 | +--- |
| 5 | + |
| 6 | +The compiler expands enum classes and cases to code that only uses |
| 7 | +Scala's other language features. As such, enums in Scala are |
| 8 | +convenient _syntactic sugar_, but they are not essential to understand |
| 9 | +Scala's core. |
| 10 | + |
| 11 | +We now explain the expansion of enums is explained in detail. First, |
| 12 | +some terminology and notational conventions: |
| 13 | + |
| 14 | + - We use `E` as a name of an enum class, and `C` as a name of an enum case that appears in the companion object of `E`. |
| 15 | + - We use `<...>` for syntactic constructs that in some circumstances might be empty. For instance `<body>` represents either the body of a case between `{...}` or nothing at all. |
| 16 | + |
| 17 | + - Enum cases fall into three categories: |
| 18 | + |
| 19 | + - _Class cases_ are those cases that are parameterized, either with a type parameter section `[...]` or with one or more (possibly empty) parameter sections `(...)`. |
| 20 | + - _Simple cases_ are cases of a non-generic enum class that have neither parameters nor an extends clause or body. That is, they consist of a name only. |
| 21 | + - _Value cases_ are all cases that do not have a parameter section but that do have a (possibly generated) extends clause and/or a body. |
| 22 | + |
| 23 | + Simple cases and value cases are called collectively _singleton cases_. |
| 24 | + |
| 25 | +The desugaring rules imply that class cases are mapped to case classes, and singleton cases are mapped to `val` definitions. |
| 26 | + |
| 27 | +There are eight desugaring rules. Rules (1) and (2) desugar enums and |
| 28 | +enum classes. Rules (3) and (4) define extends clauses for cases that |
| 29 | +are missing them. Rules (5 - 7) define how such expanded cases map |
| 30 | +into case classes, case objects or vals. Finally, rule (8) expands |
| 31 | +comma separated simple cases into a sequence of cases. |
| 32 | + |
| 33 | +1. An `enum` definition |
| 34 | + |
| 35 | + enum E ... { <cases> } |
| 36 | + |
| 37 | + expands to an enum class and a companion object |
| 38 | + |
| 39 | + enum class E ... |
| 40 | + object E { <cases> } |
| 41 | + |
| 42 | +2. An enum class definition |
| 43 | + |
| 44 | + enum class E ... extends <parents> ... |
| 45 | + |
| 46 | + expands to a `sealed` `abstract` class that extends the `scala.Enum` trait: |
| 47 | + |
| 48 | + sealed abstract class E ... extends <parents> with scala.Enum ... |
| 49 | + |
| 50 | +3. If `E` is an enum class without type parameters, then a case in its companion object without an extends clause |
| 51 | + |
| 52 | + case C <params> <body> |
| 53 | + |
| 54 | + expands to |
| 55 | + |
| 56 | + case C <params> <body> extends E |
| 57 | + |
| 58 | +4. If `E` is an enum class with type parameters `Ts`, then a case in its |
| 59 | + companion object without an extends clause |
| 60 | + |
| 61 | + case C <params> <body> |
| 62 | + |
| 63 | + expands according to two alternatives, depending whether `C` has type |
| 64 | + parameters or not. If `C` has type parameters, they must have the same |
| 65 | + names and appear in the same order as the enum type parameters `Ts` |
| 66 | + (variances may be different, however). In this case |
| 67 | + |
| 68 | + case C [Ts] <params> <body> |
| 69 | + |
| 70 | + expands to |
| 71 | + |
| 72 | + case C[Ts] <params> extends E[Ts] <body> |
| 73 | + |
| 74 | + For the case where `C` does not have type parameters, assume `E`'s type |
| 75 | + parameters are |
| 76 | + |
| 77 | + V1 T1 > L1 <: U1 , ... , Vn Tn >: Ln <: Un (n > 0) |
| 78 | + |
| 79 | + where each of the variances `Vi` is either `'+'` or `'-'`. Then the case |
| 80 | + expands to |
| 81 | + |
| 82 | + case C <params> extends E[B1, ..., Bn] <body> |
| 83 | + |
| 84 | + where `Bi` is `Li` if `Vi = '+'` and `Ui` if `Vi = '-'`. It is an error if |
| 85 | + `Bi` refers to some other type parameter `Tj (j = 0,..,n-1)`. It is also |
| 86 | + an error if `E` has type parameters that are non-variant. |
| 87 | + |
| 88 | +5. A class case |
| 89 | + |
| 90 | + case C <params> ... |
| 91 | + |
| 92 | + expands analogous to a case class: |
| 93 | + |
| 94 | + final case class C <params> ... |
| 95 | + |
| 96 | + However, unlike for a regular case class, the return type of the associated |
| 97 | + `apply` method is a fully parameterized type instance of the enum class `E` |
| 98 | + itself instead of `C`. Also the enum case defines an `enumTag` method of |
| 99 | + the form |
| 100 | + |
| 101 | + def enumTag = n |
| 102 | + |
| 103 | + where `n` is the ordinal number of the case in the companion object, |
| 104 | + starting from 0. |
| 105 | + |
| 106 | +6. A value case |
| 107 | + |
| 108 | + case C extends <parents> <body> |
| 109 | + |
| 110 | + expands to a value definition |
| 111 | + |
| 112 | + val C = new <parents> { <body>; def enumTag = n; $values.register(this) } |
| 113 | + |
| 114 | + where `n` is the ordinal number of the case in the companion object, |
| 115 | + starting from 0. The statement `$values.register(this)` registers the value |
| 116 | + as one of the `enumValues` of the enumeration (see below). `$values` is a |
| 117 | + compiler-defined private value in the companion object. |
| 118 | + |
| 119 | +7. A simple case |
| 120 | + |
| 121 | + case C |
| 122 | + |
| 123 | + of an enum class `E` that does not take type parameters expands to |
| 124 | + |
| 125 | + val C = $new(n, "C") |
| 126 | + |
| 127 | + Here, `$new` is a private method that creates an instance of of `E` (see |
| 128 | + below). |
| 129 | + |
| 130 | +8. A simple case consisting of a comma-separated list of enum names |
| 131 | + |
| 132 | + case C_1, ..., C_n |
| 133 | + |
| 134 | + expands to |
| 135 | + |
| 136 | + case C_1; ...; case C_n |
| 137 | + |
| 138 | + Any modifiers or annotations on the original case extend to all expanded |
| 139 | + cases. |
| 140 | + |
| 141 | +## Translation of Enumerations |
| 142 | + |
| 143 | +Non-generic enum classes `E` that define one or more singleton cases |
| 144 | +are called _enumerations_. Companion objects of enumerations define |
| 145 | +the following additional members. |
| 146 | + |
| 147 | + - A method `enumValue` of type `scala.collection.immutable.Map[Int, E]`. |
| 148 | + `enumValue(n)` returns the singleton case value with ordinal number `n`. |
| 149 | + - A method `enumValueNamed` of type `scala.collection.immutable.Map[String, E]`. |
| 150 | + `enumValueNamed(s)` returns the singleton case value whose `toString` |
| 151 | + representation is `s`. |
| 152 | + - A method `enumValues` which returns an `Iterable[E]` of all singleton case |
| 153 | + values in `E`, in the order of their definitions. |
| 154 | + |
| 155 | +Companion objects that contain at least one simple case define in addition: |
| 156 | + |
| 157 | + - A private method `$new` which defines a new simple case value with given |
| 158 | + ordinal number and name. This method can be thought as being defined as |
| 159 | + follows. |
| 160 | + |
| 161 | + def $new(tag: Int, name: String): ET = new E { |
| 162 | + def enumTag = tag |
| 163 | + def toString = name |
| 164 | + $values.register(this) // register enum value so that `valueOf` and `values` can return it. |
| 165 | + } |
0 commit comments