Skip to content

Commit 0cf8b51

Browse files
bishaboshasjrd
authored andcommitted
apply enums/adts.md
1 parent 51bbee0 commit 0cf8b51

File tree

3 files changed

+139
-173
lines changed

3 files changed

+139
-173
lines changed

docs/_spec/05-classes-and-objects.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,3 +801,52 @@ Generally, a _companion module_ of a class is an object which has the same name
801801
Conversely, the class is called the _companion class_ of the module.
802802

803803
Very much like a concrete class definition, an object definition may still contain declarations of abstract type members, but not of abstract term members.
804+
805+
## Enum Definitions
806+
807+
<!-- TODO: Agree with NTs of rest of spec -->
808+
```ebnf
809+
TmplDef ::= ‘enum’ EnumDef
810+
EnumDef ::= id ClassConstr [‘extends’ [ConstrApps]] EnumBody
811+
EnumBody ::= [nl] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
812+
EnumStat ::= TemplateStat
813+
| {Annotation [nl]} {Modifier} EnumCase
814+
```
815+
816+
### Enum Cases
817+
<!-- TODO: Agree with NTs of rest of spec -->
818+
```ebnf
819+
EnumCase ::= ‘case’ (id ClassConstr [‘extends’ ConstrApps] | ids)
820+
```
821+
822+
<!-- TODO: an enum case is defined in terms of other scala constructs... -->
823+
824+
### Variance for Type Parameters
825+
826+
A parameterized enum case ´C´ of enum ´E´ with _inferred_ type parameters will copy variance annotations.
827+
e.g. type parameter ´T_{i}´ from ´E´ will have the same variance as type parameter `´T'_{i}´` in ´C´.
828+
829+
###### Example
830+
831+
The following enum `View` has a contravariant type parameter ´T´ and a single case `Refl`, representing a function mapping a type `T` to itself:
832+
833+
```scala
834+
enum View[-´T´]:
835+
case Refl(f: ´T´ => ´T´)
836+
```
837+
838+
`Refl` expands to the following enum:
839+
840+
```scala
841+
enum View[-´T´]:
842+
case Refl[-´T'´](f: ´T'´ => ´T'´) extends View[´T'´]
843+
```
844+
845+
The definition of `Refl` is incorrectly typed, as it uses contravariant type `´T'´` in the covariant result position of a function type.
846+
847+
A correctly typed version would use an _explicit_, _invariant_ type parameter `´R´` on case `Refl`:
848+
849+
```scala
850+
enum View[-´T´]:
851+
case ReflR´](f: ´R´ => ´R´) extends ViewR´]
852+
```
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
---
2+
layout: doc-page
3+
title: "Algebraic Data Types"
4+
nightlyOf: https://docs.scala-lang.org/scala3/reference/enums/adts.html
5+
---
6+
7+
The [`enum` concept](./enums.md) is general enough to also support algebraic data types (ADTs) and their generalized version (GADTs).
8+
Here is an example how an `Option` type can be represented as an ADT:
9+
10+
```scala
11+
enum Option[+T]:
12+
case Some(x: T)
13+
case None
14+
```
15+
16+
This example introduces an `Option` enum with a covariant type parameter `T` consisting of two cases, `Some` and `None`.
17+
`Some` is parameterized with a value parameter `x`.
18+
It is a shorthand for writing a case class that extends `Option`.
19+
Since `None` is not parameterized, it is treated as a normal enum value.
20+
21+
The `extends` clauses that were omitted in the example above can also be given explicitly:
22+
23+
```scala
24+
enum Option[+T]:
25+
case Some(x: T) extends Option[T]
26+
case None extends Option[Nothing]
27+
```
28+
29+
Note that the parent type of the `None` value is inferred as `Option[Nothing]`.
30+
Generally, all covariant type parameters of the enum class are minimized in a compiler-generated `extends` clause whereas all contravariant type parameters are maximized.
31+
If `Option` was non-variant, you would need to give the extends clause of `None` explicitly.
32+
33+
As for normal enum values, the cases of an `enum` are all defined in the `enum`'s companion object.
34+
So it's `Option.Some` and `Option.None` unless the definitions are "pulled out" with an import.
35+
36+
37+
## Widening of Constructor Application
38+
39+
Observe here the inferred result types of the following expressions:
40+
```scala
41+
scala> Option.Some("hello")
42+
val res1: t2.Option[String] = Some(hello)
43+
44+
scala> Option.None
45+
val res2: t2.Option[Nothing] = None
46+
```
47+
48+
Note that the type of the expressions above is always `Option`.
49+
Generally, the type of a enum case constructor application will be widened to the underlying enum type, unless a more specific type is expected.
50+
This is a subtle difference with respect to normal case classes.
51+
The classes making up the cases do exist, and can be unveiled, either by constructing them directly with a `new`, or by explicitly providing an expected type.
52+
53+
```scala
54+
scala> new Option.Some(2)
55+
val res3: Option.Some[Int] = Some(2)
56+
scala> val x: Option.Some[Int] = Option.Some(3)
57+
val res4: Option.Some[Int] = Some(3)
58+
```
59+
60+
As all other enums, ADTs can define methods.
61+
For instance, here is `Option` again, with an `isDefined` method and an `Option(...)` constructor in its companion object.
62+
63+
```scala
64+
enum Option[+T]:
65+
case Some(x: T)
66+
case None
67+
68+
def isDefined: Boolean = this match
69+
case None => false
70+
case _ => true
71+
72+
object Option:
73+
74+
def apply[T >: Null](x: T): Option[T] =
75+
if x == null then None else Some(x)
76+
77+
end Option
78+
```
79+
80+
Enumerations and ADTs have been presented as two different concepts.
81+
But since they share the same syntactic construct, they can be seen simply as two ends of a spectrum and it is perfectly possible to construct hybrids.
82+
For instance, the code below gives an implementation of `Color` either with three enum values or with a parameterized case that takes an RGB value.
83+
84+
```scala
85+
enum Color(val rgb: Int):
86+
case Red extends Color(0xFF0000)
87+
case Green extends Color(0x00FF00)
88+
case Blue extends Color(0x0000FF)
89+
case Mix(mix: Int) extends Color(mix)
90+
```

docs/_spec/TODOreference/enums/adts.md

Lines changed: 0 additions & 173 deletions
This file was deleted.

0 commit comments

Comments
 (0)