]> git.lizzy.rs Git - rust.git/blob - src/doc/unstable-book/src/language-features/generators.md
Closures implement Copy and Clone, generators don't
[rust.git] / src / doc / unstable-book / src / language-features / generators.md
1 # `generators`
2
3 The tracking issue for this feature is: [#43122]
4
5 [#43122]: https://github.com/rust-lang/rust/issues/43122
6
7 ------------------------
8
9 The `generators` feature gate in Rust allows you to define generator or
10 coroutine literals. A generator is a "resumable function" that syntactically
11 resembles a closure but compiles to much different semantics in the compiler
12 itself. The primary feature of a generator is that it can be suspended during
13 execution to be resumed at a later date. Generators use the `yield` keyword to
14 "return", and then the caller can `resume` a generator to resume execution just
15 after the `yield` keyword.
16
17 Generators are an extra-unstable feature in the compiler right now. Added in
18 [RFC 2033] they're mostly intended right now as a information/constraint
19 gathering phase. The intent is that experimentation can happen on the nightly
20 compiler before actual stabilization. A further RFC will be required to
21 stabilize generators/coroutines and will likely contain at least a few small
22 tweaks to the overall design.
23
24 [RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033
25
26 A syntactical example of a generator is:
27
28 ```rust
29 #![feature(generators, generator_trait)]
30
31 use std::ops::{Generator, GeneratorState};
32 use std::pin::Pin;
33
34 fn main() {
35     let mut generator = || {
36         yield 1;
37         return "foo"
38     };
39
40     match Pin::new(&mut generator).resume() {
41         GeneratorState::Yielded(1) => {}
42         _ => panic!("unexpected value from resume"),
43     }
44     match Pin::new(&mut generator).resume() {
45         GeneratorState::Complete("foo") => {}
46         _ => panic!("unexpected value from resume"),
47     }
48 }
49 ```
50
51 Generators are closure-like literals which can contain a `yield` statement. The
52 `yield` statement takes an optional expression of a value to yield out of the
53 generator. All generator literals implement the `Generator` trait in the
54 `std::ops` module. The `Generator` trait has one main method, `resume`, which
55 resumes execution of the generator at the previous suspension point.
56
57 An example of the control flow of generators is that the following example
58 prints all numbers in order:
59
60 ```rust
61 #![feature(generators, generator_trait)]
62
63 use std::ops::Generator;
64 use std::pin::Pin;
65
66 fn main() {
67     let mut generator = || {
68         println!("2");
69         yield;
70         println!("4");
71     };
72
73     println!("1");
74     Pin::new(&mut generator).resume();
75     println!("3");
76     Pin::new(&mut generator).resume();
77     println!("5");
78 }
79 ```
80
81 At this time the main intended use case of generators is an implementation
82 primitive for async/await syntax, but generators will likely be extended to
83 ergonomic implementations of iterators and other primitives in the future.
84 Feedback on the design and usage is always appreciated!
85
86 ### The `Generator` trait
87
88 The `Generator` trait in `std::ops` currently looks like:
89
90 ```
91 # #![feature(arbitrary_self_types, generator_trait)]
92 # use std::ops::GeneratorState;
93 # use std::pin::Pin;
94
95 pub trait Generator {
96     type Yield;
97     type Return;
98     fn resume(self: Pin<&mut Self>) -> GeneratorState<Self::Yield, Self::Return>;
99 }
100 ```
101
102 The `Generator::Yield` type is the type of values that can be yielded with the
103 `yield` statement. The `Generator::Return` type is the returned type of the
104 generator. This is typically the last expression in a generator's definition or
105 any value passed to `return` in a generator. The `resume` function is the entry
106 point for executing the `Generator` itself.
107
108 The return value of `resume`, `GeneratorState`, looks like:
109
110 ```
111 pub enum GeneratorState<Y, R> {
112     Yielded(Y),
113     Complete(R),
114 }
115 ```
116
117 The `Yielded` variant indicates that the generator can later be resumed. This
118 corresponds to a `yield` point in a generator. The `Complete` variant indicates
119 that the generator is complete and cannot be resumed again. Calling `resume`
120 after a generator has returned `Complete` will likely result in a panic of the
121 program.
122
123 ### Closure-like semantics
124
125 The closure-like syntax for generators alludes to the fact that they also have
126 closure-like semantics. Namely:
127
128 * When created, a generator executes no code. A closure literal does not
129   actually execute any of the closure's code on construction, and similarly a
130   generator literal does not execute any code inside the generator when
131   constructed.
132
133 * Generators can capture outer variables by reference or by move, and this can
134   be tweaked with the `move` keyword at the beginning of the closure. Like
135   closures all generators will have an implicit environment which is inferred by
136   the compiler. Outer variables can be moved into a generator for use as the
137   generator progresses.
138
139 * Generator literals produce a value with a unique type which implements the
140   `std::ops::Generator` trait. This allows actual execution of the generator
141   through the `Generator::resume` method as well as also naming it in return
142   types and such.
143
144 * Traits like `Send` and `Sync` are automatically implemented for a `Generator`
145   depending on the captured variables of the environment. Unlike closures,
146   generators also depend on variables live across suspension points. This means
147   that although the ambient environment may be `Send` or `Sync`, the generator
148   itself may not be due to internal variables live across `yield` points being
149   not-`Send` or not-`Sync`. Note that generators do
150   not implement traits like `Copy` or `Clone` automatically.
151
152 * Whenever a generator is dropped it will drop all captured environment
153   variables.
154
155 Note that unlike closures, generators at this time cannot take any arguments.
156 That is, generators must always look like `|| { ... }`. This restriction may be
157 lifted at a future date, the design is ongoing!
158
159 ### Generators as state machines
160
161 In the compiler, generators are currently compiled as state machines. Each
162 `yield` expression will correspond to a different state that stores all live
163 variables over that suspension point. Resumption of a generator will dispatch on
164 the current state and then execute internally until a `yield` is reached, at
165 which point all state is saved off in the generator and a value is returned.
166
167 Let's take a look at an example to see what's going on here:
168
169 ```rust
170 #![feature(generators, generator_trait)]
171
172 use std::ops::Generator;
173 use std::pin::Pin;
174
175 fn main() {
176     let ret = "foo";
177     let mut generator = move || {
178         yield 1;
179         return ret
180     };
181
182     Pin::new(&mut generator).resume();
183     Pin::new(&mut generator).resume();
184 }
185 ```
186
187 This generator literal will compile down to something similar to:
188
189 ```rust
190 #![feature(arbitrary_self_types, generators, generator_trait)]
191
192 use std::ops::{Generator, GeneratorState};
193 use std::pin::Pin;
194
195 fn main() {
196     let ret = "foo";
197     let mut generator = {
198         enum __Generator {
199             Start(&'static str),
200             Yield1(&'static str),
201             Done,
202         }
203
204         impl Generator for __Generator {
205             type Yield = i32;
206             type Return = &'static str;
207
208             fn resume(mut self: Pin<&mut Self>) -> GeneratorState<i32, &'static str> {
209                 use std::mem;
210                 match mem::replace(&mut *self, __Generator::Done) {
211                     __Generator::Start(s) => {
212                         *self = __Generator::Yield1(s);
213                         GeneratorState::Yielded(1)
214                     }
215
216                     __Generator::Yield1(s) => {
217                         *self = __Generator::Done;
218                         GeneratorState::Complete(s)
219                     }
220
221                     __Generator::Done => {
222                         panic!("generator resumed after completion")
223                     }
224                 }
225             }
226         }
227
228         __Generator::Start(ret)
229     };
230
231     Pin::new(&mut generator).resume();
232     Pin::new(&mut generator).resume();
233 }
234 ```
235
236 Notably here we can see that the compiler is generating a fresh type,
237 `__Generator` in this case. This type has a number of states (represented here
238 as an `enum`) corresponding to each of the conceptual states of the generator.
239 At the beginning we're closing over our outer variable `foo` and then that
240 variable is also live over the `yield` point, so it's stored in both states.
241
242 When the generator starts it'll immediately yield 1, but it saves off its state
243 just before it does so indicating that it has reached the yield point. Upon
244 resuming again we'll execute the `return ret` which returns the `Complete`
245 state.
246
247 Here we can also note that the `Done` state, if resumed, panics immediately as
248 it's invalid to resume a completed generator. It's also worth noting that this
249 is just a rough desugaring, not a normative specification for what the compiler
250 does.