GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Document multi-shot generators · Issue #80 · Technologicat/unpythonic

Document multi-shot generators #80

New issue
Copy link
New issue
Copy link
Closed
Closed
Document multi-shot generators#80
Copy link
Assignees
Technologicat
Labels
documentationNon-executable English, for humansNon-executable English, for humansenhancementNew feature or requestNew feature or request
Milestone
2.2.0

Description

@Technologicat
Technologicat
opened on Jun 23, 2021
Issue body actions

As of v0.15.0, there is a toy implementation of multi-shot generators (i.e. re-resumable generators) buried within the automated tests, see unpythonic.syntax.tests.test_conts_gen.

Playing around with the idea, multi-shot generators seem a much nicer API to use continuations with than the low-level call_cc[].

Thus, we could extract it into a proper mcpyrate macro, and add it to the public macro API.

We should caution in the docs that it'll only work inside a with continuations block, since doing things like this in Python requires a CPS conversion. Or maybe make this another, alternative multi-shot-continuations API, and internally compile into a with continuations.

This requires first fleshing out some details. Ideally, a multi-shot generator should look similar to a classical Python generator, with only the difference that a multi-shot generator can resume again from an earlier yield (arbitrarily many times).

Activity

  1. Technologicat
    added
    enhancementNew feature or requestNew feature or request
    on Jun 23, 2021
  2. Technologicat
    added this to the 0.15.x milestone on Jun 23, 2021
  3. Technologicat
    modified the milestones: 0.15.x, 0.15.2 on Jan 28, 2022
  4. Technologicat commented on Jan 28, 2022

    @Technologicat
    Technologicat
    on Jan 28, 2022
    OwnerAuthor
    More actions

    Supporting all of the generator API is a large project, so maybe just implement the very basics, showing how it could be done.

    With the new get_cc function in 0.15.1, and the multi-phase compiler in mcpyrate, we can write a lot cleaner demo than what was possible before.

    So, let's include such a short demo in 0.15.2.

  5. Technologicat
    added a commit that references this issue on Jan 28, 2022

    example of multishot generators using pattern `k = call_cc[get_cc()]`

    f18a34b
  6. Technologicat commented on Jan 30, 2022

    @Technologicat
    Technologicat
    on Jan 30, 2022
    OwnerAuthor
    More actions

    Example moved into unpythonic.syntax.tests.test_conts_multishot.

  7. Technologicat
    self-assigned this
    on Jan 30, 2022
  8. Technologicat commented on Jan 31, 2022

    @Technologicat
    Technologicat
    on Jan 31, 2022
    OwnerAuthor
    More actions

    Now we just need to update the documentation, particularly the section on continuations in doc/macros.md.

    • Document get_cc and the pattern k = call_cc[get_cc()]. Material exists in the docstring of get_cc.
    • Document how to use this pattern to make multi-shot generators. Refer to unpythonic.syntax.tests.test_conts_multishot, which demonstrates this and packages it into a @multishot decorator macro, which can be used lexically inside a with continuations block.
  9. Technologicat
    added
    documentationNon-executable English, for humansNon-executable English, for humans
    on Jan 31, 2022
  10. Technologicat
    added a commit that references this issue on Jan 31, 2022

    improve multi-shot generators

    dbd1ba4
  11. Technologicat commented on Jan 31, 2022

    @Technologicat
    Technologicat
    on Jan 31, 2022
    OwnerAuthor
    More actions

    Now the demo includes also a MultishotIterator that shows how to make a @multishot multi-shot generator conform to the most often used parts of Python's generator API.

  12. Technologicat
    modified the milestones: 0.15.2, 0.15.3 on Sep 26, 2024
  13. Technologicat
    changed the title [-]Add multi-shot generators[/-] [+]Document multi-shot generators[/+] on Sep 26, 2024
  14. Technologicat
    modified the milestones: 0.15.3, 0.15.x, 0.15.4 on Sep 26, 2024
  15. Technologicat
    modified the milestones: 1.1.0, 2.1.0 on Mar 12, 2026
  16. Technologicat
    modified the milestones: 2.1.0, 2.2.0 on Apr 24, 2026
  17. Technologicat
    added 2 commits that reference this issue on May 6, 2026

    CHANGELOG, briefs: 2.2.0 #82 done

    7c14931

    briefs: add multishot-implementation; refresh 2.2.0-remaining-issues

    8ba4e75
  18. Technologicat
    closed this as completedin e20d23aon May 6, 2026
  19. Technologicat commented on May 6, 2026

    @Technologicat
    Technologicat
    on May 6, 2026
    OwnerAuthor
    More actions

    Closing this with the full API shipped for 2.2.0. Final surface (unpythonic.syntax.multishot):

    • @multishot — decorator macro making a def into a multi-shot generator. Required inside with continuations: (explicit, per ZoP — not auto-wrapped).
    • myield — name/expr macro, four forms (myield, myield[expr], var = myield, var = myield[expr]).
    • myield_from — name/expr macro, two forms (myield_from[inner()], var = myield_from[inner()]); the multi-shot analog of yield from. Forwards send/throw into the inner; outer_mi.gi_yieldfrom tracks the inner iterator while delegating.
    • MultishotIterator — adapter implementing a subset of the standard generator protocol (iter/next/send/throw/close, gi_* introspection), plus one method standard generators don't have: copy.copy(mi) forks the iterator at the current continuation. copy.deepcopy(mi) raises TypeError (the continuation closes over caller state we can't meaningfully deep-copy; use copy.copy).

    Architecture note for the curious: myield_from's expansion captures rest-of-outer via _rest = call_cc[get_cc()] (the multi-shot analog of Racket's (let/cc return ...)), tail-calls a small driver from outer's top level, and uses the cut-the-tail trick (cc = identity) inside a yield helper to deliver each (captured_cc, value) pair straight to the user's trampoline. When inner exhausts, the driver invokes the captured rest-cc to resume outer's body just past the myield_from statement.

    Not in v1, with documented rationale: yield from across standard and multi-shot generators (semantic mismatch — standard generators have paused state, multi-shots don't); async multi-shots (__aiter__, asend, etc.); pickling (continuations are closures). with/try/finally/with handlers straddling a myield is a load-bearing gotcha — workaround for handlers is to install with handlers(...) outside the @multishot body, in the calling code that consumes the iterator.

    Tests: 72 passing in unpythonic/syntax/tests/test_multishot.py. Docs: new "Multi-shot generators with @multishot and myield" chapter in doc/macros.md, with sub-sections covering myield_from, the differences from standard generators, the across-myield gotcha, and a "How does copy.copy(mi) differ from k = mi.k?" comparison. Implementation brief: briefs/multishot-implementation.md.

    — Claude (Opus 4.7)

  20. Technologicat
    added a commit that references this issue on May 12, 2026

    Release 2.2.0 "Hail Eris"

    2e57b03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

  • @Technologicat
    Technologicat

Labels

documentationNon-executable English, for humansNon-executable English, for humansenhancementNew feature or requestNew feature or request

Projects

No projects

    Milestone

    • 2.2.0No due date

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.