Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Function

async / await — why Osy# has neither

// there is no `async`, and no `Task<T>`. // `await` appears in exactly one place: await Workflow.Run("step", …);

Osy# has no async and no Task. A function that calls out to the world is written like any other function — the engine suspends and resumes it around the effect. await exists in exactly one place, Workflow.Run.

stable1 example compiled by CIfunctionconcurrencydurability

Summary#

There is no async in Osy#, and no Task<T>. A function that calls out to the world — an HTTP request, an LLM completion — is written exactly like one that adds two numbers. You call the thing; the platform takes care of the waiting.

await exists in one place in the whole language: await Workflow.Run("step", …).

If you are coming from C#, this is the first thing to unlearn, so it is worth a page of its own.

Signature#

// No `async`. No `Task<T>`. No `.Result`, no `ConfigureAwait`, no `Task.WhenAll`.
<ReturnType> <Name>(<params>) {
  var r = Http.Get(url);      // an effect — just call it
  …
}

await Workflow.Run("step", <workflow>);   // the ONE await: wait for another long-running thing to finish

Description#

Just call the effect#

An effect is anything that reaches outside the database: an HTTP call, a model completion, a file read. You call it. That is all:

app Shop {
  model "model/**/*.osy";
  use Osyrin.Http;
}

entity Order {
  [Required] string Code;
  bool Notified;
}

void Notify(string code, string url) {
  var order = Order.Single(o => o.Code == code);
  var r = Http.Get(url);         // the function pauses here — but you did not have to say so
  order.Notified = r.IsSuccess;
}

The function does not return a Task. Its caller does not await it. Nothing about its signature says it might take a while.

What happens when a function hits an effect?#

When a function reaches an effect, the engine suspends it, performs the effect, and resumes it at the very next line — with every local still in place. That suspension is durable: if the process is restarted, redeployed or killed while the HTTP call is in flight, the function still resumes where it left off. It is not a thread parked in memory; it is a continuation the platform persisted and will pick up again.

That is a stronger promise than async makes. A C# async method whose process dies mid-await is simply gone.

Why is there no async colour to propagate?#

In C#, async is a colour. A method that awaits must be async, so its callers must await it, so they must be async, and it spreads outward until it has reached Main. You end up marking a hundred functions to describe a property of one — and then a library forces you into .Result and you deadlock a thread pool at 4am.

The colour exists so that a caller knows the callee might yield. Here, that is the engine's business rather than the signature's: any function can suspend, so no function has to advertise it. There is nothing to spread, so there is nothing to mark.

The practical consequence: the ability to call out to the world costs you nothing in your function signatures. You can add an HTTP call to a function three layers down and not touch a single caller.

The one place await is legal — Workflow.Run#

await Workflow.Run("step", …) is the exception, and it earns it. There, waiting is the thing you are actually saying: start this other long-running process, and do not continue until it is finished. It may be finished in ten seconds or in three weeks; the await is what says you are content to wait either way.

That is a decision about your business process, not a detail of your threading — which is exactly why it is the one place the word appears.

If you write async or await anyway#

The compiler stops you. async is a parse error — "Osy# has no async — effects run in place, so a function or method is never marked async." await is an error everywhere except the one place it means something (await Workflow.Run("step", …)) — "Osy# has no await — effects run in place, so await is never needed." Both messages point you straight back to this rule. There is no tolerated middle ground: the word suggests a distinction that does not exist, so the compiler removes the temptation rather than letting it read as meaningful.

See also#

  • function — how a function is written
  • Http.*Http.Get / Http.Post, the effects you call without ceremony
  • subscribe — long-running processes, where waiting is the point

Related

function

A function is a top-level unit of work, written like a C# method — a return type, a name, typed parameters, a body. It…

Http.*

Make an outbound HTTP call to a URL you build at runtime — a webhook, a third-party API, a discovered endpoint…

subscribe

Declares that a workflow state waits on an event, and configures the wait — who may hold it, who may hand it on…