Hacker News new | ask | show | jobs
by MuffinFlavored 2502 days ago
How does `yield` work under the hood? Does it add a reference to some array, with code to loop over all the references with some small timeout until the reference status changes from "pending" to "completed"?
2 comments

Generators do nothing unless you call their resume() method. resume moves the generator from the last state it was in to the next yield (or return).

Internally, when the code hits a yield, it's happening inside the resume method. yield works by saving the current state of the generator in the object (see e.g. resume_from in the post), and returning from resume().

It gets converted into a state machine.

  || {
    yield 2;
    yield 3;
    yield 5;
  }
will get converted to a struct that implements the Generator trait[1] with a resume method something like

  fn resume(self: Pin<&mut Self>) -> GeneratorState<i32, ()> {
    match self.next_state {
      0 => {
        self.next_state = 1;
        Yielded(2)
      },
      1 => {
        self.next_state = 2;
        Yielded(3)
      },
      2 => {
        self.next_state = 3;
        Yielded(5)
      },
      _ => Complete(())
    }
  }
Local variables become fields in the struct and if you have more complex control flow, the state could end up jumping around instead of just increasing by one each time. It's nothing that you couldn't write by hand, but it would be very tedious to do so.

[1] https://doc.rust-lang.org/beta/unstable-book/language-featur...

Just like for async, borrow across yield points here are a special feature that you couldn't implement in Rust as an open coded state machine, you'd have to find a workaround.