Skip to content

Commit 5a68b16

Browse files
committed
Add a docs page for betterFors experimental feature
1 parent f6bfa0a commit 5a68b16

File tree

1 file changed

+79
-0
lines changed

1 file changed

+79
-0
lines changed

Diff for: docs/_docs/reference/experimental/better-fors.md

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
---
2+
layout: doc-page
3+
title: "Better fors"
4+
nightlyOf: https://docs.scala-lang.org/scala3/reference/experimental/better-fors.html
5+
---
6+
7+
The `betterFors` language extension improves the usability of `for`-comprehensions.
8+
9+
The extension is enabled by the language import `import scala.language.experimental.betterFors` or by setting the command line option `-language:experimental.betterFors`.
10+
11+
The biggest user facing change is the new ability to start `for`-comprehensions with with aliases. This means that the following previously invalid code is now valid:
12+
13+
```scala
14+
for
15+
as = List(1, 2, 3)
16+
bs = List(4, 5, 6)
17+
a <- as
18+
b <- bs
19+
yield a + b
20+
```
21+
22+
The desugaring of this code is the same as if the aliases were introduced with `val`:
23+
24+
```scala
25+
val as = List(1, 2, 3)
26+
val bs = List(4, 5, 6)
27+
for
28+
a <- as
29+
b <- bs
30+
yield a + b
31+
```
32+
33+
Additionally this extension changes the way `for`-comprehensions are desugared. The desugaring is now done in a more intuitive way and the desugared code can be more efficient, because it avoids some unnecessary method calls. There are two main changes in the desugaring:
34+
35+
1. **Simpler Desugaring for Pure Aliases**:
36+
When an alias is not followed by a guard, the desugaring is simplified. The last generator and the aliases don't have to be wrapped in a tuple, and instead the aliases are simply introduced as local variables in a block with the next generator.
37+
**Current Desugaring**:
38+
```scala
39+
for {
40+
a <- doSth(arg)
41+
b = a
42+
} yield a + b
43+
```
44+
Desugars to:
45+
```scala
46+
doSth(arg).map { a =>
47+
val b = a
48+
(a, b)
49+
}.map { case (a, b) =>
50+
a + b
51+
}
52+
```
53+
**New Desugaring**:
54+
```scala
55+
doSth(arg).map { a =>
56+
val b = a
57+
a + b
58+
}
59+
```
60+
This change makes the desugaring more intuitive and avoids unnecessary `map` calls, when an alias is not followed by a guard.
61+
62+
2. **Avoiding Redundant `map` Calls**:
63+
When the result of the `for`-comprehension is the same expression as the last generator pattern, the desugaring avoids an unnecessary `map` call. but th eequality of the last pattern and the result has to be able to be checked syntactically, so it is either a variable or a tuple of variables.
64+
**Current Desugaring**:
65+
```scala
66+
for {
67+
a <- List(1, 2, 3)
68+
} yield a
69+
```
70+
Desugars to:
71+
```scala
72+
List(1, 2, 3).map(a => a)
73+
```
74+
**New Desugaring**:
75+
```scala
76+
List(1, 2, 3)
77+
```
78+
79+
For more details on the desugaring scheme see the comment in [`Desugar.scala#makeFor`](https://github.com/scala/scala3/blob/main/compiler/src/dotty/tools/dotc/ast/Desugar.scala#L1928).

0 commit comments

Comments
 (0)