Hacker News new | ask | show | jobs
by anon4 4443 days ago
Yield and generators (i.e. save stack; return value to caller; receive value from caller) are really a language feature for writing a runtime for a different language with coroutines. Or if you're willing to write your program in a way that looks like it was generated by a source-to-source transformation tool, you can write your coroutines on top of them. The most basic construct is something like this:

  CurrentCoroutine = None


  def run(main, arg):
    global CurrentCoroutine
    CurrentCoroutine = main
    while CurrentCoroutine is not None
      CurrentCoroutine, arg = CurrentCoroutine.send(arg)


  def corodecorator(coro):
    @functools.wraps(coro):
    def init():
      c = coro()
      c.next()
      return c
    return init

And this is pretty much it. A simple example for two coroutines that pass control to each other would be:

  @corodecorator
  def coro1():
    # yield nothing on first call to receive args
    arg = yield None
    friend = arg[0]
    while True:
      print('coro1')
      arg = yield friend, (CurrentCoroutine,)
      friend = arg[0]


  @corodecorator
  def coro2():
    arg = yield None
    friend = arg[0]
    while True:
      print('coro2')
      arg = yield friend, (CurrentCoroutine,)
      friend = arg[0]


  run(coro1(), (coro2(),))

You can do the same with javascript and events, but it requires a much higher degree of masochism.