<p>Some languages, such as JS and Rust, make a distinction between normal/synchronous functions and <code>async</code> ones. An <code>async</code> function is typically syntax sugar for one which returns a future/promise, which like the name implies, will (theoretically) have a value at some point in the future. In order to get a value from this promise without using a callback function, one can <code>await</code> it. An <code>await</code> can only be used in an <code>async</code> function, and it will &quot;block&quot; (typically allowing other things to run in the thread) until the promise returns.</p>
<p>Both JS and Rust use an <code>async</code> keyword in front of the function keyword to make a function asynchronous. While JS uses a prefix <code>await</code> operator, Rust uses a postfix <code>.await</code> which looks like a property access. I've seen complains about both syntaxes, many of which I agree with.</p>
<p>What are some different options for <code>async</code>/<code>await</code> syntax, and what are their pros and cons?</p>

<syntax><language-design><async>
What are some options for syntax for async/await?
CC BY-SA 4.0
2023-05-19T17:08:31.000Z
The answers so far focus on `await`, but I’m curious about `async` as well — JS `async function foo()` vs Swift `func foo() async`, for example.
Bbrk24
CC BY-SA 4.0
2023-05-19T21:45:35.720Z
@Bbrk24 Ooh I've never seen postfix `async` before, it's worth making that an answer I think
rydwolf
<h1>Postfix <code>async</code></h1>
<p>Everything else so far talks about <code>await</code>, but what about <code>async</code>? Most languages I'm familiar with put it at the front, e.g:</p>
<pre class="lang-js prettyprint-override"><code>async function foo() {
  // ...
}
</code></pre>
<pre class="lang-csharp prettyprint-override"><code>async Task Foo()
{
  // ...
}
</code></pre>
<p>However, Swift puts it at the end:</p>
<pre class="lang-swift prettyprint-override"><code>func foo() async {
  // ...
}
</code></pre>
<p>My understanding is that this is to mirror the syntax of throws/try:</p>
<pre class="lang-swift prettyprint-override"><code>func foo() async {}
func bar() throws {}
func baz() async throws {}

await foo()
try bar()
try await baz()
</code></pre>

CC BY-SA 4.0
2023-05-19T21:48:54.537Z
2023-05-19T21:48:54.537Z
Bbrk24
<h1>Distinction between asynchronous functions and Tasks/Futures/Promises</h1>
<p>This is what Swift does. Asynchronous functions are <em><strong>not</strong></em> distinguished by returning a Task, as in many other languages. Rather, <code>async</code> is an intrinsic part of the function, and you can even overload on it — <code>foo()</code> and <code>await foo()</code> could do different things, and both or neither of these could return Tasks.</p>
<p>A major advantage to this is that it allows asynchronicity to apply at the level of the entire expression, rather than just a single method call. Instead of having to say <code>await (await x()).y()</code>, one can just write <code>await x().y()</code>.</p>
<p>The only way to kick off asynchronous work from synchronous code is to wrap it in a <code>Task { }</code>, equivalent to C# <code>Task.Run</code>.</p>

CC BY-SA 4.0
2023-05-16T19:58:47.997Z
2023-05-17T03:37:25.477Z
2023-05-17T03:37:25.477Z
Bbrk24
<p>In addition to previous answers:</p>
<ol>
<li>Automatic coloring via implicit conversions.
I.e., when we have an implicit conversion from F[X] to X, which is enabled when the result of the async function is used as X and this is 'safe'.  (Safety analysis depends on the type of F[_])</li>
</ol>
<p>details: one of the modes, supported by dotty-cps-async (user-level implementation of async/await for Scala)
Not very popular - people are afraid to enable it.</p>
<ol start="2">
<li><p>All is async by default (Ozz, variant of C# used in Singularity)</p>
</li>
<li><p>It's more about effects:  representing async computation as a context function which returns result in the direct form.
(i.e.  DirectContext[F] =&gt; A. instead F[A])</p>
</li>
</ol>
<p>Variants were discussed on the Scala contributors forum.
Exists few projects which explore this direction.</p>
<ol start="4">
<li><p>Computation expressions:  I.e., after async, we have expression language enriched by special constructions (let! binding, await, ...  etc.)
F#,</p>
</li>
<li><p>Using monadic effects DSL instead async functions (close to 4).
Haskell do-notation</p>
</li>
</ol>

CC BY-SA 4.0
2023-05-19T08:45:33.253Z
2023-05-19T08:45:33.253Z
rssh
<p>To add to <a href="https://languagedesign.stackexchange.com/a/658/504">rssh's answer</a>, the need for special syntax for async/await derives from a lack of a general effect system.<br />
Effect-aware languages such as Koka encode effects in function types and have <code>async</code> be an user-defined effect.<br />
In Koka, such a function may be written</p>
<pre><code>effect async
    fun await(f: (a -&gt; io ()) -&gt; io ()): a

fun sleep(d: duration): async ()
    await fn(cb) {
        set-timeout(cb, d.milliseconds)
    }

fun f(): async int
    sleep(2.ms)
    42
</code></pre>
<p>See <a href="https://www.microsoft.com/en-us/research/wp-content/uploads/2017/05/asynceffects-msr-tr-2017-21.pdf" rel="noreferrer">Structured Asynchrony with Algebraic Effects</a>, Daan Leijen, 2017, and <a href="https://github.com/koka-lang/koka/blob/v1-master/lib/std/async.kk" rel="noreferrer">Koka's <code>async</code>/<code>await</code> implementation</a>.</p>
<p>Other languages in this category include <a href="https://www.eff-lang.org/" rel="noreferrer">Eff</a>, <a href="https://effekt-lang.org/" rel="noreferrer">Effekt</a>, <a href="https://antelang.org/" rel="noreferrer">Ante</a>, <a href="https://granule-project.github.io/" rel="noreferrer">Granule</a>, and <a href="https://www.unison-lang.org/" rel="noreferrer">Unison</a>, among others.</p>
<p>As far as syntax go, some of the ones used by those languages are</p>
<ul>
<li><code>a -&gt; b c</code> as in <code>int -&gt; async string</code></li>
<li><code>a -{b}&gt; c</code> as in <code>int -{async}&gt; string</code></li>
<li><code>a -&gt; '{a} c</code> as in <code>int -&gt; '{async} string</code></li>
</ul>

CC BY-SA 4.0
2023-05-19T23:45:38.230Z
2023-05-20T00:27:50.897Z
2023-05-20T00:27:50.897Z
Longinus
<h1>Deferred <code>await</code></h1>
<p>A system can be constructed such that if the actual value of the future/promise is needed (e.g. for addition or printing, but not for purely structural operations), there's an implied <code>await</code>. An explicit <code>await</code> is probably needed too, but will be much less frequent.</p>

CC BY-SA 4.0
2023-05-16T19:56:37.147Z
2023-05-16T19:56:37.147Z
Adám
<p>A language sketch I once made, had await-by-default. That is, the expression <code>f(x)</code> was equivalent to <code>await f(x)</code> in languages like Python and JavaScript. In order to not await, there was special syntax, <code>f!(x)</code> which would call <code>f</code> but not await its return value.</p>
<p>A major downside for this is that this requires the entire language to be built around async/await semantics. Effectively, every function is an async function. Presumably, this would be hard to implement efficiently.</p>

CC BY-SA 4.0
2023-05-16T23:32:26.567Z
2023-05-16T23:32:26.567Z
Jasmijn
<h1>No special syntax</h1>
<p>In this case, <code>async</code>/<code>await</code> is just a normal function call.</p>
<p>This is an option for languages with coroutines. This includes Go and Lua, but may also work for any language with generators (e.g. C#, Rust, and Python).</p>
<p>An example of such an implementation is at <a href="https://github.com/ms-jpq/lua-async-await" rel="nofollow noreferrer">https://github.com/ms-jpq/lua-async-await</a></p>
<pre class="lang-lua prettyprint-override"><code>local a = require &quot;async&quot;, async = a.sync, await = a.wait, await_all = a.wait_all

local do_thing = async(function (val)
  local o = await(async_func())
  return o + val
end)

local main = async(function ()
  local thing = await(do_thing())

  local x = await(async_func())
  local y, z = await_all{async_func(), async_func()}
end)

main()
</code></pre>

CC BY-SA 4.0
2023-07-04T23:40:41.460Z
2023-07-04T23:40:41.460Z
somebody
<h1>Prefix <code>await</code> operator</h1>
<p><strong>Used by:</strong></p>
<ul>
<li>JavaScript</li>
<li>Python</li>
</ul>
<p><strong>Pros:</strong></p>
<p>(None)</p>
<p><strong>Cons:</strong></p>
<ul>
<li>Can be ambiguous with an identifier (e.g., since JS added this in after the fact, the error message for <code>await</code> in a non-<code>async</code> function is incredibly cryptic to maintain backwards compatibility)</li>
<li>Ambiguous what it's applying to, requiring parentheses (is <code>await y().z()</code> <code>await</code>ing <code>y()</code> or <code>.z()</code>?)</li>
<li>Reads out of order (<code>await (await fetch(...)).body()</code>)</li>
</ul>
<h1>Postfix <code>.await</code> property/operator</h1>
<p><strong>Used by:</strong></p>
<ul>
<li>Rust</li>
</ul>
<p><strong>Pros:</strong></p>
<ul>
<li>Reads in the same order as methods (<code>.post().await.to_string()</code>)</li>
<li>Distinct from other methods due to lack of <code>()</code></li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li>Looks like a struct/object property instead of an operator</li>
</ul>
<h1>Postfix <code>.await()</code> method/operator</h1>
<p><strong>Used by:</strong></p>
<p>(Nothing?)</p>
<p><strong>Pros:</strong></p>
<ul>
<li>Reads in the same order as methods</li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li>Looks like an ordinary method, rather than one which has a special meaning</li>
</ul>
<h1>Implied <code>await</code></h1>
<p>Implied <code>await</code> would be a system where a promise/future returned by a function would, by default, be <code>await</code>ed, with some sort of operator being used to force it to return a promise. This operator could even work on non-<code>async</code> functions, meaning that the interface with a function stays identical regardless of whether or not it's <code>async</code>, removing the need to go through and add <code>await</code> to every instance of a function call.</p>
<p><strong>Used by:</strong></p>
<ul>
<li>Kotlin (although <code>async</code> is called <code>suspend</code> there)</li>
</ul>
<p><strong>Pros:</strong></p>
<ul>
<li>Saves clutter</li>
<li>Interface with a function is the same regardless of whether it's <code>async</code></li>
</ul>
<p><strong>Cons:</strong></p>
<ul>
<li>Could cause confusion?</li>
</ul>

CC BY-SA 4.0
2023-05-16T19:33:54.343Z
2023-05-19T05:50:27.880Z
2023-05-19T05:50:27.880Z
rydwolf
CC BY-SA 4.0
2023-05-19T23:59:34.687Z
I would put a pro in "prefix await operator": since it's used by many big languages it's more common than the alternatives.

Implicit `await` can be ambiguous (do I want to pass the promise or the value? We could do based on type, but what if it's a generic?)
tarzh
CC BY-SA 4.0
2023-07-04T23:24:22.130Z
re: properties/methods - note that that's trivially solved by highlighting. also parentheses being (mostly) optional is an advantage of postfix `await`
somebody
CC BY-SA 4.0
2023-07-13T16:25:37.420Z
@tarzh Implicit await isn't ambiguous. The rule is simple: you don't look inside until you need the value. If you need to know the runtime type, that's looking at the value, so you await. If you pass it to a function in the same language, if it's not a generic, you just pass it along, until something awaits.

Then you keep on passing it along. If you pass it to a foreign function, you extrac the value, awaiting if needed, unless the ff is declared to take a future/promise/awaitable

Downside is awaiting is invisible.
Bob Kerns
CC BY-SA 4.0
2023-07-13T16:31:40.983Z
I'd want my IDE to higlight all potential  await points. Sometimes you need to know, particularly when it's a single-threaded environment (ie. JS) and  you typically depend on a guarantee no other task will be executing.
Bob Kerns
CC BY-SA 4.0
2023-05-16T20:13:34.170Z
Swift uses prefix await, but avoids the parentheses issue by letting you “factor it out”: Instead of `await (await x()).y()`, you can just say `await x().y()`.
Bbrk24
CC BY-SA 4.0
2023-05-16T20:19:19.987Z
@Bbrk24 Ooh, interesting. Maybe post that as an answer?
rydwolf
CC BY-SA 4.0
2023-05-16T20:27:02.423Z
Just added it to my existing answer.
Bbrk24
CC BY-SA 4.0
2023-05-17T18:39:14.437Z
“Looks like an ordinary method, rather than one which has a special meaning” isn’t the the whole point? Many methods are special in many languages
Seggan
CC BY-SA 4.0
2024-03-30T02:35:59.447Z
@BobKerns indeed, IntelliJ automatically highlights all functions calls that could `suspend`
Seggan
# What are some options for syntax for async/await?
Posted by: username_0 on 2023-05-16
Some languages, such as JS and Rust, make a distinction between normal/synchronous functions and `async` ones. An `async` function is typically syntax sugar for one which returns a future/promise, which like the name implies, will (theoretically) have a value at some point in the future. In order to get a value from this promise without using a callback function, one can `await` it. An `await` can only be used in an `async` function, and it will "block" (typically allowing other things to run in the thread) until the promise returns.

Both JS and Rust use an `async` keyword in front of the function keyword to make a function asynchronous. While JS uses a prefix `await` operator, Rust uses a postfix `.await` which looks like a property access. I've seen complains about both syntaxes, many of which I agree with.

What are some different options for `async`/`await` syntax, and what are their pros and cons?
**Tags:** syntax language-design async
> **Comments:**
> **username_1**: The answers so far focus on `await`, but I’m curious about `async` as well — JS `async function foo()` vs Swift `func foo() async`, for example.  
> **username_0**: @Bbrk24 Ooh I've never seen postfix `async` before, it's worth making that an answer I think  
---
## 8 answers
### Answer by username_0 on 2023-05-16. Score: 9
# Prefix `await` operator

**Used by:**

* JavaScript
* Python

**Pros:**

(None)

**Cons:**

* Can be ambiguous with an identifier (e.g., since JS added this in after the fact, the error message for `await` in a non-`async` function is incredibly cryptic to maintain backwards compatibility)
* Ambiguous what it's applying to, requiring parentheses (is `await y().z()` `await`ing `y()` or `.z()`?)
* Reads out of order (`await (await fetch(...)).body()`)

# Postfix `.await` property/operator

**Used by:**

* Rust

**Pros:**

* Reads in the same order as methods (`.post().await.to_string()`)
* Distinct from other methods due to lack of `()`

**Cons:**

* Looks like a struct/object property instead of an operator

# Postfix `.await()` method/operator

**Used by:**

(Nothing?)

**Pros:**

* Reads in the same order as methods

**Cons:**

* Looks like an ordinary method, rather than one which has a special meaning

# Implied `await`

Implied `await` would be a system where a promise/future returned by a function would, by default, be `await`ed, with some sort of operator being used to force it to return a promise. This operator could even work on non-`async` functions, meaning that the interface with a function stays identical regardless of whether or not it's `async`, removing the need to go through and add `await` to every instance of a function call.

**Used by:**

* Kotlin (although `async` is called `suspend` there)

**Pros:**

* Saves clutter
* Interface with a function is the same regardless of whether it's `async`

**Cons:**

* Could cause confusion?
> **Comments:**
> **username_1** (2023-05-16): Swift uses prefix await, but avoids the parentheses issue by letting you “factor it out”: Instead of `await (await x()).y()`, you can just say `await x().y()`.  
> **username_0** (2023-05-16): @Bbrk24 Ooh, interesting. Maybe post that as an answer?  
> **username_1** (2023-05-16): Just added it to my existing answer.  
> **username_9** (2023-05-17): “Looks like an ordinary method, rather than one which has a special meaning” isn’t the the whole point? Many methods are special in many languages  
> **username_7** (2023-05-19): I would put a pro in "prefix await operator": since it's used by many big languages it's more common than the alternatives.

Implicit `await` can be ambiguous (do I want to pass the promise or the value? We could do based on type, but what if it's a generic?)  
> **username_6** (2023-07-04): re: properties/methods - note that that's trivially solved by highlighting. also parentheses being (mostly) optional is an advantage of postfix `await`  
> **username_8** (2023-07-13): @tarzh Implicit await isn't ambiguous. The rule is simple: you don't look inside until you need the value. If you need to know the runtime type, that's looking at the value, so you await. If you pass it to a function in the same language, if it's not a generic, you just pass it along, until something awaits.

Then you keep on passing it along. If you pass it to a foreign function, you extrac the value, awaiting if needed, unless the ff is declared to take a future/promise/awaitable

Downside is awaiting is invisible.  
> **username_8** (2023-07-13): I'd want my IDE to higlight all potential  await points. Sometimes you need to know, particularly when it's a single-threaded environment (ie. JS) and  you typically depend on a guarantee no other task will be executing.  
> **username_9** (2024-03-30): @BobKerns indeed, IntelliJ automatically highlights all functions calls that could `suspend`  
---
### Answer by username_3 on 2023-05-19. Score: 8
To add to rssh's answer, the need for special syntax for async/await derives from a lack of a general effect system.
Effect-aware languages such as Koka encode effects in function types and have async be an user-defined effect.
In Koka, such a function may be written
effect async
    fun await(f: (a -> io ()) -> io ()): a

fun sleep(d: duration): async ()
    await fn(cb) {
        set-timeout(cb, d.milliseconds)
    }

fun f(): async int
    sleep(2.ms)
    42

See Structured Asynchrony with Algebraic Effects, Daan Leijen, 2017, and Koka's async/await implementation.
Other languages in this category include Eff, Effekt, Ante, Granule, and Unison, among others.
As far as syntax go, some of the ones used by those languages are

a -> b c as in int -> async string
a -{b}> c as in int -{async}> string
a -> '{a} c as in int -> '{async} string
---
### Answer by username_1 on 2023-05-19. Score: 4
Postfix async
Everything else so far talks about await, but what about async? Most languages I'm familiar with put it at the front, e.g:
async function foo() {
  // ...
}

async Task Foo()
{
  // ...
}

However, Swift puts it at the end:
func foo() async {
  // ...
}

My understanding is that this is to mirror the syntax of throws/try:
func foo() async {}
func bar() throws {}
func baz() async throws {}

await foo()
try bar()
try await baz()
---
### Answer by username_1 on 2023-05-16. Score: 4
# Distinction between asynchronous functions and Tasks/Futures/Promises

This is what Swift does. Asynchronous functions are ***not*** distinguished by returning a Task, as in many other languages. Rather, `async` is an intrinsic part of the function, and you can even overload on it — `foo()` and `await foo()` could do different things, and both or neither of these could return Tasks.

A major advantage to this is that it allows asynchronicity to apply at the level of the entire expression, rather than just a single method call. Instead of having to say `await (await x()).y()`, one can just write `await x().y()`.

The only way to kick off asynchronous work from synchronous code is to wrap it in a `Task { }`, equivalent to C# `Task.Run`.
---
### Answer by username_2 on 2023-05-19. Score: 4
In addition to previous answers:

1. Automatic coloring via implicit conversions.
   I.e., when we have an implicit conversion from F[X] to X, which is enabled when the result of the async function is used as X and this is 'safe'. (Safety analysis depends on the type of F[\_])

details: one of the modes, supported by dotty-cps-async (user-level implementation of async/await for Scala)
Not very popular - people are afraid to enable it.

2. All is async by default (Ozz, variant of C# used in Singularity)
3. It's more about effects: representing async computation as a context function which returns result in the direct form.
   (i.e. DirectContext[F] => A. instead F[A])

Variants were discussed on the Scala contributors forum.
Exists few projects which explore this direction.

4. Computation expressions: I.e., after async, we have expression language enriched by special constructions (let! binding, await, ... etc.)
   F#,
5. Using monadic effects DSL instead async functions (close to 4).
   Haskell do-notation
---
### Answer by username_4 on 2023-05-16. Score: 3
# Deferred `await`

A system can be constructed such that if the actual value of the future/promise is needed (e.g. for addition or printing, but not for purely structural operations), there's an implied `await`. An explicit `await` is probably needed too, but will be much less frequent.
---
### Answer by username_5 on 2023-05-16. Score: 3
A language sketch I once made, had await-by-default. That is, the expression `f(x)` was equivalent to `await f(x)` in languages like Python and JavaScript. In order to not await, there was special syntax, `f!(x)` which would call `f` but not await its return value.

A major downside for this is that this requires the entire language to be built around async/await semantics. Effectively, every function is an async function. Presumably, this would be hard to implement efficiently.
---
### Answer by username_6 on 2023-07-04. Score: 2
No special syntax
In this case, async/await is just a normal function call.
This is an option for languages with coroutines. This includes Go and Lua, but may also work for any language with generators (e.g. C#, Rust, and Python).
An example of such an implementation is at https://github.com/ms-jpq/lua-async-await
local a = require "async", async = a.sync, await = a.wait, await_all = a.wait_all

local do_thing = async(function (val)
  local o = await(async_func())
  return o + val
end)

local main = async(function ()
  local thing = await(do_thing())

  local x = await(async_func())
  local y, z = await_all{async_func(), async_func()}
end)

main()
---
