[Concurrency] Asynchronous functions

Is there any meaningful analogue to rethrows in an async/await world, i.e., a function which is async if and only if a provided closure parameter is async?

6 Likes

Thank you, fixed

1 Like

Maybe we can add reasync later should it be needed? At least the current proposal doesn't seem to clash with that.

1 Like

It's hard to say. I can certainly imagine situations where it might be useful, but I'm not sure there are enough to justify the complexity cost, which behind the scenes would be quite substantial — we'd essentially have to rig up a complete task just to call the function, then throw it away. The thing is that many higher-order functions probably need to think carefully about how they ought to work with an async function — guaranteeing sequential use is not necessarily what clients would actually want.

The most important use case would probably be withFoo functions that introduce a scoped value, and I'd really prefer to address those with a more targeted coroutine feature — they're problematic for a lot of other things besides async.

3 Likes

This design currently provides no way to prevent the current context from interleaving code while an asynchronous function is waiting for an operation in a different context. This omission is intentional: allowing for the prevention of interleaving is inherently prone to deadlock.

This should also be in the reference doc once it's included/accepted. It took a lot of cross-reading to find this sentence that makes sense of a lot of design decisions on the other threads. It's also easily surprising.

Rationale : This order restriction is arbitrary, but it's not harmful, and it eliminates the potential for stylistic debates.

Praise be.

1 Like

Why is async specified after the func declaration, rather than before, e.g. async func f()?

4 Likes

It's the same place where throws is specified, because it has a similar role in the type system.

Doug

19 Likes

Good explanation! I wonder though why:

await other.asyncFunction(otherActor: self)

In rust, one would have:

other.asyncFunction(otherActor: self).await

and optionally:

other.asyncFunction(otherActor: self).await?

Which is quite handy as other.asyncFunction(otherActor: self) returns a Future? await makes this the type returned by the Future? With .await you can chain on this? With rust if this is a Result<Success, Error> type, then ? resolves it to Success or returns Error from the "block".

Will await other.asyncFunction(otherActor: self) need parentheses to chain on its results?

1 Like

Async is an adjective, and throws is a verb, so adjective-object-verb makes sense. How/why does the type system factor into this?

1 Like

async and throws are both part of the type of a function. I.e, if you have

func foo() async throws {}

let bar = foo

then the type of bar is () -> () async throws. OTOH, if you had something like:

private func foo() {}

public let bar = foo()

then the type of bar is just () -> () (i.e., private is not part of the type).

2 Likes

Unrelated, but what's that language? It doesn't seem to be English.

Subject, rather.

Or, async is an adverb, being an abbreviation for “asynchronously”: () async -> Int is a function that asynchronously returns an integer.

4 Likes

You can find a detailed discussion of this in the asynchronous functions proposal. The short answer is that await is like try and doesn't need to be pedantically placed on the exact asynchronous operation, as long as it logically "covers" it.

4 Likes

Are there any plans on naming conventions for async functions? for example in C# its convention to postfix async function names with "async". Is this something that has been discussed for swift?

It doesn't seem necessary to postfix the name when the async attributes requires the use of await at the call site.

10 Likes

I imagine it is similar to other uses of the async/await keywords in other languages, it makes it clear that asynchronous work is done in that function.

Plus from an API consumer point of view, you may not know the implementation of a method and what it is doing, knowing it has asynchronous calls which may be suspended

The fact that you have to await the function, or use it with a local async variable, should be enough to make that distinction. It's the same reason we don't end methods marked with throws with Throwing.

15 Likes

In what sense? The compiler telling you?

It’s the same case with throws, if you can only see the public declaration then you know that there is the chance of the function calling asynchronous code.

I guess the difference is that with throws you can override catching/failing gracefully with try! for asynchronous functions you can’t override that...

Maybe this can continue over [Concurrency] Asynchronous functions? I think it's getting out of a roadmap thread.

(Moderator note: this post and the chain of posts it responds to were originally in the roadmap thread)

1 Like