|
| 1 | +# Algebraic Data Types |
| 2 | + |
| 3 | +The `enum` concept is general enough to also support algebraic data |
| 4 | +types (ADTs) and their generalized version (GADTs). Here's an example |
| 5 | +how an `Option` type can be represented as an ADT: |
| 6 | + |
| 7 | +```scala |
| 8 | +enum Option[+T] { |
| 9 | + case Some[+T](x: T) |
| 10 | + case None |
| 11 | +} |
| 12 | +``` |
| 13 | + |
| 14 | +This example introduces `Option` enum class with a covariant type |
| 15 | +parameter `T`, together with two cases, `Some` and `None`. `Some` is |
| 16 | +parameterized with a type parameter `T` and a value parameter `x`. It |
| 17 | +is a shorthand for writing a case class that extends `Option`. Since |
| 18 | +`None` is not parameterized it is treated as a normal enum value. |
| 19 | + |
| 20 | +The `extends` clauses that were omitted in the example above can also |
| 21 | +be given explicitly: |
| 22 | + |
| 23 | +```scala |
| 24 | +enum Option[+T] { |
| 25 | + case Some[T](x: T) extends Option[T] |
| 26 | + case None extends Option[Nothing] |
| 27 | +} |
| 28 | +``` |
| 29 | + |
| 30 | +Note that the parent type of `None` is inferred as |
| 31 | +`List[Nothing]`. Generally, all covariant type parameters of the enum |
| 32 | +class are minimized in a compiler-generated extends clause whereas all |
| 33 | +contravariant type parameters are maximized. If `Option` was non-variant, |
| 34 | +you'd need to give the extends clause of `None` explicitly. |
| 35 | + |
| 36 | +As for normal enum values, the cases of an `enum` are all defined in |
| 37 | +the `enum`s companion object. So it's `Option.Some` and `Option.None` |
| 38 | +unless the definitions are "pulled out" with an import: |
| 39 | + |
| 40 | +```scala |
| 41 | +scala> Option.Some("hello") |
| 42 | +val res1: t2.Option[String] = Some(hello) |
| 43 | +scala> Option.None |
| 44 | +val res2: t2.Option[Nothing] = None |
| 45 | +``` |
| 46 | + |
| 47 | +Note that the type of the expressions above is always `Option`. That |
| 48 | +is, the implementation case classes are not visible in the result |
| 49 | +types of their `apply` methods. This is a subtle difference with |
| 50 | +respect to normal case classes. The classes making up the cases do |
| 51 | +exist, and can be unvealed by constructing them directly with a `new`. |
| 52 | + |
| 53 | +```scala |
| 54 | +val res3: t2.Option.Some[Int] = Some(2) |
| 55 | +scala> scala> new Option.Some(2) |
| 56 | +``` |
| 57 | + |
| 58 | + |
| 59 | + |
| 60 | + |
| 61 | + |
0 commit comments