Run independent tasks with concurrent and collect their results in named record fields. Set a timeout and use else to choose the result when time runs out.
Install Topaz with First Program. Save each program below in a working folder and run its commands there.
Complete before the timeout
Save this code as concurrency-success.tpz.
let result = concurrent(timeout: 3s) {
total: 1 + 2
label: "ready"
} else {
{ total: -1, label: "timeout" }
}
print("{result.total} {result.label}")Check and run it.
topaz check concurrency-success.tpz
topaz run concurrency-success.tpzBoth commands exit with code 0. When both tasks finish within three seconds, the program prints the result record values.
3 readyEach named expression inside concurrent is a task, also called an arm. Here, total computes 3 and label produces "ready". Their names become fields in the result record. The record does not indicate which task started or finished first.
Return a different value on timeout
This program has a task that keeps looping. Save it as concurrency-timeout.tpz.
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.
topaz check concurrency-timeout.tpz
topaz run concurrency-timeout.tpzThe five-millisecond timeout selects else, which supplies the whole result. Both commands exit with code 0.
-1No task results are returned on timeout, including results from tasks that already finished. If your own task should finish, correct its loop condition or input. Returning a timeout value does not fix the unfinished work.
Distinguish completion, timeout, and faults
| What happens | Expression result |
|---|---|
| Every task finishes before timeout | A record with one field per task |
| Time runs out first | The else block value |
| A task faults before timeout | The whole expression faults, without running else |
A fault is an error that stops evaluation, such as an out-of-bounds array access. A task returning Err(error) completes with an ordinary Result value. That value goes into its named field. The else block handles timeouts and neither catches faults nor extracts values from Err.
The else result must have a type compatible with the successful result record. Both examples use the same field names and compatible field types on both paths.
Control output order
Print after concurrent returns when output order matters. Task names identify results, but the runtime does not specify task start or completion order. It also does not specify how task output interleaves, how fairly tasks are scheduled, or whether interleaving repeats across runs.
After timeout, the runtime decides how to cancel unfinished work and clean up its resources. Later faults from abandoned work do not reach the Topaz expression. Do not depend on a particular cancellation or cleanup sequence.
Write a valid timeout
Write a whole number followed immediately by ms, s, or m, as in 5ms or 3s. Spaces and property forms such as .seconds are invalid. Duration literals are used in the concurrent timeout clause.
After conversion to milliseconds, the duration must fit unsigned u64, from 0 to 18446744073709551615. Larger values produce TPZ5001. Reduce the literal to a supported value.
| Unit | Largest accepted literal |
|---|---|
| Milliseconds | 18446744073709551615ms |
| Seconds | 18446744073709551s |
| Minutes | 307445734561825m |
Give each task a unique name. A timeout requires else. The form concurrent { ... } waits for all tasks without a timeout and cannot have else. Prefer an explicit timeout for application examples.
Topaz has no implicit async model, async/await, public task handles, or general duration arithmetic. See Runtime Behavior for faults and ordering, and Forbidden & Deferred Forms for unsupported syntax.