-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Reference sections for some of the new things in Dotty #2498
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
000dce1
Implicit By Name Parameters section
odersky 554bbb7
Add test code
odersky 9954e81
Fix indentation
odersky 834674f
Add scala syntax highlighting
odersky 7f64c57
Better type inference for new
odersky abe87a8
Don't infer final classes as parents for anonymous new
odersky a36b052
Section on enumerations
odersky a15570a
More info on enum implementation
odersky 1b81d00
Fix problem with parameterized enums
odersky aa292d7
Add test file
odersky 5244d76
Section on ADTs
odersky def3bcf
More ADT material
odersky eda79d9
Fix reference tests
odersky 15418c5
Add section on enum translation
odersky a3f0b22
Add syntax section for adts and enums
odersky 7aba3c5
Address reviewer comments
odersky bf34e85
Section on trait parameters
odersky 76bc34b
Fix typo
odersky c6b458b
Add reference to sidebar
odersky 77db6bd
Add titles
odersky c6c27f6
Add section in intersection types
odersky 1a901ec
Add sectionon union types
odersky 20e681b
Fix typo
odersky 8d750a1
Add reference to index
felixmulder 8013ea4
Fixup markup in union-types
felixmulder File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
--- | ||
layout: doc-page | ||
title: "Algebraic Data Types" | ||
--- | ||
|
||
|
||
The `enum` concept is general enough to also support algebraic data | ||
types (ADTs) and their generalized version (GADTs). Here's an example | ||
how an `Option` type can be represented as an ADT: | ||
|
||
```scala | ||
enum Option[+T] { | ||
case Some[+T](x: T) | ||
case None | ||
} | ||
``` | ||
|
||
This example introduces `Option` enum class with a covariant type | ||
parameter `T`, together with two cases, `Some` and `None`. `Some` is | ||
parameterized with a type parameter `T` and a value parameter `x`. It | ||
is a shorthand for writing a case class that extends `Option`. Since | ||
`None` is not parameterized it is treated as a normal enum value. | ||
|
||
The `extends` clauses that were omitted in the example above can also | ||
be given explicitly: | ||
|
||
```scala | ||
enum Option[+T] { | ||
case Some[+T](x: T) extends Option[T] | ||
case None extends Option[Nothing] | ||
} | ||
``` | ||
|
||
Note that the parent type of `None` is inferred as | ||
`Option[Nothing]`. Generally, all covariant type parameters of the enum | ||
class are minimized in a compiler-generated extends clause whereas all | ||
contravariant type parameters are maximized. If `Option` was non-variant, | ||
you'd need to give the extends clause of `None` explicitly. | ||
|
||
As for normal enum values, the cases of an `enum` are all defined in | ||
the `enum`s companion object. So it's `Option.Some` and `Option.None` | ||
unless the definitions are "pulled out" with an import: | ||
|
||
```scala | ||
scala> Option.Some("hello") | ||
val res1: t2.Option[String] = Some(hello) | ||
scala> Option.None | ||
val res2: t2.Option[Nothing] = None | ||
``` | ||
|
||
Note that the type of the expressions above is always `Option`. That | ||
is, the implementation case classes are not visible in the result | ||
types of their `apply` methods. This is a subtle difference with | ||
respect to normal case classes. The classes making up the cases do | ||
exist, and can be unvealed by constructing them directly with a `new`. | ||
|
||
```scala | ||
val res3: t2.Option.Some[Int] = Some(2) | ||
scala> scala> new Option.Some(2) | ||
``` | ||
|
||
As all other enums, ADTs can have methods on both the enum class and | ||
its companion object. For instance, here is `Option` again, with an | ||
`isDefined` method and an `Option(...)` constructor. | ||
|
||
```scala | ||
enum class Option[+T] { | ||
def isDefined: Boolean | ||
} | ||
object Option { | ||
def apply[T >: Null](x: T): Option[T] = | ||
if (x == null) None else Some(x) | ||
|
||
case Some[+T](x: T) { | ||
def isDefined = true | ||
} | ||
case None { | ||
def isDefined = false | ||
} | ||
} | ||
``` | ||
|
||
Enumerations and ADTs have been presented as two different | ||
concepts. 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 conctruct hybrids. 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. | ||
|
||
```scala | ||
enum Color(val rgb: Int) { | ||
case Red extends Color(0xFF0000) | ||
case Green extends Color(0x00FF00) | ||
case Blue extends Color(0x0000FF) | ||
case Mix(mix: Int) extends Color(mix) | ||
} | ||
``` | ||
|
||
## Syntax of Enums | ||
|
||
Changes to the syntax fall in two categories: enum classes and cases inside enums. | ||
The changes are specified below as deltas with respect to the Scala syntax given [here](https://github.com/lampepfl/dotty/blob/master/docs/docs/internals/syntax.md) | ||
|
||
1. Enum definitions and enum classes are defined as follows: | ||
|
||
TmplDef ::= `enum' `class’ ClassDef | ||
| `enum' EnumDef | ||
EnumDef ::= id ClassConstr [`extends' [ConstrApps]] | ||
[nl] `{’ EnumCaseStat {semi EnumCaseStat} `}’ | ||
|
||
2. Cases of enums are defined as follows: | ||
|
||
EnumCaseStat ::= {Annotation [nl]} {Modifier} EnumCase | ||
EnumCase ::= `case' (EnumClassDef | ObjectDef | ids) | ||
EnumClassDef ::= id [ClsTpeParamClause | ClsParamClause] | ||
ClsParamClauses TemplateOpt | ||
TemplateStat ::= ... | EnumCaseStat | ||
|
||
|
||
|
||
|
||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
--- | ||
layout: doc-page | ||
title: "Translation of Enums and ADTs" | ||
--- | ||
|
||
The compiler expands enum classes and cases to code that only uses | ||
Scala's other language features. As such, enums in Scala are | ||
convenient _syntactic sugar_, but they are not essential to understand | ||
Scala's core. | ||
|
||
We now explain the expansion of enums is explained in detail. First, | ||
some terminology and notational conventions: | ||
|
||
- 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`. | ||
- 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. | ||
|
||
- Enum cases fall into three categories: | ||
|
||
- _Class cases_ are those cases that are parameterized, either with a type parameter section `[...]` or with one or more (possibly empty) parameter sections `(...)`. | ||
- _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. | ||
- _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. | ||
|
||
Simple cases and value cases are called collectively _singleton cases_. | ||
|
||
The desugaring rules imply that class cases are mapped to case classes, and singleton cases are mapped to `val` definitions. | ||
|
||
There are eight desugaring rules. Rules (1) and (2) desugar enums and | ||
enum classes. Rules (3) and (4) define extends clauses for cases that | ||
are missing them. Rules (5 - 7) define how such expanded cases map | ||
into case classes, case objects or vals. Finally, rule (8) expands | ||
comma separated simple cases into a sequence of cases. | ||
|
||
1. An `enum` definition | ||
|
||
enum E ... { <cases> } | ||
|
||
expands to an enum class and a companion object | ||
|
||
enum class E ... | ||
object E { <cases> } | ||
|
||
2. An enum class definition | ||
|
||
enum class E ... extends <parents> ... | ||
|
||
expands to a `sealed` `abstract` class that extends the `scala.Enum` trait: | ||
|
||
sealed abstract class E ... extends <parents> with scala.Enum ... | ||
|
||
3. If `E` is an enum class without type parameters, then a case in its companion object without an extends clause | ||
|
||
case C <params> <body> | ||
|
||
expands to | ||
|
||
case C <params> <body> extends E | ||
|
||
4. If `E` is an enum class with type parameters `Ts`, then a case in its | ||
companion object without an extends clause | ||
|
||
case C <params> <body> | ||
|
||
expands according to two alternatives, depending whether `C` has type | ||
parameters or not. If `C` has type parameters, they must have the same | ||
names and appear in the same order as the enum type parameters `Ts` | ||
(variances may be different, however). In this case | ||
|
||
case C [Ts] <params> <body> | ||
|
||
expands to | ||
|
||
case C[Ts] <params> extends E[Ts] <body> | ||
|
||
For the case where `C` does not have type parameters, assume `E`'s type | ||
parameters are | ||
|
||
V1 T1 > L1 <: U1 , ... , Vn Tn >: Ln <: Un (n > 0) | ||
|
||
where each of the variances `Vi` is either `'+'` or `'-'`. Then the case | ||
expands to | ||
|
||
case C <params> extends E[B1, ..., Bn] <body> | ||
|
||
where `Bi` is `Li` if `Vi = '+'` and `Ui` if `Vi = '-'`. It is an error if | ||
`Bi` refers to some other type parameter `Tj (j = 0,..,n-1)`. It is also | ||
an error if `E` has type parameters that are non-variant. | ||
|
||
5. A class case | ||
|
||
case C <params> ... | ||
|
||
expands analogous to a case class: | ||
|
||
final case class C <params> ... | ||
|
||
However, unlike for a regular case class, the return type of the associated | ||
`apply` method is a fully parameterized type instance of the enum class `E` | ||
itself instead of `C`. Also the enum case defines an `enumTag` method of | ||
the form | ||
|
||
def enumTag = n | ||
|
||
where `n` is the ordinal number of the case in the companion object, | ||
starting from 0. | ||
|
||
6. A value case | ||
|
||
case C extends <parents> <body> | ||
|
||
expands to a value definition | ||
|
||
val C = new <parents> { <body>; def enumTag = n; $values.register(this) } | ||
|
||
where `n` is the ordinal number of the case in the companion object, | ||
starting from 0. The statement `$values.register(this)` registers the value | ||
as one of the `enumValues` of the enumeration (see below). `$values` is a | ||
compiler-defined private value in the companion object. | ||
|
||
7. A simple case | ||
|
||
case C | ||
|
||
of an enum class `E` that does not take type parameters expands to | ||
|
||
val C = $new(n, "C") | ||
|
||
Here, `$new` is a private method that creates an instance of of `E` (see | ||
below). | ||
|
||
8. A simple case consisting of a comma-separated list of enum names | ||
|
||
case C_1, ..., C_n | ||
|
||
expands to | ||
|
||
case C_1; ...; case C_n | ||
|
||
Any modifiers or annotations on the original case extend to all expanded | ||
cases. | ||
|
||
## Translation of Enumerations | ||
|
||
Non-generic enum classes `E` that define one or more singleton cases | ||
are called _enumerations_. Companion objects of enumerations define | ||
the following additional members. | ||
|
||
- A method `enumValue` of type `scala.collection.immutable.Map[Int, E]`. | ||
`enumValue(n)` returns the singleton case value with ordinal number `n`. | ||
- A method `enumValueNamed` of type `scala.collection.immutable.Map[String, E]`. | ||
`enumValueNamed(s)` returns the singleton case value whose `toString` | ||
representation is `s`. | ||
- A method `enumValues` which returns an `Iterable[E]` of all singleton case | ||
values in `E`, in the order of their definitions. | ||
|
||
Companion objects that contain at least one simple case define in addition: | ||
|
||
- A private method `$new` which defines a new simple case value with given | ||
ordinal number and name. This method can be thought as being defined as | ||
follows. | ||
|
||
def $new(tag: Int, name: String): ET = new E { | ||
def enumTag = tag | ||
def toString = name | ||
$values.register(this) // register enum value so that `valueOf` and `values` can return it. | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be TemplateOpt or the above line be TemplateStat