Early preview: syntax, standard library APIs, and tooling may change.

Safety and Runtime ModelConcurrency

Concurrency

concurrent: starts child work and joins it before control continues.

Concurrent:

Each binding inside a concurrent: block runs as a child task.

concurrent:
    left = slow_left()
    right = slow_right()

Task Results

After the block, each binding is Result[T, ConcurrencyError]. The outer error is Timeout, Cancelled, or TaskFailed(message), not a returned application error. These are task-boundary outcomes, not exceptions.

import:
	channel: ConcurrencyError(Timeout, Cancelled, TaskFailed)


pure func task_error_message(error: ConcurrencyError) -> String:
	match error:
		Timeout: "task timed out"
		Cancelled: "task cancelled"
		TaskFailed(message): message


func report_task_result(result: Result[Int, ConcurrencyError]) -> Void:
	match result:
		Ok(value): print(value.to_string())
		Err(error): print_error(task_error_message(error))


func main(args: List[String]) -> Void:
	report_task_result(Ok(42)) -- stdout: 42

Application Errors

A task that returns Result[T, E] produces two layers: Ok(Err(error)) means it completed with an application error; outer Err means a concurrency failure. An application Err does not cancel siblings. Inspect both layers and choose your application's failure policy.

import:
	channel: ConcurrencyError(Timeout, Cancelled, TaskFailed), sleep_for
	units: milliseconds


pure func application_error() -> Result[Int, String]:
	Err("invalid input")


func successful_sibling() -> Int:
	sleep_for(milliseconds(1))
	42


func main(args: List[String]) -> Int:
	concurrent:
		application = application_error()
		sibling = successful_sibling()

	-- Outer Ok means the task completed; inner Err is application data.
	application_failed = match application:
		Ok(Err(message)):
			print("application error: ${message}") -- stdout: application error: invalid input
			message == "invalid input"
		_:
			False

	-- Returning an application Err did not cancel this sibling.
	sibling_finished = match sibling:
		Ok(value):
			print("sibling: ${value}") -- stdout: sibling: 42
			value == 42
		Err(_):
			False

	if application_failed and sibling_finished:
		0
	else:
		1

Timeouts

A typed Duration deadline is shared by the block. Unfinished tasks return Err(Timeout). Cancellation is cooperative: the block waits for cleanup before continuing, which can take longer than the deadline.

import:
	units: milliseconds


concurrent(timeout: milliseconds(500)):
    value = slow_operation()

Cancellation Points

Sleep, channel waits, and joins observe cancellation. The compiler also inserts budgeted checkpoints in while, for, and lowered tail recursion. Cancelling a parent cancels and joins its structured children, closing scoped resources. Blocking native calls can delay that cleanup.

import:
	channel: sleep_for
	units: milliseconds


func slow() -> Int:
	sleep_for(milliseconds(100))
	42


pure func count_steps(limit: Int) -> Int:
	var steps: Int = 0
	while steps < limit:
		steps += 1
	steps

Bounded Fan-Out

for ... concurrently(limit: 2) bounds active children and joins them. It is statement-only; use List.concurrent to inspect task results and failures.

import:
	channel: sleep_for
	units: milliseconds


func rebuild_page(page: String) -> Void:
	sleep_for(milliseconds(10))
	print("rebuilt ${page}")


func main(args: List[String]) -> Void:
	pages: List[String] = ["intro", "concurrency", "resources"]

	for page in pages concurrently(limit: 2):
		rebuild_page(page)

Detached Work

detach has no result handle or implicit join. Detached work is not guaranteed to finish after main returns; process shutdown can discard parked tasks. Use structured concurrency when completion matters. This example waits for a bounded channel acknowledgement, not proof of task termination.

import:
	channel:
		RecvAttempt(RecvSealed, RecvTimedOut, RecvValue, RecvWouldBlock),
		recv_timeout_attempt_for,
		wait_send
	units: seconds


func publish_ready(done: Channel[String]) -> Void:
	match wait_send(done, "ready"):
		Ok(_):
			void
		Err(_):
			print_error("ready channel was sealed")


func main(args: List[String]) -> Int:
	done: Channel[String] = channel(1)
	detach publish_ready(done)

	-- Wait for an acknowledgement; detach itself provides no join or result.
	match recv_timeout_attempt_for(done, seconds(5)):
		RecvValue(message):
			print(message) -- stdout: ready
			0
		RecvSealed:
			print_error("ready channel was sealed")
			1
		RecvTimedOut:
			print_error("background task did not report")
			1
		RecvWouldBlock:
			print_error("background task was not ready")
			1

Example

two-tasks.brp
import:
	channel: sleep_for
	units: milliseconds, seconds


func slow_left() -> Int:
	sleep_for(milliseconds(100))
	20


func slow_right() -> Int:
	sleep_for(milliseconds(100))
	22


func report_task_error(error: ConcurrencyError) -> Void:
	match error:
		Timeout: print_error("task timed out")
		Cancelled: print_error("task cancelled")
		TaskFailed(message): print_error(message)


func main(args: List[String]) -> Int:
	concurrent(timeout: seconds(5)):
		left = slow_left()
		right = slow_right()

	match left:
		Ok(a):
			match right:
				Ok(b):
					print(a + b) -- prints: 42
					0
				Err(error):
					report_task_error(error)
					1
		Err(error):
			report_task_error(error)
			1

Try it

terminal
blorp run two-tasks.brp