← index

Plan

inherits Object · defined at core/11-plan.qn:23

Plan — the join graph (docs/internal/CONCURRENCY_ARCH.md §13.5).

A Plan is a LAZY spec tree: constructors build it, nothing runs until await. Leaf methods name WHERE the code runs; composites name shape:

Plan.task:{ b } in-VM task (same heap, ordinary closure) Plan.thread:{ b } thread isolate, portable block Plan.thread:'unit.qn' thread isolate, unit form Plan.process:'unit.qn' child qn process (data-only lanes) Plan.all:#( plans ) structural gather -> isomorphic result List Plan.any:#( plans ) race -> first success, rest cancelled

Worker leaves take send: (the input message) and label: (stamped into the registry: VM.psTree shows plan ownership). Failure policy is a composite attribute: onError:'cancelRest' (default — first error cancels the rest and re-raises) or 'collect' (every slot resolves to #{'ok': v} or #{'err': message}).

Cancellation is per-backing: process leaves are TERMINATED (killed), thread leaves are orphaned (marked orphaned: in the registry — they run to completion detached), task leaves get cooperative cancel. Timeouts compose: Async.timeout:ms do:{ plan.await }.

Class methods

all:

Structural gather: a composite that launches every plan in plans in parallel; await answers a List isomorphic to the input. The failure policy defaults to 'cancelRest' (see all:onError:).

(Plan.all:#( (Plan.task:{ 1 + 1 }) (Plan.thread:{ 2 + 2 }) )).await    "* -> #(2 4)

core/11-plan.qn:80

all: onError:

A gather with an explicit failure policy: 'cancelRest' (the first error cancels the remaining children and re-raises) or 'collect' (no slot is lost — each resolves to #{'ok': v} or #{'err': message}). Any other policy string throws.

(Plan.all:#( (Plan.task:{ 1 }) (Plan.task:{ 'boom'.throw }) ) onError:'collect').await
    "* -> #(#{'ok': 1} #{'err': 'boom'})

core/11-plan.qn:90

any:

Race: launch every child; the first SUCCESS wins — await answers its value and cancels the rest. Errors don't win the race: if every branch fails, await throws with the last error.

(Plan.any:#( (Plan.task:{ Async.sleep:50; 1 }) (Plan.task:{ 2 }) )).await    "* -> 2

core/11-plan.qn:103

cancelNode:

Cancel whatever part of a live subtree has not completed: process -> terminate, thread -> orphan + label, task -> cancel.

core/11-plan.qn:120

process:

A child-process leaf: run unit file u in its own qn process. Unit-form only — blocks cannot cross a process boundary — and the lanes carry data-only values.

core/11-plan.qn:59

process: label:

A process leaf stamped with registry label l (see thread:label:).

core/11-plan.qn:66

process: send:

A process leaf whose child is sent m as its first message at launch (see thread:send:).

core/11-plan.qn:62

process: send: label:

A process leaf with both an input message and a registry label.

core/11-plan.qn:70

settleNode:

Internal: settle a live node from a fresh task (no captured instance state).

core/11-plan.qn:116

task:

An in-VM task leaf: run block b as a Task on this VM's scheduler — same heap, ordinary closure, so it may capture freely (the only leaf kind that can).

(Plan.task:{ 1 + 1 }).await    "* -> 2

core/11-plan.qn:32

thread:

A thread-isolate leaf: c is a portable block, or a unit path (String) loaded fresh in the isolate. The work runs on its own thread with its own heap; the result deep-copies back.

(Plan.thread:{ 6 * 7 }).await    "* -> 42

core/11-plan.qn:40

thread: label:

A thread leaf stamped with registry label l, so VM.psTree shows which plan owns the worker.

core/11-plan.qn:50

thread: send:

A thread leaf whose worker is sent m as its first message at launch — the code reads it with Worker.receive.

(Plan.thread:{ Worker.receive * 2 } send:21).await    "* -> 42

core/11-plan.qn:47

thread: send: label:

A thread leaf with both an input message (see thread:send:) and a registry label (see thread:label:).

core/11-plan.qn:53

unitPath:

Internal: validate a process-leaf target — unit paths (Strings) only, because blocks cannot cross a process boundary (§13.2).

core/11-plan.qn:107

Instance methods

await

Run the plan: launch the whole spec tree without waiting (that is what makes siblings start in parallel), then join it in structure. Answers the leaf's value or the composite's result; failures re-raise here, subject to the composite's policy. The calling task parks until the answer is ready — compose a deadline with Async.timeout:do:.

(Plan.task:{ 1 + 1 }).await    "* -> 2

core/11-plan.qn:189

init

A fresh Plan defaults to an empty in-VM task leaf under the 'cancelRest' policy; the class-side constructors overwrite from here.

core/11-plan.qn:139

kind

The node's kind: 'task', 'thread' or 'process' for leaves, 'all' or 'any' for composites.

(Plan.task:{ 1 }).kind    "* -> task

core/11-plan.qn:169

label

The registry label for a worker leaf, or nil when unlabelled.

(Plan.thread:{ 1 } label:'demo').label    "* -> demo

core/11-plan.qn:178

launch

Phase 1: spawn the whole tree without waiting on anything. A live node is #{'plan' 'handle' 'children' 'done?'} — 'handle' is a Worker or Task handle, nil for composites.

core/11-plan.qn:197

policy

The failure policy a composite settles under: 'cancelRest' (the default) or 'collect'.

core/11-plan.qn:172

setKind: children:

Internal setter used by the constructors: stamp a composite kind ('all' / 'any') and its child plans. Answers self for chaining.

core/11-plan.qn:153

setKind: code:

Internal setter used by the constructors: stamp the leaf kind and its code (portable block or unit path). Answers self for chaining.

core/11-plan.qn:150

setLabel:

Internal setter used by the constructors: record the registry label stamped onto a worker leaf at launch. Answers self for chaining.

core/11-plan.qn:159

setMsg:

Internal setter used by the constructors: record the message a worker leaf is sent at launch. Answers self for chaining.

core/11-plan.qn:156

setPolicy:

Internal setter used by the constructors: set a composite's failure policy ('cancelRest' or 'collect'). Answers self for chaining.

core/11-plan.qn:162

settle:

Phase 2: join in structure. Composites join their children through an outcome channel so policy reacts in COMPLETION order, not index order — a fast failure cancels a slow sibling immediately.

core/11-plan.qn:225

settleAll:

Internal join for an 'all' composite: children settle through a shared channel in COMPLETION order — under 'cancelRest' a fast failure cancels the in-flight siblings immediately; under 'collect' each slot files #{'ok': v} or #{'err': message} — while results land by index, so the answer matches the children's order.

core/11-plan.qn:243

settleAny:

Internal join for an 'any' composite: the first success cancels every other child and becomes the answer; when all branches fail, throws with the last error.

core/11-plan.qn:285