Skip to content

Commit 8fab91c

Browse files
authored
Merge pull request #10923 from ShapelessCat/improve-docs
Improve docs
2 parents 08bb0bb + 215e04a commit 8fab91c

File tree

9 files changed

+181
-110
lines changed

9 files changed

+181
-110
lines changed

docs/docs/reference/changed-features/match-syntax.md

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,45 +6,47 @@ title: Match Expressions
66
The syntactical precedence of match expressions has been changed.
77
`match` is still a keyword, but it is used like an alphabetical operator. This has several consequences:
88

9-
1. `match` expressions can be chained:
9+
1. `match` expressions can be chained:
10+
11+
```scala
12+
xs match {
13+
case Nil => "empty"
14+
case x :: xs1 => "nonempty"
15+
} match {
16+
case "empty" => 0
17+
case "nonempty" => 1
18+
}
19+
```
20+
21+
(or, dropping the optional braces)
22+
23+
```scala
24+
xs match
25+
case Nil => "empty"
26+
case x :: xs1 => "nonempty"
27+
match
28+
case "empty" => 0
29+
case "nonempty" => 1
30+
```
31+
32+
2. `match` may follow a period:
1033

1134
```scala
12-
xs match {
13-
case Nil => "empty"
14-
case x :: xs1 => "nonempty"
15-
} match {
16-
case "empty" => 0
17-
case "nonempty" => 1
18-
}
35+
if xs.match
36+
case Nil => false
37+
case _ => true
38+
then "nonempty"
39+
else "empty"
1940
```
2041

21-
(or, dropping the optional braces)
22-
23-
```scala
24-
xs match
25-
case Nil => "empty"
26-
case x :: xs1 => "nonempty"
27-
match
28-
case "empty" => 0
29-
case "nonempty" => 1
30-
```
31-
32-
2. `match` may follow a period:
33-
34-
```scala
35-
if xs.match
36-
case Nil => false
37-
case _ => true
38-
then "nonempty"
39-
else "empty"
40-
```
41-
42-
3. The scrutinee of a match expression must be an `InfixExpr`. Previously the scrutinee could be followed by a type ascription `: T`, but this is no longer supported. So `x : T match { ... }` now has to be
43-
written `(x: T) match { ... }`.
42+
3. The scrutinee of a match expression must be an `InfixExpr`. Previously the scrutinee could be
43+
followed by a type ascription `: T`, but this is no longer supported. So `x : T match { ... }`
44+
now has to be written `(x: T) match { ... }`.
4445

4546
## Syntax
4647

4748
The new syntax of match expressions is as follows.
49+
4850
```
4951
InfixExpr ::= ...
5052
| InfixExpr MatchClause

docs/docs/reference/changed-features/numeric-literals.md

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,47 +24,54 @@ how large they can be.
2424

2525
The meaning of a numeric literal is determined as follows:
2626

27-
- If the literal ends with `l` or `L`, it is a `Long` integer (and must fit
28-
in its legal range).
29-
- If the literal ends with `f` or `F`, it is a single precision floating point number of type `Float`.
30-
- If the literal ends with `d` or `D`, it is a double precision floating point number of type `Double`.
27+
- If the literal ends with `l` or `L`, it is a `Long` integer (and must fit in its legal range).
28+
- If the literal ends with `f` or `F`, it is a single precision floating point number of type `Float`.
29+
- If the literal ends with `d` or `D`, it is a double precision floating point number of type `Double`.
3130

3231
In each of these cases the conversion to a number is exactly as in Scala 2 or in Java. If a numeric literal does _not_ end in one of these suffixes, its meaning is determined by the expected type:
3332

34-
1. If the expected type is `Int`, `Long`, `Float`, or `Double`, the literal is
33+
1. If the expected type is `Int`, `Long`, `Float`, or `Double`, the literal is
3534
treated as a standard literal of that type.
36-
2. If the expected type is a fully defined type `T` that has a given instance of type
35+
2. If the expected type is a fully defined type `T` that has a given instance of type
3736
`scala.util.FromDigits[T]`, the literal is converted to a value of type `T` by passing it as an argument to
3837
the `fromDigits` method of that instance (more details below).
39-
3. Otherwise, the literal is treated as a `Double` literal (if it has a decimal point or an
38+
3. Otherwise, the literal is treated as a `Double` literal (if it has a decimal point or an
4039
exponent), or as an `Int` literal (if not). (This last possibility is again as in Scala 2 or Java.)
4140

4241
With these rules, the definition
42+
4343
```scala
4444
val x: Long = -10_000_000_000
4545
```
46+
4647
is legal by rule (1), since the expected type is `Long`. The definitions
48+
4749
```scala
4850
val y: BigInt = 0x123_abc_789_def_345_678_901
4951
val z: BigDecimal = 111222333444.55
5052
```
53+
5154
are legal by rule (2), since both `BigInt` and `BigDecimal` have `FromDigits` instances
5255
(which implement the `FromDigits` subclasses `FromDigits.WithRadix` and `FromDigits.Decimal`, respectively).
5356
On the other hand,
57+
5458
```scala
5559
val x = -10_000_000_000
5660
```
61+
5762
gives a type error, since without an expected type `-10_000_000_000` is treated by rule (3) as an `Int` literal, but it is too large for that type.
5863

5964
### The FromDigits Trait
6065

6166
To allow numeric literals, a type simply has to define a `given` instance of the
6267
`scala.util.FromDigits` type class, or one of its subclasses. `FromDigits` is defined
6368
as follows:
69+
6470
```scala
6571
trait FromDigits[T]:
6672
def fromDigits(digits: String): T
6773
```
74+
6875
Implementations of the `fromDigits` convert strings of digits to the values of the
6976
implementation type `T`.
7077
The `digits` string consists of digits between `0` and `9`, possibly preceded by a
@@ -74,6 +81,7 @@ the string is passed to `fromDigits`.
7481
The companion object `FromDigits` also defines subclasses of `FromDigits` for
7582
whole numbers with a given radix, for numbers with a decimal point, and for
7683
numbers that can have both a decimal point and an exponent:
84+
7785
```scala
7886
object FromDigits:
7987

@@ -95,6 +103,7 @@ object FromDigits:
95103
*/
96104
trait Floating[T] extends Decimal[T]
97105
```
106+
98107
A user-defined number type can implement one of those, which signals to the compiler
99108
that hexadecimal numbers, decimal points, or exponents are also accepted in literals
100109
for this type.
@@ -104,6 +113,7 @@ for this type.
104113
`FromDigits` implementations can signal errors by throwing exceptions of some subtype
105114
of `FromDigitsException`. `FromDigitsException` is defined with three subclasses in the
106115
`FromDigits` object as follows:
116+
107117
```scala
108118
abstract class FromDigitsException(msg: String) extends NumberFormatException(msg)
109119

@@ -115,17 +125,22 @@ class MalformedNumber(msg: String = "malformed number literal") extends FromDigi
115125
### Example
116126

117127
As a fully worked out example, here is an implementation of a new numeric class, `BigFloat`, that accepts numeric literals. `BigFloat` is defined in terms of a `BigInt` mantissa and an `Int` exponent:
128+
118129
```scala
119130
case class BigFloat(mantissa: BigInt, exponent: Int):
120131
override def toString = s"${mantissa}e${exponent}"
121132
```
133+
122134
`BigFloat` literals can have a decimal point as well as an exponent. E.g. the following expression
123135
should produce the `BigFloat` number `BigFloat(-123, 997)`:
136+
124137
```scala
125138
-0.123E+1000: BigFloat
126139
```
140+
127141
The companion object of `BigFloat` defines an `apply` constructor method to construct a `BigFloat`
128142
from a `digits` string. Here is a possible implementation:
143+
129144
```scala
130145
object BigFloat:
131146
import scala.util.FromDigits
@@ -149,13 +164,16 @@ object BigFloat:
149164
(intPart, givenExponent)
150165
BigFloat(BigInt(intPart), exponent)
151166
```
167+
152168
To accept `BigFloat` literals, all that's needed in addition is a `given` instance of type
153169
`FromDigits.Floating[BigFloat]`:
170+
154171
```scala
155172
given FromDigits: FromDigits.Floating[BigFloat] with
156173
def fromDigits(digits: String) = apply(digits)
157174
end BigFloat
158175
```
176+
159177
Note that the `apply` method does not check the format of the `digits` argument. It is
160178
assumed that only valid arguments are passed. For calls coming from the compiler
161179
that assumption is valid, since the compiler will first check whether a numeric
@@ -164,35 +182,42 @@ literal has the correct format before it gets passed on to a conversion method.
164182
### Compile-Time Errors
165183

166184
With the setup of the previous section, a literal like
185+
167186
```scala
168187
1e10_0000_000_000: BigFloat
169188
```
189+
170190
would be expanded by the compiler to
191+
171192
```scala
172193
BigFloat.FromDigits.fromDigits("1e100000000000")
173194
```
195+
174196
Evaluating this expression throws a `NumberTooLarge` exception at run time. We would like it to
175197
produce a compile-time error instead. We can achieve this by tweaking the `BigFloat` class
176198
with a small dose of metaprogramming. The idea is to turn the `fromDigits` method
177199
into a macro, i.e. make it an inline method with a splice as right hand side.
178200
To do this, replace the `FromDigits` instance in the `BigFloat` object by the following two definitions:
201+
179202
```scala
180203
object BigFloat:
181204
...
182205

183206
class FromDigits extends FromDigits.Floating[BigFloat]:
184207
def fromDigits(digits: String) = apply(digits)
185208

186-
given FromDigits:
209+
given FromDigits with
187210
override inline def fromDigits(digits: String) = ${
188211
fromDigitsImpl('digits)
189212
}
190213
```
214+
191215
Note that an inline method cannot directly fill in for an abstract method, since it produces
192216
no code that can be executed at runtime. That is why we define an intermediary class
193217
`FromDigits` that contains a fallback implementation which is then overridden by the inline
194218
method in the `FromDigits` given instance. That method is defined in terms of a macro
195219
implementation method `fromDigitsImpl`. Here is its definition:
220+
196221
```scala
197222
private def fromDigitsImpl(digits: Expr[String])(using ctx: Quotes): Expr[BigFloat] =
198223
digits.value match
@@ -207,6 +232,7 @@ implementation method `fromDigitsImpl`. Here is its definition:
207232
'{apply($digits)}
208233
end BigFloat
209234
```
235+
210236
The macro implementation takes an argument of type `Expr[String]` and yields
211237
a result of type `Expr[BigFloat]`. It tests whether its argument is a constant
212238
string. If that is the case, it converts the string using the `apply` method
@@ -218,10 +244,13 @@ The interesting part is the `catch` part of the case where `digits` is constant.
218244
If the `apply` method throws a `FromDigitsException`, the exception's message is issued as a compile time error in the `ctx.error(ex.getMessage)` call.
219245

220246
With this new implementation, a definition like
247+
221248
```scala
222249
val x: BigFloat = 1234.45e3333333333
223250
```
251+
224252
would give a compile time error message:
253+
225254
```scala
226255
3 | val x: BigFloat = 1234.45e3333333333
227256
| ^^^^^^^^^^^^^^^^^^

docs/docs/reference/contextual/derivation.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ Note the following properties of `Mirror` types,
123123
+ Properties are encoded using types rather than terms. This means that they have no runtime footprint unless used and
124124
also that they are a compile time feature for use with Scala 3's metaprogramming facilities.
125125
+ The kinds of `MirroredType` and `MirroredElemTypes` match the kind of the data type the mirror is an instance for.
126-
This allows `Mirrors` to support ADTs of all kinds.
126+
This allows `Mirror`s to support ADTs of all kinds.
127127
+ There is no distinct representation type for sums or products (ie. there is no `HList` or `Coproduct` type as in
128128
Scala 2 versions of Shapeless). Instead the collection of child types of a data type is represented by an ordinary,
129129
possibly parameterized, tuple type. Scala 3's metaprogramming facilities can be used to work with these tuple types
@@ -167,7 +167,6 @@ The low-level method we will use to implement a type class `derived` method in t
167167
type-level constructs in Scala 3: inline methods, inline matches, and implicit searches via `summonInline` or `summonFrom`. Given this definition of the
168168
`Eq` type class,
169169

170-
171170
```scala
172171
trait Eq[T]:
173172
def eqv(x: T, y: T): Boolean
@@ -194,7 +193,6 @@ implementation of `summonAll` is `inline` and uses Scala 3's `summonInline` cons
194193
`List`,
195194

196195
```scala
197-
198196
inline def summonAll[T <: Tuple]: List[Eq[_]] =
199197
inline erasedValue[T] match
200198
case _: EmptyTuple => Nil
@@ -297,7 +295,7 @@ given derived$Eq[T](using eqT: Eq[T]): Eq[Opt[T]] =
297295
eqSum(
298296
summon[Mirror[Opt[T]]],
299297
List(
300-
eqProduct(summon[Mirror[Sm[T]]], List(summon[Eq[T]]))
298+
eqProduct(summon[Mirror[Sm[T]]], List(summon[Eq[T]])),
301299
eqProduct(summon[Mirror[Nn.type]], Nil)
302300
)
303301
)
@@ -357,10 +355,13 @@ ConstrApps ::= ConstrApp {‘with’ ConstrApp}
357355

358356
Note: To align `extends` clauses and `derives` clauses, Scala 3 also allows multiple
359357
extended types to be separated by commas. So the following is now legal:
358+
360359
```scala
361360
class A extends B, C { ... }
362361
```
362+
363363
It is equivalent to the old form
364+
364365
```scala
365366
class A extends B with C { ... }
366367
```

0 commit comments

Comments
 (0)