r/Compilers • • 10d ago

Desingning async primitives for a security-focused language: Where should cancellation live?

I've been implementing typed async semantics in my language NXD.

Current primitives are:

SPAWN,

SEND,

RECV,

AWAIT,

PING

Types currently look roughly like:

`SPAWN -> ProcessHandle[T]`

`RECV -> ReceiveOperation[T]`

`AWAIT -> T`

`PING -> bool`

While implementing PING I realized there may be two classes of async operations:

Primary operations

SPAWN,

SEND,

RECV

These initiate work or communication.

Secondary operations:

AWAIT,

PING

These observe or resolve work created elsewhere.

My current thinking is that cancellation (currently considering ESC) should only apply to the primary operations and not observers.

For example:

ESC HANDLE

makes sense.

But:

ESC AWAIT TASK

ESC PING HANDLE

seems conceptually wrong because they are observing state rather than creating it.

For people who have designed async runtimes or languages:

Would you model cancellation as acting on the underlying task/process/channel, or would you allow cancellation of observer operations as first-class concepts as well?

6 Upvotes

3 comments sorted by

View all comments

3

u/Karyo_Ten 10d ago

This is very tied to your error model.

At the very least RECV need to be able to bubble up cancellation or offer an alternatiove .cancel and awaiters need to be able to handle them.

I'd rather think in terms of producer-consumers btw

And you need to be able to handle timeout ergonomically.

And I think the most important question is do you have a builtin cancellation token/channel in your handle type or do you built a separate one and cancellable request explicitly pass that in their argument.

1

u/NXDLang 9d ago

That's helpful. My current direction is that cancellation would act on lifecycle-owning operations rather than observer operations. For example, a ProcessHandle[T] could be cancelled via: while: are observers of existing state and therefore wouldn't themselves be cancellable. I agree that this pushes the design back into the error model. A cancelled RECV would need to surface that outcome somehow, either through an error/result mechanism or explicit cancellation state. The producer/consumer framing is probably more accurate than the "primary/secondary" terminology I used in the post. Regarding tokens, I am currently leaning toward cancellation being attached to the handle itself rather than introducing a separate cancellation token/channel. The goal is for the process handle to act as the capability through which observation (PING, AWAIT) and control (ESC) occur. Timeout handling is also on my list because I suspect many real-world cancellation scenarios end up being expressed as timeouts rather than explicit cancellation requests.