# SE-0338: Clarify the Execution of Non-Actor-Isolated Async Functions

**URL:** <https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621>\
**Category:** Proposal Reviews\
**Created:** [January 14, 2022, 10:18pm UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621 "2022-01-14T22:18:05Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [January 14, 2022, 10:18pm UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/1 "2022-01-14T22:18:05Z")

</div>

Hello Swift community,

The review of [SE-0338 "Clarify the Execution of Non-Actor-Isolated Async Functions"](https://github.com/apple/swift-evolution/blob/main/proposals/0338-clarify-execution-non-actor-async.md) begins now and runs through January 24, 2022.

Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to the review manager. When emailing the review manager directly, please keep the proposal link at the top of the message.

##### What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

- What is your evaluation of the proposal?
- Is the problem being addressed significant enough to warrant a change to Swift?
- Does this proposal fit well with the feel and direction of Swift?
- If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
- How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at

> [https://github.com/apple/swift-evolution/blob/master/process.md](https://github.com/apple/swift-evolution/blob/master/process.md)

Thank you,

Doug Gregor  
Review Manager

---

<div class="post-metadata">

**Author:** ![marco.masser](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/marco.masser/32/6010_2.png) [@marco.masser](https://forums.swift.org/u/marco.masser)\
**Post date:** [January 17, 2022, 9:52am UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/2 "2022-01-17T09:52:38Z")

</div>

While I do not feel qualified to seriously evaluate this proposal, I do want to state that I am in favor of clarification on this behavior (not surprising, since I [ran into this issue](https://forums.swift.org/t/hang-when-awaiting-call-to-actor/54026) in production). Also, a big thank you to everyone who addressed this issue so quickly, especially @kavon!

---

<div class="post-metadata">

**Author:** ![nonsensery](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nonsensery/32/4317_2.png) [@nonsensery](https://forums.swift.org/u/nonsensery)\
**Post date:** [January 18, 2022, 5:55pm UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/3 "2022-01-18T17:55:46Z")

</div>

The Sendability section reads:

> the arguments and results of _all_ `async` calls must be `Sendable` unless … the caller and callee are both known to be non-actor-isolated.

Is that allowed (i.e. known to be safe) because both calls would be part of the same `Task`?

---

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [January 18, 2022, 6:05pm UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/4 "2022-01-18T18:05:09Z")

</div>

> [@nonsensery](#):
>
> The Sendability section reads:
> 
> > the arguments and results of _all_ `async` calls must be `Sendable` unless … the caller and callee are both known to be non-actor-isolated.
> 
> Is that allowed (i.e. known to be safe) because both calls would be part of the same `Task` ?

Yes, that is correct. With a call (whether `async` or synchronous), the caller and callee are always part of the same task. When both are non-isolated (or both have the same actor isolation), the call won't let the data escape into another actor, either.

Doug

---

<div class="post-metadata">

**Author:** ![John\_McCall](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/john_mccall/32/1351_2.png) [@John\_McCall](https://forums.swift.org/u/John_McCall)\
**Post date:** [January 18, 2022, 8:20pm UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/5 "2022-01-18T20:20:17Z")

</div>

Right. Non-`Sendable` values require all their uses to be totally ordered by the _happens before_ relation. Tasks totally order their execution, so if a non-`Sendable` value is isolated to a single task, that's good enough. Actors totally order the execution of their actor-isolated functions, so if a non-`Sendable` value is isolated to a single actor, that's also good enough. Swift doesn't currently distinguish these things at a precise enough level to allow e.g. an actor function to take a task-isolated parameter; instead, we just assume that all non-`Sendable` values accessible in an actor-isolated function are meant to be isolated to the actor. As long as that's true, we need to restrict non-`Sendable` values from crossing an actor isolation boundary on a task; but there's no need to restrict values from being passed around in non-isolated code.

---

<div class="post-metadata">

**Author:** ![technikyle](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/technikyle/32/21180_2.png) [@technikyle](https://forums.swift.org/u/technikyle)\
**Post date:** [January 20, 2022, 5:48am UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/6 "2022-01-20T05:48:52Z")

</div>

Thanks for the write-up. I'm unclear on 2 points:

1. Does the non-actor-isolated global executor serialize access (like an actor executor) or allow parallelism?

2. This has been discussed but it is still unclear to me. Re:`the caller and callee are both known to be non-actor-isolated`. I understand why that is ok within the same Task, but can you clarify if that non-Sendable args and results can be used from different Tasks like this example:

```swift
class Test {
    var int = 0
}

func foo(_ arg: Test) async {
    arg.int = Int.random(in: (0..<100))
}

let test = Test()

Task.detached {
    await foo(test)
}

Task.detached {
    await foo(test)
}

```

---

<div class="post-metadata">

**Author:** ![kavon](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/kavon/32/9774_2.png) [@kavon](https://forums.swift.org/u/kavon)\
**Post date:** [January 20, 2022, 8:28pm UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/7 "2022-01-20T20:28:40Z")

</div>

> - What is your evaluation of the proposal?

I think this proposal will do an excellent job of resolving a confusing corner-case of Swift's concurrency model. The existing "sticky" behavior of non-isolated async functions has been the subject of at least one [bug report](https://bugs.swift.org/browse/SR-15595) because the reasoning for that behavior wasn't intuitive.

> - Is the problem being addressed significant enough to warrant a change to Swift?

Absolutely. If it were not resolved, I think programmers would keep running into hard-to-debug "overhang" issues.

> - Does this proposal fit well with the feel and direction of Swift?

Yes.

> - If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

N/A

> - How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I did a quick read and also helped push this issue into the spotlight.

---

<div class="post-metadata">

**Author:** ![John\_McCall](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/john_mccall/32/1351_2.png) [@John\_McCall](https://forums.swift.org/u/John_McCall)\
**Post date:** [January 20, 2022, 9:08pm UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/8 "2022-01-20T21:08:00Z")

</div>

> [@technikyle](#):
>
> Does the non-actor-isolated global executor serialize access (like an actor executor) or allow parallelism?

No, it does not serialize execution. I should clarify that the non-actor-isolated global executor is not a new concept; it is where new tasks begin running if they do not inherit an actor to be isolated to, as well as where tasks resume running after various kinds of suspension.

> [@technikyle](#):
>
> This has been discussed but it is still unclear to me. Re: `the caller and callee are both known to be non-actor-isolated` . I understand why that is ok within the same Task, but can you clarify if that non-Sendable args and results can be used from different Tasks like this example:

No, they cannot. Here's how that restriction works:

- In general, it's fine to pass a non-`Sendable` value from a non-isolated `async` function (like the closure passed to `Task.detached` to another non-isolated `async` function (like `foo`).
- In this case, since `test` is a value from an enclosing function, the closure passed to `Task.detached` must capture it.
- A closure that captures a non-`Sendable` value must itself be non-`Sendable`.
- But `Task.detached` must be passed a `Sendable` function, so this is ill-formed.

This restriction on captures is not new; it's always been part of how `Sendable` works.

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [January 26, 2022, 4:25pm UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/9 "2022-01-26T16:25:52Z")

</div>

+1 - I agree with everything in the proposal.

- I agree that `async` calls from an actor-isolated function should not be guaranteed to run on the actor's executor. Aspects of the actor design (such as reentrancy) suggest to me that they are designed for maximum throughput while allowing safe access to isolated data, _not_ for performing suspending operations on the actor's executor - i.e. it seems to me that the best way to use an actor is to quickly read any state you need up-front, perform any operations with that data on your own time, then return to the actor only to update its state.

- I agree that all arguments and return values of `async` functions must be `Sendable`. I actually had a draft reply to the [Improving Sendable](https://forums.swift.org/t/improving-sendable/52377) pitch which arrived at the same conclusion. Unfortunately I was distracted by other things and forgot to post it (I sometimes write draft replies, then leave them to stew for a bit while I think about things a bit more). Here was my reasoning, which is more about the underlying threads tasks are ultimately scheduled on and types with reference semantics than the more formal reasoning in this proposal:

> One thing that I've been wondering about (and perhaps this is the right place to bring it up) is whether we should require that arguments to _all_ `async` functions are `Sendable`.
> 
> My understanding is that we want `Sendable` enforcement to eventually become a guarantee against data races. If you pass some data in to an `async` function, we have no idea whether or not there are other references to its memory, whether it has been passed to any other `async` functions, and whether any of them will mutate the memory's contents. And when the function you are calling suspends, we don't know which thread it's ultimately going to resume on, and whether or not its reads will be serialised with writes from other functions or overlap with them.
> 
> The thing that gives us those guarantees is `Sendable`.

So yeah, these look like good, important changes to me.

---

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [January 27, 2022, 10:57pm UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/10 "2022-01-27T22:57:59Z")

</div>

Hey all, thank you for your reviews here and on the pitch thread. The Core Team has accepted this proposal and a proper announcement will be coming soon.

---

<div class="post-metadata">

**Author:** ![Kai\_Br](https://avatars.discourse-cdn.com/v4/letter/k/4da419/32.png) [@Kai\_Br](https://forums.swift.org/u/Kai_Br)\
**Post date:** [January 31, 2022, 8:15am UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/11 "2022-01-31T08:15:35Z")

</div>

Please correct me if this isn’t appropriate to ask here, but we are trying to build an architecture with Swift concurrency and are puzzled how to do this after this change. I described our issue here: [How to create an object graph with… | Apple Developer Forums](https://developer.apple.com/forums/thread/699458)

---

<div class="post-metadata">

**Author:** ![Avi](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/avi/32/2962_2.png) [@Avi](https://forums.swift.org/u/Avi)\
**Post date:** [January 31, 2022, 8:57am UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/12 "2022-01-31T08:57:02Z")

</div>

You should start a new thread.

---

<div class="post-metadata">

**Author:** ![Kai\_Br](https://avatars.discourse-cdn.com/v4/letter/k/4da419/32.png) [@Kai\_Br](https://forums.swift.org/u/Kai_Br)\
**Post date:** [January 31, 2022, 9:04am UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/13 "2022-01-31T09:04:09Z")

</div>

Thank you. I did: " How to create an object graph with serialized access using Swift concurrency?"

---

<div class="post-metadata">

**Author:** ![Donellen](https://avatars.discourse-cdn.com/v4/letter/d/ec9cab/32.png) [@Donellen](https://forums.swift.org/u/Donellen)\
**Post date:** [March 23, 2022, 10:31am UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/14 "2022-03-23T10:31:39Z")

</div>

So in other words: non-sendable types cannot escape from a Task or an Actor to another Actor or Task, right?

---

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [March 25, 2022, 6:52pm UTC](https://forums.swift.org/t/se-0338-clarify-the-execution-of-non-actor-isolated-async-functions/54621/15 "2022-03-25T18:52:10Z")

</div>

> [@Donellen](#):
>
> So in other words: non-sendable types cannot escape from a Task or an Actor to another Actor or Task, right?

Exactly.

Doug
