Program Structure

Concurrency

Run named work with a bounded timeout, then distinguish success, timeout, Result values, and faults.

Use concurrent when independent expressions may run together and the caller needs one named result record. Ordinary application code should choose the bounded form with an explicit timeout fallback.

Complete successfully

Save this as concurrency-success.tpz:

TOPAZ
let result = concurrent(timeout: 3s) {
    total: 1 + 2
    label: "ready"
} else {
    { total: -1, label: "timeout" }
}

print("{result.total} {result.label}")

Check and run it:

BASH
topaz check concurrency-success.tpz
topaz run concurrency-success.tpz

Both arms finish before the deadline, so their names become record fields:

Output
3 ready

The record associates each value with its arm name. This does not reveal which arm started or completed first.

Let the deadline choose the fallback

This second program has an arm that cannot finish. Save it as concurrency-timeout.tpz:

TOPAZ
function spin() -> int {
    let mut i = 0
    while true { i += 1 }
    i
}

let result = concurrent(timeout: 5ms) {
    stuck: spin()
} else {
    { stuck: -1 }
}

print("{result.stuck}")

Check and run it:

BASH
topaz check concurrency-timeout.tpz
topaz run concurrency-timeout.tpz

The deadline wins, no partial arm record is exposed, and the fallback supplies the whole result:

Output
-1

Distinguish the three outcomes

What happens before the deadline?Expression result
Every arm completesA record with one field per arm
The timeout winsThe else block value
An arm faultsThe whole expression faults; else does not run

An arm that evaluates to Err(error) has not faulted. That Result is an ordinary value stored in its named record field. The fallback must be type-compatible with the successful arm record, which is why each example returns the same field names and compatible value types on both paths.

What the names do not guarantee

Arm names fix result association, not scheduling. Topaz does not promise arm start order, completion order, output interleaving, fairness, or deterministic interleaving. Do not put print calls in arms when their order matters; join first, then print the record as the examples do.

When a timeout abandons work, cancellation and cleanup are runtime policy. Later faults from abandoned work are not observed by the Topaz expression. This is not permission to rely on a particular scheduler or on portable cleanup after timeout.

Common corrections

  • Write 3s or 5ms with no space. Property forms such as .seconds are not duration syntax.
  • A timeout form requires else; a plain join cannot have else.
  • else handles timeout only. It does not catch a fault or unwrap an Err.
  • Arm names must be unique, and no syntax exposes a partial result.

The plain concurrent { ... } join is useful on an advanced concurrency page when waiting without a timeout is itself the point. It is not the default form for ordinary examples.

There is no implicit async model, async/await syntax, public task handle, general duration arithmetic, or specified cancellation protocol. See Runtime Behavior for observable fault and order boundaries and Forbidden & Deferred Forms for familiar-looking forms that are not current Topaz.