7
$\begingroup$

In a lot of modern languages (such as Python), asynchronous functions (those that return coroutines) must be explicitly marked as such:

async function foo():
    pass

Is there any specific reason for this, and if so are there any alternatives?

$\endgroup$
6
  • 1
    $\begingroup$ “Primarily python” — off the top of my head, I don’t know of any language with an await operator that doesn’t require this. $\endgroup$ Commented May 18, 2023 at 11:51
  • 1
    $\begingroup$ As opposed to what, inferring asyncness from the use of awaits in the body? Though it's not like that isn't how generators work, it's still pretty clear why that would be undesirable... $\endgroup$ Commented May 18, 2023 at 11:52
  • 1
    $\begingroup$ @UnrelatedString Clarified that I'm asking for alternatives, if any. $\endgroup$ Commented May 18, 2023 at 11:54
  • 1
    $\begingroup$ Does “just don’t have await at all” count as a valid alternative? Swift only had callbacks until late 2021 when they finally added await. $\endgroup$ Commented May 18, 2023 at 11:55
  • 2
    $\begingroup$ this blog post by Bob Nystrom about colours is classic. $\endgroup$ Commented May 18, 2023 at 19:16

2 Answers 2

8
$\begingroup$

No

There are various solutions to avoid needing to mark functions as async.

Making every function async by default

Some languages work this way. All functions return promises in theory and can use your await syntax.

This is what Go does.

Making functions async if they contain await

Since a non-async function can't await, it makes sense to just automatically make functions with that syntax async. This is how generators work in Python, including yield makes them a generator.

Also if you don't have await or insert it implicitly there is no way to know.

Disadvantage is the return type changes depending on syntax. A stub method now returns the wrong type if it has no await.

Making functions async depending on their return type

If your language is statically typed and requires functions to have a return type specified, you could use that to detect if a function is async. Requires no special syntax.

Disadvantage is if your function returns a literal promise that wouldn't be possible. You could have separate types for automatic promises and manually created promises to resolve this issue, but then you have the whole complexity of converting between them and it might not be worth it.

$\endgroup$
8
  • 1
    $\begingroup$ Of course, if Python inferred async from await, they could also add await pass or something to that effect. $\endgroup$ Commented May 18, 2023 at 11:59
  • $\begingroup$ Yep, but it's a bit annoying. I've had this problem with generators where even throwing a NotImplementedException immediately is still a type error because it won't return a generator without a yield. A await pass could give a potential syntax for async functions but still annoying to need to write code after the exception throw to make it work properly $\endgroup$ Commented May 18, 2023 at 12:03
  • $\begingroup$ @Bbrk24 what is the difference of always having to add await vs always having to add async? Seems like fully equivalent, you just swap what you have to add, but in either case you need to add something. $\endgroup$ Commented May 18, 2023 at 12:07
  • 5
    $\begingroup$ The first option is discussed in excellent detail in the blog post What colour is your function?. $\endgroup$ Commented May 18, 2023 at 12:10
  • 1
    $\begingroup$ What do you mean with your first point? Go functions are not async and they does not return a promise. They are all synchronous and blocking, e.g. you cannot call two of them and then wait for them both. In Go, you must use go-routines for concurrency. $\endgroup$ Commented Sep 6 at 11:54
6
$\begingroup$

Marking asynchronous functions async is indeed unnecessary in many languages, as mousetail's answer explains. However, in C#, the async function marker keyword was needed for another reason: to to maintain backwards compatibility, in case an existing (non-async) method used await as a variable or method name. So await would only be treated as a keyword if it was in a method marked async. More details are given in this MSDN blog post.

I speculate that the async/await syntax was then simply copied into other languages like Python and JavaScript without too much thought, which is why it's present there, even when they may not have the same backwards-compatibility goals, or a better new design could've been used. But I can't be sure on that.

$\endgroup$
1
  • 4
    $\begingroup$ I’d argue that it’s even more necessary in JS than C#: C# versions both the compiler and runtime, but JS needs to support decades-old code. $\endgroup$ Commented May 18, 2023 at 13:10

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.