Skip to content

Commit ca7bb01

Browse files
committed
Some details about interactions with other features
1 parent 4146a83 commit ca7bb01

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

text/0000-gen-fn.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ gen fn odd_dup(values: impl Iterator<Item = u32>) -> u32 {
7676
}
7777
```
7878

79+
Iterators created with `gen` return `None` once they `return` (implicitly at the end of the scope or explicitly with `return`).
80+
See [#unresolved-questions] for whether `gen` iterators are fused or may behave strangely after having returned `None` once.
81+
Under no circumstances will it be undefined behavior if `next` is invoked again after having gotten a `None`.
82+
7983
# Guide-level explanation
8084
[guide-level-explanation]: #guide-level-explanation
8185

@@ -166,6 +170,10 @@ We'll probably be able to modularize the generator impl and make it more robust
166170

167171
It's another language feature for something that can already be written entirely in user code.
168172

173+
In contrast to `Generator`, `gen` blocks that produce `Iterator`s cannot hold references across `yield` points.
174+
See also https://doc.rust-lang.org/std/iter/fn.from_generator.html, which has an `Unpin` bound on the generator it takes
175+
to produce an `Iterator`.
176+
169177
# Rationale and alternatives
170178
[rationale-and-alternatives]: #rationale-and-alternatives
171179
## Keyword
@@ -191,6 +199,40 @@ that has very complex diagnostics that are hard to improve, even if it's nice on
191199
Users can use crates like [`genawaiter`](https://crates.io/crates/genawaiter) instead, which work on stable and give you `gen!` blocks that behave pretty mostly
192200
like `gen` blocks, but don't have compiler support for nice diagnostics or language support for the `?` operator.
193201

202+
## `return` statements `yield` one last element
203+
204+
Similarly to `try` blocks, trailing expresisons could yield their element.
205+
206+
But then have no way to terminate iteration, as `return` statements would similarly have to have a
207+
value that needs to get `yield`ed before terminating iteration.
208+
209+
We could do something magical where returning `()` terminates the iteration, so
210+
211+
```rust
212+
gen fn foo() -> i32 {
213+
42
214+
}
215+
```
216+
217+
could be a way to specify `std::iter::once(42)`. The issue I see with this is that
218+
219+
```rust
220+
gen fn foo() -> i32 {
221+
42; // note the semicolon
222+
}
223+
```
224+
225+
would then not return a value.
226+
227+
Furthermore this would make it unclear what the behaviour of
228+
229+
```rust
230+
gen fn foo() {}
231+
```
232+
233+
is supposed to be, as it could be either `std::iter::once(())` or `std::iter::empty::<()>()`
234+
235+
194236
# Prior art
195237
[prior-art]: #prior-art
196238

@@ -277,3 +319,22 @@ while `gen` blocks are the simpler concept that has no arguments and just captur
277319

278320
Either way, support for full `Generator`s should (in my opinion) be discussed and implemented separately,
279321
as there are many more open questions around them than around just a simpler way to write `Iterator`s.
322+
323+
## `async` interactions
324+
325+
We could support using `await` in `gen` blocks, similar to how we support `?` being used within them.
326+
This is not trivially possible due to the fact that `Iterator::next` takes `&mut self` and not `Pin<&mut self>`.
327+
328+
There are a few options forward for this:
329+
330+
* Add a separate trait for pinned iteration that is also usable with `gen` and `for`
331+
* downside: very similar traits for the same thing
332+
* backwards compatibly add a way to change the argument type of `Iterator::next`
333+
* downside: unclear if possible
334+
* implement `Iterator` for `Pin<&mut G>` instead of for `G` directly (whatever `G` is here, but it could be a `gen` block)
335+
* downside: the thing being iterated over must now be pinned for the entire iteration, instead of for each iteration
336+
337+
## `try` interactions
338+
339+
We could allow `try gen fn foo() -> i32` to actually mean something akin to `gen fn foo() -> Result<i32, E>`.
340+
Whatever we do here, it should mirror whatever `try fn` will mean in the future.

0 commit comments

Comments
 (0)