# Concurrency and @escaping closures

**URL:** <https://forums.swift.org/t/concurrency-and-escaping-closures/55798>\
**Category:** Discussion\
**Tags:** concurrency\
**Created:** [March 8, 2022, 8:47pm UTC](https://forums.swift.org/t/concurrency-and-escaping-closures/55798 "2022-03-08T20:47:36Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![bjhomer](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/bjhomer/32/313_2.png) [@bjhomer](https://forums.swift.org/u/bjhomer)\
**Post date:** [March 8, 2022, 8:47pm UTC](https://forums.swift.org/t/concurrency-and-escaping-closures/55798/1 "2022-03-08T20:47:36Z")

</div>

Currently, there's a hole in the Swift Concurrency story regarding escaping closures. For example:

```swift
// This function does not document whether the completion
// closure will be invoked on the main thread or on some
// other thread.
func runSomethingLater(_ completion: @escaping ()->Void) {
    DispatchQueue.global().async {
        completion()
    }
}

@MainActor
func mainThreadThing() {
    assert(Thread.isMainThread)
}

func main() {
    runSomethingLater {
        // The compiler doesn't know whether this
        // closure will run on the main thread or
        // a background thread. It allows this call
        // without an `await`, even though we're 
        // actually on a background thread here. This
        // will trigger the 'assert' in mainThreadThing()
        mainThreadThing()
    }
}

```

This means that annotating a function with `@MainActor` is not currently sufficient to ensure that it actually runs on the main thread. This is the current state of things. No warning is given for this code, even with `-warn-concurrency` enabled.

I know there are proposals for `@Sendable` closures and Senable checking., but I don't think I have a complete understanding of what that will entail. Is there a plan that will cause the code above to issue either a warning or an error at some point in the future?

---

<div class="post-metadata">

**Author:** ![ksluder](https://avatars.discourse-cdn.com/v4/letter/k/eada6e/32.png) [@ksluder](https://forums.swift.org/u/ksluder)\
**Post date:** [March 8, 2022, 9:39pm UTC](https://forums.swift.org/t/concurrency-and-escaping-closures/55798/2 "2022-03-08T21:39:30Z")

</div>

My understanding is that Sendable checking will enforce that you either `await mainThreadThing()` or mark the closure argument to `runSomethingLater` as `@MainActor in`.

---

<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 8, 2022, 11:22pm UTC](https://forums.swift.org/t/concurrency-and-escaping-closures/55798/3 "2022-03-08T23:22:05Z")

</div>

> [@bjhomer](#):
>
> I know there are proposals for `@Sendable` closures and Senable checking., but I don't think I have a complete understanding of what that will entail. Is there a plan that will cause the code above to issue either a warning or an error at some point in the future?

The Swift 5.6 beta I have installed correctly diagnoses this:

```swift
error: call to main actor-isolated global function 'mainThreadThing()' in a synchronous nonisolated context
        mainThreadThing()
        ^
note: calls to global function 'mainThreadThing()' from outside of its actor context are implicitly asynchronous
func mainThreadThing() {
     ^

```

Doug

---

<div class="post-metadata">

**Author:** ![bjhomer](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/bjhomer/32/313_2.png) [@bjhomer](https://forums.swift.org/u/bjhomer)\
**Post date:** [March 9, 2022, 4:25am UTC](https://forums.swift.org/t/concurrency-and-escaping-closures/55798/4 "2022-03-09T04:25:21Z")

</div>

Okay, that's good to know. I investigated more, and found some more interesting information. As posted above, the code does indeed produce an error. However, if `func main()` is itself tagged with `@MainActor`, then the warning goes away.

Here's the actual code from my sample project:

```swift
@MainActor
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        callCompletion {
            mainThreadThing()
        }
    }
}

func callCompletion(_ completion: @escaping ()->Void) {
    DispatchQueue.global().async {
        completion()
    }
}

@MainActor
func mainThreadThing() {
    assert(Thread.isMainThread)
}

```

Because `viewDidLoad` is implicitly `@MainActor`, the error seems to have gone away, and yet the assertion still fails. Is the compiler assuming that the completion handler is also being implicitly annotated with `@MainActor`?

---

<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 9, 2022, 9:09pm UTC](https://forums.swift.org/t/concurrency-and-escaping-closures/55798/5 "2022-03-09T21:09:59Z")

</div>

> [@bjhomer](#):
>
> ```swift
> func callCompletion(_ completion: @escaping ()->Void) {
> DispatchQueue.global().async {
> completion()
> }
> }
> 
> ```

Here, `completion` needs to be `Sendable` because it is captured in a closure that will be executed concurrently. However, your `callCompletion` function doesn't use any concurrency (per the definition in [SE-0337](https://github.com/apple/swift-evolution/blob/main/proposals/0337-support-incremental-migration-to-concurrency-checking.md)), so Swift 5 doesn't warn. Under Swift 6, you get:

```swift
t7.swift:19:9: error: capture of 'completion' with non-sendable type '() -> Void' in a `@Sendable` closure
        completion()
        ^
t7.swift:19:9: note: a function type must be marked '@Sendable' to conform to 'Sendable'
        completion()
        ^

```

At present, we don't get a corresponding warning for this code under `-warn-concurrency`. I consider that a bug that we should fix.

Doug
