Skip to content

Concurrency API ​

Explicit Java completion adaptation is defined in java.norm; JavaCollectionTaskInteropTest verifies completion, failure, cancellation and resource ownership.

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.

norm
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.

When an execution instance closes, pending asynchronous delivery is rejected before guest code runs; task cleanup remains idempotent and does not re-enter the closed execution.

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, or explicitly closing 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 concurrency types retain their java.base nominal identity; see Java bindings. A long-running entry point can use awaitCancellation to wait for cancellation or interruption.

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. Completion sources do not own a work body, so their tasks return 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.

Java asynchronous completion boundaries use completionFuture. Its canonical Java types are owned by java.base; TaskExecutionTest and JvmJarBindingTaskTest verify runtime projection and cancellation.

Norm 0.25