Async / Await
The async chapter documents Nitpick's Phase 1 async surface as
shipped in the v0.31.x cycle: async func: declarations,
await <expr> resolution, the compiler-injected executor
drain, the borrow rules around suspension points, the Drop
interaction, and the spin-poll bridge into the runtime's async
file I/O.
This is Phase 1 of 5. The async runtime in
src/runtime/async/ (~3,100 lines, predating v0.31) is largely
complete, but the user-facing language surface only exposes a
narrow slice of it this cycle. Network async, a real awaiter
over NitpickFutureHandle, try/catch, and a multi-threaded
work-stealing executor are not documented here as if they
were available — they are explicit non-goals for v0.31.x.
When to reach for async
| You want… | Use |
|---|---|
Compose calls to other compiled async func:s |
await |
| Schedule background work and forget it | drop <call> |
| Read/write a file without blocking the caller thread | npk_*_file_async (extern) |
| Block-style code with synchronous semantics | a regular func: |
Catch an await-site error as a fallback value |
defaults / ? / !! / pick |
| Anything network-shaped | Phase 2 (not v0.31.x) |
Async is for suspendable composition of work, not parallelism.
The Phase 1 executor is single-threaded run-to-completion. The
only "real" suspension that lands this cycle is at the
machine-instruction level inside coroutine state machines; the
file-I/O runtime futures run on a separate 4-thread I/O pool and
are observed from user code by polling, not by await.
When not to reach for async
- You're trying to express parallelism. The Phase 1 executor is single-threaded. Use threads (Phase 3+) or a process pool.
- You want
try { ... } catch e { ... }exception handling.catchwas pulled from the keyword list in v0.31.0.2 (D-8 / seeMETA/NITPICK/ROADMAP/0.31/AUDIT_v0.31.0.0.md§D-8). UseResult<T>,defaults,?,!!, orpick. - You want to hold a
$$i/$$mborrow across anawait.ARIA-041rejects it (v0.31.0.4). Take aHandle<T>instead, or re-borrow after the await resumes. - You want to
awaitover a runtimeNitpickFutureHandle(e.g. the result ofnpk_read_file_async). Phase 1 has no bridge — the user-levelawaitresolves only other compiledasync func:calls. File I/O is observed via spin-poll onnpk_future_is_ready+npk_future_is_error. Bridging the two futures is deferred.
Chapters
- README — this page.
- Surface —
async func:,await <expr>,Result<T>at await sites, the compiler-injectednpk_executor_rundrain. - Errors —
pass/failsemantics in async bodies,ARIA-040(awaitoutside an async function), the pulledcatchkeyword. - Borrows across await —
ARIA-041, why borrows don't survive suspension, theHandle<T>escape hatch. - Drop interaction — Drop fires on async completion,
on
failunwind, LIFO across nested scopes; the shutdown-of- suspended-task case is deferred. - Async file I/O — the extern + spin-poll surface
for
npk_write_file_async,npk_read_file_async,npk_file_exists_async,npk_delete_file_async, and thenpk_future_is_errordisambiguation idiom. - FAQ — known gaps, why no awaiter bridge yet, what Phase 2 and beyond are expected to add.
See also
guide/drop/— Drop / RAII model that the async runtime layers on top of for resource cleanup on completion and onfailunwind.guide/handles/—Handle<T>is the ARIA-032-protected cross-await reference type.guide/memory/— region model that governs what GC root scanning sees inside suspended coroutine frames.META/NITPICK/ROADMAP/0.31/AUDIT_v0.31.0.0.md— the Phase 1 baseline survey and decisions (D-1..D-11) that this cookbook documents.
Validation snapshot (v0.31.0.8)
- CTest: 99/99 at v0.31.0.7 close (this slice is doc-only).
- Bug regressions added in v0.31.x to date:
bug334–bug356covering executor drain,ARIA-040, the pulledcatch, pass/fail short-circuit,ARIA-041borrow-across-await, Drop-on-completion / Drop-on-fail / LIFO Drop ordering, GC root scanning across suspended frames, and the async file I/O spin-poll surface. - Decisions locked: D-1 (single-threaded executor), D-2
(compiler-injected
npk_executor_rundrain), D-3 (ARIA-040hard error), D-5 (ARIA-041borrow-across-await), D-6 (GC root scanning across all suspended frames), D-7 (pass/fail short-circuit), D-8 (catchpulled, Option A), D-9 (async file I/O documented as user-facing surface), D-10 (Drop on completion +failunwind; shutdown-of-suspended-task deferred), D-11 (pinsurvives across suspend).