Skip to content
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

Add a docs page for betterFors experimental feature #21784

Merged
merged 2 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions docs/_docs/reference/experimental/better-fors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
layout: doc-page
title: "Better fors"
nightlyOf: https://docs.scala-lang.org/scala3/reference/experimental/better-fors.html
---

The `betterFors` language extension improves the usability of `for`-comprehensions.

The extension is enabled by the language import `import scala.language.experimental.betterFors` or by setting the command line option `-language:experimental.betterFors`.

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:

```scala
for
as = List(1, 2, 3)
bs = List(4, 5, 6)
a <- as
b <- bs
yield a + b
```

The desugaring of this code is the same as if the aliases were introduced with `val`:

```scala
val as = List(1, 2, 3)
val bs = List(4, 5, 6)
for
a <- as
b <- bs
yield a + b
```

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:

1. **Simpler Desugaring for Pure Aliases**:
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.
**Current Desugaring**:
```scala
for {
a <- doSth(arg)
b = a
} yield a + b
```
Desugars to:
```scala
doSth(arg).map { a =>
val b = a
(a, b)
}.map { case (a, b) =>
a + b
}
```
**New Desugaring**:
```scala
doSth(arg).map { a =>
val b = a
a + b
}
```
This change makes the desugaring more intuitive and avoids unnecessary `map` calls, when an alias is not followed by a guard.

2. **Avoiding Redundant `map` Calls**:
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.
**Current Desugaring**:
```scala
for {
a <- List(1, 2, 3)
} yield a
```
Desugars to:
```scala
List(1, 2, 3).map(a => a)
```
**New Desugaring**:
```scala
List(1, 2, 3)
```

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).
1 change: 1 addition & 0 deletions docs/sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ subsection:
- page: reference/experimental/modularity.md
- page: reference/experimental/typeclasses.md
- page: reference/experimental/runtimeChecked.md
- page: reference/experimental/better-fors.md
- page: reference/syntax.md
- title: Language Versions
index: reference/language-versions/language-versions.md
Expand Down