Concurrency API
std.concurrent.Task<T> represents a typed operation that completes later and implements std.io.Resource. tasks.norm defines its declarations and overloads.
std.concurrent.async submits value-returning or Void work in the current TaskScope; submission without a scope is rejected. The host implements TaskScope.start and connects executor and lifecycle behavior; the standard library has no UI dependency. Once a component binds this context, it reuses the UI queue, task cancellation, and cleanup barrier. Use startTask for independent work without a scope. AsyncExecutionTest covers the standard-library contract.
var task = startTask { 20 } then { result * 2 } then { result + 2 }
var handled = task.then { printLine(result) } error { printLine(failure.message) }startTask returns immediately after submitting virtual-thread work; Void work uses Unit to represent completion. then handles the previous stage's success and error handles its failure, including exceptions thrown by a success callback. Every registration returns an independent continuation and does not execute the callback on the caller's stack. Value-returning overloads preserve their exact result type; Void callbacks produce Unit. Returning another Task preserves that return type without automatically flattening nested tasks.
By default, continuations are scheduled onto a virtual thread only after completion notification; an unready stage does not start a waiting thread in advance. startTask(executor: executor) { ... } selects a TaskExecutor. Work still runs on a virtual thread, while later success and error stages inherit that executor. Dispatch must queue the action rather than call it inline or silently drop it. A dispatch rejection must throw, causing that stage to fail. A task captures the current ResourceOwner at creation, and later stages inherit ownership; a GUI must still connect its UI queue through an executor. Completion, cancellation, or closing releases resource ownership and removes the task from the execution instance's resource list; the completed result remains readable. Closing an owner may cancel stages it owns; a closed owner rejects new stages. Tasks do not extend the lifetime of their execution instance. Cancelling a continuation does not cancel its prerequisite or sibling stages.
The existing await() returns a completed value and routes failures through Norm exceptions; completed() observes terminal state, and cancel() requests cancellation. TaskExecutionTest covers language behavior; JvmJarBindingTaskTest covers scheduling, cancellation, and result conversion.
With a TaskExecutor, an unhandled failure is queued to that executor and then passed to its report(error). The default implementation throws; a GUI executor sends it to the window error reporter. Connecting a continuation, awaiting, cancelling, explicitly closing, or handing the result to Java all count as taking responsibility for a task; a new failure at the end of a chain can still be reported independently. Automatic resource release does not mean an error was handled. A handler registered while reporting is queued suppresses the default report, but a report already made cannot be revoked by a later handler. Cancellation is not reported as an unhandled exception; without a selected executor, the caller reads the result.
Java Binding projects Future, CompletionStage, and CompletableFuture as the same Task type. Tasks originating in Java use an adapted host Future view; Norm-created tasks provide a separately converted Java CompletionStage view. A long-running application entry point can use awaitCancellation to keep execution alive until cancellation or interruption.
Java declarations of Future<?>, CompletionStage<?>, and CompletableFuture<?> retain an unknown element type rather than becoming Task<Any?>. This lets a Java API that only checks completion accept Tasks of different result types without changing ordinary parameterized-type invariance.
termination() returns an independent Task<Unit>? notification that completes only after Norm-scheduled work leaves its execution body, including finally, even if the task was cancelled. Cancelling work that has not run or was rejected by an executor also completes the notification. It does not inherit the component's ResourceOwner, and closing it does not cancel the original work; the notification is not another work body. An external Java Future cannot prove its background work has exited, so it returns null. This API coordinates resource closing; UI threads should not block on await.
External events create a completable task source through completion<T>(). See completion.norm for declarations and CompletionTest for cross-thread completion, failure identity, and close cancellation.