# Sending a var risks causing data races

**URL:** <https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051>\
**Category:** Using Swift\
**Tags:** concurrency\
**Created:** [January 7, 2025, 1:13pm UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051 "2025-01-07T13:13:58Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![dsharma](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dsharma/32/38922_2.png) [@dsharma](https://forums.swift.org/u/dsharma)\
**Post date:** [January 7, 2025, 1:13pm UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/1 "2025-01-07T13:13:58Z")

</div>

I have the following code:

```swift
actor Pipeline {
    let updater = Updater()
    
    func startUpdates() {
        updater.startUpdates()
    }
    
    func stopUpdates() async {
        await updater.stopUpdates() //Error: Sending 'self.updater' risks causing data races
    }
}

final class Updater {
    
    func startUpdates() {
        print("started updates")
    }
    
    func stopUpdates() async {
        print("stopped updates")
    }
}

```

While I can fix the error by marking `Updater` as `Sendable`, I will not be able to add member variables to this class. I also tried adding `nonisolated` to `updater` but it gives error again:

```
 ` nonisolated let updater = Updater()`

   `'nonisolated' can not be applied to variable with non-'Sendable' type 'Updater'

```

---

<div class="post-metadata">

**Author:** ![Cyberbeni](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/cyberbeni/32/46241_2.png) [@Cyberbeni](https://forums.swift.org/u/Cyberbeni)\
**Post date:** [January 7, 2025, 1:35pm UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/2 "2025-01-07T13:35:12Z")

</div>

Updater either needs to be Sendable and use Mutex (or similar) for data storage or it needs to be an actor.

---

<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 7, 2025, 1:52pm UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/3 "2025-01-07T13:52:53Z")

</div>

Because `Updater` is not sendable, it does not guarantee that it is safe to use concurrently.

By default, if you mark `Updater` as `Sendable`, you are limited to doing things that the compiler can prove are safe all by itself. For classes, it's pretty severe; for instance, you cannot add _any_ mutable data members, of _any_ type.

```swift
final class Problem: Sendable {
  var x: Int = 0
      `- error: stored property 'x' of 'Sendable'-conforming class 'Problem' is mutable
}

```

That doesn't mean you can't do it! You have a couple of options:

1. Convert the class in to an `actor`. This will automatically ensure accesses to your mutable data are serialised. The compiler knows this - in fact, you don't even need to mark actors as `Sendable` because they just inherently _are_.

2. Perform your own serialisation/locking. If you mark the updater as `@unchecked Sendable`, you will not be restricted to things the compiler can prove are safe -- of course, this means _you_ are responsible for proving that the type is thread-safe.

---

<div class="post-metadata">

**Author:** ![Jon\_Shier](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jon_shier/32/921_2.png) [@Jon\_Shier](https://forums.swift.org/u/Jon_Shier)\
**Post date:** [January 7, 2025, 2:17pm UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/4 "2025-01-07T14:17:50Z")

</div>

I think there's more nuance here since the example, as given, doesn't have any mutation in the first place.

Fundamentally, it's due to the fact that `Updater`'s `async` work isn't isolated, so the call to `stopUpdates()` is performed on the default executor rather than the `Pipeline` context you may expect. Since `Updater` itself isn't `Sendable`, trying to send the `updater` instance from the `Pipeline` context to the default context will fail. That's in addition to any future mutation that may make the instance more unsafe. There's been some discussion of making non isolated `async` funcs default to using the current context, which I think would fix the original issue.

---

<div class="post-metadata">

**Author:** ![mattie](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mattie/32/13267_2.png) [@mattie](https://forums.swift.org/u/mattie)\
**Post date:** [January 7, 2025, 3:27pm UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/5 "2025-01-07T15:27:06Z")

</div>

Very generally speaking, I think trying to make reference (class) types Sendable is a trap. It's tempting because it can make some immediate problems go away. But as you are seeing it can be quite hard to pull off.

And that will lead you down the path of trying out actors. Which also fixes some immediate problems. But, now all the types inputs and outputs have to be Sendable and the interface must now be async.

If you can solve this problem by _removing concurrency_ from the system, that's definitely what I would recommend.

(What @Jon_Shier says is true, there is on-going to work to try to make this less problematic. However, this is a long-ways off.)

---

<div class="post-metadata">

**Author:** ![dsharma](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dsharma/32/38922_2.png) [@dsharma](https://forums.swift.org/u/dsharma)\
**Post date:** [January 7, 2025, 5:23pm UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/6 "2025-01-07T17:23:28Z")

</div>

@mattie By removing concurrency, you mean getting rid of Swift Concurrency and using other concurrency tools such as mutex?

---

<div class="post-metadata">

**Author:** ![mattie](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mattie/32/13267_2.png) [@mattie](https://forums.swift.org/u/mattie)\
**Post date:** [January 7, 2025, 6:35pm UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/7 "2025-01-07T18:35:06Z")

</div>

Sorry I wasn't nearly clear enough. I meant reduce the amount of concurrency constructs in use. For example, I have encountered many situations actors are used when really a system would be much easier to model with MainActor state and just a handful of non-isolated async functions to shift some work to background threads.

I don't see enough of your project here to know if that's a good idea or not, but it's something to think about.

Of course you could also use mutexes/queues or other mechanisms. Those do still work.

---

<div class="post-metadata">

**Author:** ![tclementdev](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tclementdev/32/13398_2.png) [@tclementdev](https://forums.swift.org/u/tclementdev)\
**Post date:** [January 7, 2025, 7:04pm UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/8 "2025-01-07T19:04:22Z")

</div>

This should also help once it lands: [[Pitch] Inherit isolation by default for async functions](https://forums.swift.org/t/pitch-inherit-isolation-by-default-for-async-functions/74862).

---

<div class="post-metadata">

**Author:** ![CrystDragon](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/crystdragon/32/10461_2.png) [@CrystDragon](https://forums.swift.org/u/CrystDragon)\
**Post date:** [January 8, 2025, 4:20am UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/9 "2025-01-08T04:20:54Z")

</div>

I do not dislike the idea of "inheriting isolation by default", but I wonder if that can help in this situation.

Even though one day `func stopUpdates() async` can be called without changing isolation domain, the concurrency problem does not go away. Because practically, this function will probably need to access some shared mutable state stored in `Update`. At the end of the day, the developer still need to think about how to make `Updater` safe to use concurrently.

@dsharma you can already achieve the same semantics manually, if that's what you want:

```swift
final class Updater {
    func stopUpdates(_ isolation: isolated (any Actor)? = #isolation) async {
        print("stopped updates")
    }
}

actor Pipeline {
    let updater = Updater()
    func stopUpdates() async {
        await updater.stopUpdates() // This is OK now, but remember under this way you are still not free to access updater in random contexts
    }
}

```

---

<div class="post-metadata">

**Author:** ![dsharma](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dsharma/32/38922_2.png) [@dsharma](https://forums.swift.org/u/dsharma)\
**Post date:** [January 8, 2025, 7:45am UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/10 "2025-01-08T07:45:26Z")

</div>

> [@CrystDragon](#):
>
> ```swift
> func stopUpdates(_ isolation: isolated (any Actor)? = #isolation) async {
> print("stopped updates")
> }
> 
> ```

Yeah, that works great. I see there are plenty of options and opinions to solve a basic problem. But as you said in the code comment that `stopUpdates` should not be called from random contexts, I tried the following and it still compiles (without an actor).

```swift
final class AnotherPipeline {
    let updater = Updater()
    
    
    func startUpdates() {
        updater.startUpdates()
    }
    
    func stopUpdates() async {
        await updater.stopUpdates()
    }
}

final class Updater {
    
    func startUpdates() {
        print("started updates")
    }
    
    func stopUpdates(_ isolation: isolated (any Actor)? = #isolation) async {
            print("stopped updates") // This is OK now, but remember under this way you are still not free to access updater in random contexts
        }
}

```

---

<div class="post-metadata">

**Author:** ![dsharma](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dsharma/32/38922_2.png) [@dsharma](https://forums.swift.org/u/dsharma)\
**Post date:** [January 8, 2025, 11:04am UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/11 "2025-01-08T11:04:39Z")

</div>

Could you please explain a bit more what exactly is going on when you mark the function as

```
 `func stopUpdates(_ isolation: isolated (any Actor)? = #isolation) async `

```

I can't find much documentation about this syntax in the language but is it just statically erasing type information so that it compiles but flag raise issues in the runtime?

---

<div class="post-metadata">

**Author:** ![CrystDragon](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/crystdragon/32/10461_2.png) [@CrystDragon](https://forums.swift.org/u/CrystDragon)\
**Post date:** [January 8, 2025, 12:08pm UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/12 "2025-01-08T12:08:35Z")

</div>

This is a feature brought by [SE-0420](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0420-inheritance-of-actor-isolation.md).

---

<div class="post-metadata">

**Author:** ![dsharma](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dsharma/32/38922_2.png) [@dsharma](https://forums.swift.org/u/dsharma)\
**Post date:** [January 9, 2025, 3:50pm UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/13 "2025-01-09T15:50:50Z")

</div>

Is it not possible to make whole class initialiser isolated to a particular isolation domain? In other words, if a class has an `init` method with `#isolation` parameter, then all the methods and properties of that class instance be automatically isolated to that domain.

---

<div class="post-metadata">

**Author:** ![CrystDragon](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/crystdragon/32/10461_2.png) [@CrystDragon](https://forums.swift.org/u/CrystDragon)\
**Post date:** [January 10, 2025, 4:16am UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/14 "2025-01-10T04:16:11Z")

</div>

I don't think Swift's type system supports value-based isolation nowadays. However, if you can model your isolation as a globally shared one, then it's appropriate to make the actor a `@globalActor`.

---

<div class="post-metadata">

**Author:** ![dsharma](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dsharma/32/38922_2.png) [@dsharma](https://forums.swift.org/u/dsharma)\
**Post date:** [January 10, 2025, 7:58am UTC](https://forums.swift.org/t/sending-a-var-risks-causing-data-races/77051/15 "2025-01-10T07:58:03Z")

</div>

You are right that calling an async function through inheriting isolation domain of the caller does not solve anything as far as concurrency is concerned. Calling function like `stopUpdates` on a member variable of an Actor (which is not an Actor or confirms to Sendable) is an issue.
