Skip to content

Async and Structured Concurrency

Shape async uses await and join with structured lifetime control.

let data = await fetch_data()

Top-level await is supported in scripts and REPL.

async let spawns an expression as a concurrent task. Use await to retrieve the result.

async let data = fetch_data()
// ... other work happens here ...
let result = await data

Multiple async let bindings run concurrently:

async let users = fetch_users()
async let posts = fetch_posts()
async let stats = fetch_stats()
// All three requests run at the same time
let u = await users
let p = await posts
let s = await stats
let (a, b) = await join all {
fetch_a(),
fetch_b()
}
let fastest = await join race {
fetch_primary(),
fetch_backup()
}
let first_ok = await join any {
fetch_primary(),
fetch_backup()
}
let results = await join settle {
fetch_a(),
fetch_b(),
fetch_c()
}
let values = await join all {
left: fetch_left(),
right: fetch_right()
}
print(values.left)
async scope {
async let stream_a = subscribe_a()
async let stream_b = subscribe_b()
for await event in merge(stream_a, stream_b) {
if event.done {
break
}
}
}

When scope exits, pending child tasks are cancelled deterministically.

Custom annotations can add policy to await expressions (e.g. timeout, retry, circuit-breaking). Define them using Shape’s annotation system — see the Comptime Annotations Cookbook for examples.