Skip to content

Commit 3f3799a

Browse files
committed
Motivation and generators
1 parent 625826d commit 3f3799a

File tree

1 file changed

+34
-13
lines changed

1 file changed

+34
-13
lines changed

text/0000-gen-fn.md

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ Furthermore, add `gen fn` to the language. `gen fn foo(arg: X) -> Y` desugars to
1818
# Motivation
1919
[motivation]: #motivation
2020

21+
The main motivation of this RFC is to reserve a new keyword in the 2024 edition.
22+
The feature used by this keyword described here should be treated as an e-RFC for
23+
experimentation on nightly with this new keyword. I would like to avoid too much
24+
discussion of the semantics provided here, and instead discuss the semantics during
25+
the experimental implementation work.
26+
2127
Writing iterators manually can be very painful. Many iterators can be written by
2228
chaining `Iterator` methods, but some need to be written as a `struct` and have
2329
`Iterator` implemented for them. Some of the code that is written this way pushes
@@ -167,21 +173,13 @@ It's another language feature for something that can already be written entirely
167173
We could also use `iter` as a keyword. I would prefer `iter` in because I connect generators with a more powerful
168174
scheme than just plain `Iterator`s. The `Generator` trait can do everything that `iter` blocks and `async` blocks can do, and more. I believe connecting the `Iterator`
169175
trait with `iter` blocks is the right choice, but that would require us to carve out many exceptions for this keyword,
170-
as `iter` is used for module names and method names everywhere (including libstd/libcore).
171-
172-
## Contextual keyword
173-
174-
We allow `gen` as an identifier for function names and module names, without that conflicting with `gen` blocks, but that makes the syntax more complicated than necessary, for not too much gain.
176+
as `iter` is used for module names and method names everywhere (including libstd/libcore). It may not be much worse than `gen` (see also [#unresolved-questions])
175177

176178
## 2021 edition
177179

178180
We could allow `gen` blocks on the 2021 edition via `k#gen {}` syntax.
179181
We can allow `gen fn` on all editions.
180182

181-
## `gen` identifiers on 2024 edition
182-
183-
We can allow `i#gen` identifiers in the 2024 edition in order to refer to items named `gen` in previous edition crates.
184-
185183
## Do not do this
186184

187185
The alternative is to keep adding more helper methods to `Iterator`. It is already rather hard for new Rustaceans to get a hold of all the options they have on `Iterator`.
@@ -210,10 +208,6 @@ def odd_dup(values):
210208
# Unresolved questions
211209
[unresolved-questions]: #unresolved-questions
212210

213-
- What parts of the design do you expect to resolve through the RFC process before this gets merged?
214-
- What parts of the design do you expect to resolve through the implementation of this feature before stabilization?
215-
- What related issues do you consider out of scope for this RFC that could be addressed in the future independently of the solution that comes out of this RFC?
216-
217211
## Panicking
218212

219213
What happens when a `gen` block that panicked gets `next` called again? Do we need to poison the iterator?
@@ -222,6 +216,19 @@ What happens when a `gen` block that panicked gets `next` called again? Do we ne
222216

223217
Are `gen` blocks fused? Or may they behave eratically after returning `None` the first time?
224218

219+
## Contextual keyword
220+
221+
Popular crates (like `rand`) have methods called `gen` (https://docs.rs/rand/latest/rand/trait.Rng.html#method.gen). If we forbid those, we are forcing those crates to make a major version bump when they update their edition, and we are requiring any users of those crates to use `r#gen` instead of `gen` when calling that method.
222+
223+
We could instead choose to use a contextual keyword and only forbid
224+
225+
* bindings,
226+
* field names (due to destructuring bindings),
227+
* enum variants,
228+
* and type names
229+
230+
to be `gen`. This should avoid any parsing issues around `gen` followed by `{` in expressions.
231+
225232
# Future possibilities
226233
[future-possibilities]: #future-possibilities
227234

@@ -254,3 +261,17 @@ We could add a macro to the standard library and prelude, the macro would just e
254261
```rust
255262
yield_all!(iter)
256263
```
264+
265+
## Full on `Generator` support
266+
267+
We already have a `Generator` trait on nightly that is much more powerful than the `Iterator`
268+
API could possibly be.
269+
270+
1. it uses `Pin<&mut Self>`, allowing self-references in the generator across yield points
271+
2. it has arguments (`yield` returns the arguments passed to it in the subsequent invocations)
272+
273+
Similar (but def not the same) to ideas around `async` closures, I think we could argue for `Generators` to be `gen` closures,
274+
while `gen` blocks are the simpler concept that has no arguments and just captures variables.
275+
276+
Either way, support for full `Generator`s should (in my opinion) be discussed and implemented separately,
277+
as there are many more open questions around them than around just a simpler way to write `Iterator`s.

0 commit comments

Comments
 (0)