Skip to Content

Tasks and Spawn

spawn puts a code block into execution immediately and returns a task. A block with a value just returns it, and the block’s type is task<T> — no async function declaration needed up front.

The spawn Block

async func main() -> int { val t = spawn { await 0.5s; print("block finished"); }; val n = spawn { await 0.5s; return 7; }; print(t.IsCompleted); val r = await n; print(r); await t; print(t.IsCompleted); return 0; }
False block finished 7 True

The first spawn is a void block (task<void>); the second carries return 7 (task<int>). print(t.IsCompleted) prints False (the block is still sleeping), await n yields 7, and once await t has waited it out, the same check reads True.

Scheduling

A spawned block starts running immediately and keeps going until its own first await before suspending and yielding; it does not sit idle until the main line reaches some interleaving point.

async func main() -> int { val a = spawn { await 0.3s; print("A woke"); }; spawn { await 0.1s; print("B woke"); }; await a; return 0; }
$ mush --virtual-time run demo.ms B woke A woke

IsCompleted: the Only Member

t.IsCompleted is the only member a task exposes to script code: completed, faulted, and cancelled-by-negotiation all count as terminal states.

Capture Isolation

A spawned block can read outer variables, but writes do not flow back: modifications to a captured outer variable inside the block live only inside the block, unlike a synchronous lambda (whose writes penetrate). Data exchange between task and main line goes through the return value plus await; a task’s result is only obtainable via await.

spawn cancel

spawn cancel ct { } gives the block a cancellable environment, with cancel.requested / cancel.token available inside (see Cancellation and Timeout).

Notes

  • a spawned block’s failure propagates through await: awaiting a faulted task surfaces the failure at the await site;
  • a spawn that is never awaited is fire-and-forget; the block still runs to completion;
  • the block’s return type is inferred from its first return, and multiple returns must agree on type.
Last updated on October 11, 2026