Volume 14: Concurrency and Async¶
1. Introduction¶
This volume defines the initial async and concurrency model in the Rethon programming language. It describes the async model, async function declarations, await expressions, awaitable values, async return types, async error handling, async and try / except / finally, async result types, async function calls, async scope and control flow, async resource cleanup, task scheduling boundary, runtime and standard library boundary, deferred actors, deferred channels, deferred structured concurrency, future extensions, and summary.
This document is part of the official Rethon Language Specification. It is normative rather than descriptive. Implementations, tooling, documentation systems, and other source-processing tools shall treat the rules in this volume as authoritative.
This volume does not define coroutine lowering, scheduler internals, ABI details, or runtime-specific execution machinery. It defines the source-level and language-level behavior of async and concurrency as programmer-visible control flow.
Rethon is Python-inspired in language philosophy and Python-first in surface syntax where practical.
Rethon uses async def, await, explicit async functions, explicit suspension points, existing try / except / finally error handling, existing Result<T, E> modeling, the Standard Library Option<T> abstraction, runtime- and library-defined scheduling, and deferred advanced concurrency models.
Async and concurrency in Rethon shall remain minimal, readable, and explicit in the initial model.
2. Async Model¶
Rethon shall support async programming through explicit async functions and explicit suspension points.
The initial async model shall be source-level and readable rather than syntax-heavy or runtime-specific.
Async behavior shall be visible in the function declaration and at each suspension point.
Example:
An async function shall not be treated as ordinary synchronous code.
An async function shall not become async implicitly through hidden context.
The async model shall remain compatible with the language's static typing, error handling, and value-oriented design.
3. Async Function Declarations¶
Async function declarations shall use async def.
Example:
async def shall be the initial and canonical source form for async function declarations.
An async function declaration shall be explicit.
An async function declaration shall introduce a function whose body may contain await expressions and other async-aware control flow defined by this volume.
An async function declaration shall follow the ordinary function declaration rules established in the functions volume, except where this volume defines async-specific behavior.
Async function declarations shall remain Python-like in surface syntax.
4. Await Expressions¶
await expressions shall be supported.
Example:
An await expression shall mark an explicit suspension point.
An await expression shall evaluate an awaitable value and produce the value that the awaitable resolves to.
await shall be allowed only where async context permits it.
An await expression shall not be allowed in ordinary synchronous function bodies unless a later language rule explicitly defines a controlled form that permits it.
An await expression shall remain a source-level control-flow marker and shall not expose coroutine lowering details.
5. Awaitable Values¶
An awaitable value shall be a value that can be used with await.
An async function call shall produce an awaitable value rather than the function's final result directly.
Example:
async def load_user(id: int) -> User:
...
async def main() -> None:
pending_user = load_user(1)
user = await pending_user
An awaitable value shall represent a pending async computation at the source level.
An awaitable value shall be compatible with the function's declared return type once awaited.
The specification does not require awaitable values to expose runtime implementation details in source code.
6. Async Return Types¶
An async function shall declare the type of value produced when its awaitable result is awaited.
Example:
The declared return type of an async function shall describe the awaited result type, not the awaitable wrapper itself.
An async function that logically produces no usable value shall still declare its awaited result type explicitly, typically None until a more specific unit convention is introduced.
Example:
Async return typing shall remain consistent with the ordinary function type system.
Async return types shall be statically typed where practical.
7. Async Error Handling¶
Async error handling shall use the existing error-handling model.
try, except, finally, raise, Result<T, E>, and Option<T> shall remain the primary source-level tools for async error handling.
An async function shall not require a separate error system merely because it is async.
Example:
async def read_user(id: int) -> Result<User, Error>:
try:
user = await fetch_user(id)
return Result.success(value: user)
except NetworkError as error:
return Result.failure(error: error)
Async code shall remain compatible with the explicit recoverable-error model established elsewhere in the specification.
Thrown errors and result values shall continue to be distinct source-level choices.
8. Async and try / except / finally¶
Async functions shall support try, except, and finally using the same source-level semantics established by the error-handling volume.
Example:
async def load_and_log(path: str) -> None:
try:
data = await read_file(path)
print(data)
except IOError as error:
print(error.message)
finally:
print("done")
A try block inside async code shall handle thrown errors in the ordinary way.
A finally clause inside async code shall remain the guaranteed cleanup form.
Async source code shall not need a separate exception syntax.
9. Async Result Types¶
Result types shall be supported in async code as explicit recoverable-failure values.
Example:
async def lookup_user(id: int) -> Result<User, LookupError>:
...
async def main() -> None:
match await lookup_user(1):
case Result.success(value: user):
print(user)
case Result.failure(error: error):
print(error.message)
A result type returned from an async function shall remain a normal typed value after awaiting.
Pattern matching shall remain the preferred way to inspect result-style values in async code.
Async functions may return Option<T> or Result<T, E> when that form best expresses the API contract.
10. Async Function Calls¶
Calling an async function shall produce an awaitable value.
The caller shall use await where the language's async rules require the final result.
Example:
Async function calls shall remain explicit at the source level.
A programmer shall not assume that simply calling an async function performs the underlying work synchronously.
The language shall keep async calls readable and distinguish them from ordinary function calls through the required use of await at suspension points.
11. Async Scope and Control Flow¶
Async functions shall establish ordinary function scope plus async-aware control flow.
Local variables, parameters, nested blocks, and shadowing shall follow the ordinary function rules unless a later async-specific rule states otherwise.
Suspension points shall preserve source-level control flow in a way that remains understandable to readers.
Example:
async def fetch_and_print(id: int) -> None:
user = await load_user(id)
if user is None:
return
print(user.name)
Async control flow shall remain compatible with existing conditional, loop, and return semantics.
Async functions shall not introduce hidden scope rules merely because they may suspend.
12. Async Resource Cleanup¶
Async resource cleanup shall use the existing cleanup mechanisms defined by the language, especially finally.
Example:
async def read_config(path: str) -> str:
file = await open_file(path)
try:
return await file.read()
finally:
await file.close()
A finally clause shall remain the initial guaranteed-cleanup form for async code.
If a cleanup operation itself is async, it shall be allowed where the surrounding async rules permit suspension.
The initial model shall not require a separate with or context-manager mechanism for async resource management.
13. Task Scheduling Boundary¶
Task scheduling details shall be outside the core syntax.
The language shall define the source-level async model, but it shall not define a specific scheduler API, queueing discipline, execution policy, or task runtime mechanism in the core syntax.
Scheduling details shall be handled by the runtime or by the standard library.
This boundary preserves implementation flexibility and prevents the core syntax from depending on a particular concurrency engine.
The source language shall therefore remain focused on explicit suspension points and typed async control flow.
14. Runtime and Standard Library Boundary¶
The runtime and standard library shall define the operational details that are not part of the source-language async model.
Those details may include task creation helpers, scheduler integration, event-loop hooks, or other execution support, but such mechanisms shall not redefine the core source syntax.
The specification does not require a particular runtime strategy for concurrency.
The language shall remain free to evolve its runtime support without changing the initial async def and await source model.
15. Deferred Actors¶
Actors shall be deferred.
The initial async and concurrency model shall not include actor syntax or actor semantics.
Example of a deferred concept:
Actors may be considered later if the language concludes that they add value without complicating the core model.
Until then, the language shall not reserve actor syntax as part of the initial async surface.
16. Deferred Channels¶
Channels shall be deferred.
The initial async and concurrency model shall not include channel syntax as a core language feature.
Channels may later be introduced by the standard library or by a future concurrency volume if they are justified.
Until then, the language shall not force channel-based coordination into the core syntax.
17. Deferred Structured Concurrency¶
Structured concurrency shall be deferred.
The initial async and concurrency model shall not include structured concurrency primitives as part of the core syntax.
This decision does not prevent a future library or later volume from introducing structured concurrency forms if they remain coherent with the language direction.
The initial model shall therefore stay minimal and readable rather than prematurely feature-complete.
18. Future Extensions¶
This volume defines the current direction for async and concurrency in Rethon, but future specification work may refine the model in carefully controlled ways.
Possible future extensions include:
- a richer runtime task API
- library-defined scheduling helpers
- structured concurrency primitives
- actors
- channels
- async generators or async iterators if justified later
- additional syntax for task composition if it remains readable and explicit
- more precise interaction rules with future resource-management forms
Any future extension shall preserve the current direction:
async defremains the initial async declaration formawaitremains the suspension marker- async behavior remains explicit
- suspension points remain source-visible
- result types and option types remain available for explicit modeling
try/except/finallyremain the error-handling foundation- scheduling remains runtime- or library-defined
- actors, channels, goroutine-like syntax, and structured concurrency remain deferred until justified
19. Summary¶
Rethon shall use Python-style async def and await in its initial async model.
Async functions shall be explicit and shall expose suspension points explicitly in source code.
await shall produce the awaited result of an awaitable value and shall be allowed only where async context permits it.
Async return types shall describe the awaited result type, and async error handling shall reuse the existing try / except / finally, Result<T, E>, and Option<T> model.
Scheduling shall be runtime- or standard-library-defined rather than syntax-defined.
Actors, channels, goroutine-like syntax, and structured concurrency shall be deferred.
Rethon’s initial async and concurrency model shall therefore remain minimal, explicit, Python-first, and compatible with the language’s static typing, memory safety, and readable control-flow goals.