# Sendable in Foundation

**URL:** <https://forums.swift.org/t/sendable-in-foundation/59577>\
**Category:** Using Swift\
**Tags:** foundation, concurrency\
**Created:** [August 10, 2022, 10:14pm UTC](https://forums.swift.org/t/sendable-in-foundation/59577 "2022-08-10T22:14:56Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![OneSadCookie](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/onesadcookie/32/3205_2.png) [@OneSadCookie](https://forums.swift.org/u/OneSadCookie)\
**Post date:** [August 10, 2022, 10:14pm UTC](https://forums.swift.org/t/sendable-in-foundation/59577/1 "2022-08-10T22:14:56Z")

</div>

I noticed in Xcode 14 betas that `UserDefaults` is explicitly marked non-`Sendable`, even though the documentation states that it's thread-safe.

I thought this might be because it's an `open` class, but Foundation doesn't seem to treat that as a concern when adding `@unchecked Sendable`, for example `URLResponse` is _likely_ to be subclassed, but is still marked `Sendable`.

It'd be really helpful if the ObjC "sendability audit" macros contained _reasons_ why a class is marked `Sendable` or not, because in some cases it can be quite subtle!

In general, I'm struggling to understand some of the decisions that have been made. For example,

- `NumberFormatter` is marked `Sendable`, despite having mutable state, and unlike any of the other formatters
- `NSNumber` is marked `Sendable`, unlike `NSValue` and despite being `open` and having known subclasses
- `FileHandle` is marked `Sendable` despite having mutable state (`readabilityHandler` etc)
- `Operation` has many methods that only make sense when used from other threads, but is not marked `Sendable`, possibly because it's intended to be subclassed, but then again that didn't stop `URLResponse`
- `OperationQueue` is not marked `Sendable` despite the documentation implying it's thread-safe

It feels like there's some mistakes here, and some cases where subtleties are lost due to a lack of expressive power in the language(s). For example, perhaps

- An ObjC feature to make a class non-open, and export that to swift
- An attribute like `@subclassesMayBeSendable` for a class to say that it, itself, could be `Sendable` but wishes to allow subclassing (like the special treatment `NSObject` gets)
- An attribute like `@subclassesMustBeSendable`, which extends the previous attribute, but also allows any instance of this class to be treated as `Sendable` (like `URLRequest` apparently needs)

---

<div class="post-metadata">

**Author:** ![ffried](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ffried/32/29232_2.png) [@ffried](https://forums.swift.org/u/ffried)\
**Post date:** [August 12, 2022, 12:32pm UTC](https://forums.swift.org/t/sendable-in-foundation/59577/2 "2022-08-12T12:32:30Z")

</div>

I've just come across the same issue.

I don't think subclasses are a reason for classes not being sendable.  
For example the [docs state](https://developer.apple.com/documentation/foundation/nsnumberformatter), that as of iOS 7, `NumberFormatter` is thread-safe. So its sendable-conformance makes sense. Its mutable state is likely protected by locks.

`FileHandle` on the other hand is interesting, since [these very old docs](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html) list it as unsafe! However, it could be that this has changed since those docs were written.

`Operation` is likely not marked Sendable because it's not entirely thread safe. It has thread-safe methods and properties, but `Operation` is intended to be subclassed and could then have properties that are only accessible on the queue the operation is run on.

`URLResponse` could be marked Sendable, because its subclasses mostly live in Foundation AFAIK. So they're all known to be thread-safe.

`OperationQueue` on the other hand should be Sendable IMHO. Same goes for `UserDefaults`.

The latter two are what I find most confusing. In Xcode 13, we've modeled our application using the thread-safety docs. Thus we assumed `UserDefaults` to be `Sendable`, slapped a `@preconcurrency` on the `import Foundation` and called it a day. With Xcode 14 we suddenly get warnings here, that make no sense to me.

I've submitted FB11224364 covering `UserDefaults` and `OperationQueue`.

---

<div class="post-metadata">

**Author:** ![OneSadCookie](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/onesadcookie/32/3205_2.png) [@OneSadCookie](https://forums.swift.org/u/OneSadCookie)\
**Post date:** [August 14, 2022, 2:56am UTC](https://forums.swift.org/t/sendable-in-foundation/59577/3 "2022-08-14T02:56:46Z")

</div>

> [@ffried](#):
>
> I don't think subclasses are a reason for classes not being sendable

It's a problem when the subclass may not be Sendable, because instances of subclasses, statically typed as the parent, may be sent unsafely. That's why automatic/safe Sendable conformance is not available to non-`final` classes. @unchecked Sendable is obviously available to any type, though I feel that it probably shouldn't be available to non-`final` classes either.

---

<div class="post-metadata">

**Author:** ![OneSadCookie](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/onesadcookie/32/3205_2.png) [@OneSadCookie](https://forums.swift.org/u/OneSadCookie)\
**Post date:** [August 14, 2022, 3:01am UTC](https://forums.swift.org/t/sendable-in-foundation/59577/4 "2022-08-14T03:01:10Z")

</div>

I also find myself wondering about Swift's own `String`, which may be backed by an `NSString`. Immutable `CFString`s should be `Sendable`, but `NSString` is arbitrarily subclassable, and it's not clear to me from inspection of the code that Swift's implementation guarantees that `String` is only ever backed by an immutable `CFString` (it seems to use `NSCopying` to duplicate the string, which any subclass would be free to implement in any way).

I think you could argue that stepping into ObjC in any way removes any safety guarantees from Swift, but the fact remains that the primary way Swift is used these days is intermixed with ObjC, so it's not a completely theoretical concern.

---

<div class="post-metadata">

**Author:** ![OneSadCookie](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/onesadcookie/32/3205_2.png) [@OneSadCookie](https://forums.swift.org/u/OneSadCookie)\
**Post date:** [August 14, 2022, 3:06am UTC](https://forums.swift.org/t/sendable-in-foundation/59577/5 "2022-08-14T03:06:24Z")

</div>

> [@ffried](#):
>
> I've submitted FB11224364 covering `UserDefaults` and `OperationQueue`.

I'd filed FB11180190 "UserDefaults not Sendable" prior to making this thread.

---

<div class="post-metadata">

**Author:** ![ffried](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ffried/32/29232_2.png) [@ffried](https://forums.swift.org/u/ffried)\
**Post date:** [August 18, 2022, 12:20pm UTC](https://forums.swift.org/t/sendable-in-foundation/59577/6 "2022-08-18T12:20:43Z")

</div>

> [@OneSadCookie](#):
>
> It's a problem when the subclass may not be Sendable, because instances of subclasses, statically typed as the parent, may be sent unsafely.

Which is likely why e.g. `URLResponse` is marked `Sendable`, because you don't create new subclasses yourself and all the framework subclasses are safe.  
Whereas `Operation` isn't marked `Sendable` because here, most of the subclasses live outside of Foundation, thus it cannot be decided at the base class level that they should be `Sendable`.

---

<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:** [August 18, 2022, 7:57pm UTC](https://forums.swift.org/t/sendable-in-foundation/59577/7 "2022-08-18T19:57:45Z")

</div>

Except even the concrete subclasses of `Operation`, like `BlockOperation` aren't `Sendable` either, which doesn't make much sense. Those values are specifically sent across concurrency boundaries already, so surely they must be `Sendable`, no?

---

<div class="post-metadata">

**Author:** ![OneSadCookie](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/onesadcookie/32/3205_2.png) [@OneSadCookie](https://forums.swift.org/u/OneSadCookie)\
**Post date:** [August 18, 2022, 10:16pm UTC](https://forums.swift.org/t/sendable-in-foundation/59577/8 "2022-08-18T22:16:14Z")

</div>

> [@ffried](#):
>
> Which is likely why e.g. `URLResponse` is marked `Sendable`, because you don't create new subclasses yourself and all the framework subclasses are safe.

But you _are_ explicitly recommended to create `URLResponse` subclasses: [URLProtocol | Apple Developer Documentation](https://developer.apple.com/documentation/foundation/urlprotocol) (`URLProtocol`)

(And I don’t see anywhere in the docs any suggestion that `URLResponse` subclasses need be 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:** [August 18, 2022, 10:41pm UTC](https://forums.swift.org/t/sendable-in-foundation/59577/9 "2022-08-18T22:41:54Z")

</div>

Responses aren’t usually mutable, which is why they’d be thread safe. It would be nice if we could see the justification, one way or another, in the documentation.

---

<div class="post-metadata">

**Author:** ![eskimo](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/eskimo/32/13558_2.png) [@eskimo](https://forums.swift.org/u/eskimo)\
**Post date:** [August 19, 2022, 7:52am UTC](https://forums.swift.org/t/sendable-in-foundation/59577/10 "2022-08-19T07:52:02Z")

</div>

> But you are explicitly recommended to create `URLResponse` subclasses

That idea dates from a time when `URLSesssion` (well, at that time it was `NSURLConnection`) actively encouraged folks to create support for new protocols. That time has passed IMO. While creating a new protocol is still possible, the world has changed to make it much less useful:

- Historically, Foundation would load custom protocols from plug-ins that you could install on the system, so you can add a protocol that would then become available to all `NSURLConnection` clients. AFAIK that didn’t survive the CFNetwork rewrite.

- `URLProtocol` has not kept up with the evolution of the API. This is something I discussed in depth in the [CustomHTTPProtocol](https://developer.apple.com/library/ios/#samplecode/CustomHTTPProtocol/) sample code read me, and things have got worse since then.

- Many requests run out of process — `URLSession` background sessions, `WKWebView`, everything on watchOS — and custom protocols don’t work in that case.

Given this reality, I wouldn’t let that one line of documentation affect you thinking on this topic too much.

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

---

<div class="post-metadata">

**Author:** ![ffried](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ffried/32/29232_2.png) [@ffried](https://forums.swift.org/u/ffried)\
**Post date:** [August 26, 2022, 7:40am UTC](https://forums.swift.org/t/sendable-in-foundation/59577/11 "2022-08-26T07:40:44Z")

</div>

Not necessarily. The following code would generate an error if the closure passed to block-operation would be `@Sendable`:

```swift
var didRun = false
let blockOp = BlockOperation { didRun = true }
let queue = OperationQueue()
queue.addOperation(blockOp)

```

Here's the code with the error:

```swift
func makeBlockOp(with block: @Sendable @escaping () -> ()) -> BlockOperation {
    .init(block: block)
}

var didRun = false
let blockOp = makeBlockOp { didRun = true } // error: Mutation of captured var 'didRun' in concurrently-executing code
let queue = OperationQueue()
queue.addOperation(blockOp)

```

So here, not making `BlockOperation` conform to `Sendable` (which would in turn probably require its closure to be `@Sendable`) could likely also be due to backwards compatibility.

---

<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:** [August 26, 2022, 11:38pm UTC](https://forums.swift.org/t/sendable-in-foundation/59577/12 "2022-08-26T23:38:52Z")

</div>

I'm sorry but that doesn't make much sense to me. Marking your closure `@Sendable` simply activates the compiler warnings for using it with mutable values. Such usage is already unsafe without the markup, it's just the the compiler doesn't know it. So it seems like it should be `Sendable` but rely on the compiler's warning level not to produce new warnings on current code which is technically in violation. I really hope Apple isn't resisting marking types as `Sendable` because the Swift compiler's concurrency warnings are still too sensitive not to break code.

---

<div class="post-metadata">

**Author:** ![ffried](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ffried/32/29232_2.png) [@ffried](https://forums.swift.org/u/ffried)\
**Post date:** [August 29, 2022, 6:02am UTC](https://forums.swift.org/t/sendable-in-foundation/59577/13 "2022-08-29T06:02:06Z")

</div>

The issue here IMHO is that using an `@Sendable` closure will not generate a warning but an error! Thus breaking existing code. Whether that should be a warning or not is probably a topic for another discussion, but in this case it was probably easier to _not_ mark it as `@Sendable` to prevent breakage.

Also, my example above _can_ be completely safe if the `didRun` variable is only read and mutated from within the block operation, which in again runs on a single queue.

Don't get me wrong, I totally agree with the reasoning that `Operation`s match the idea expressed by `Sendable`! I just think, that they come from a world _without_ `Sendable` and are thus made safe in other ways, e.g. by using rules that cannot be expressed by `Sendable` today. As in above's example - which is safe using the rule that no one is allowed to read or even write `didRun` outside of the block operation's closure.

---

<div class="post-metadata">

**Author:** ![BasemEmara](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/basememara/32/21528_2.png) [@BasemEmara](https://forums.swift.org/u/BasemEmara)\
**Post date:** [September 8, 2022, 11:43am UTC](https://forums.swift.org/t/sendable-in-foundation/59577/14 "2022-09-08T11:43:49Z")

</div>

If `Sendable` doesn't mean thread-safe, then I don't know what sendable means because I thought it was much more than immutable.

Ackhtually [according to the docs](https://developer.apple.com/documentation/swift/sendable), one of the categories to be automatically considered `Sendable` is `Reference types that internally manage access to their state`.

Since `UserDefault` is a [reference type that is thread-safe](https://developer.apple.com/documentation/foundation/userdefaults), it should be considered `Sendable` meaning this Swift compiler warning is contradictory to the `Sendable` docs.

---

<div class="post-metadata">

**Author:** ![nh7a](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nh7a/32/1141_2.png) [@nh7a](https://forums.swift.org/u/nh7a)\
**Post date:** [March 14, 2024, 4:59pm UTC](https://forums.swift.org/t/sendable-in-foundation/59577/15 "2024-03-14T16:59:29Z")

</div>

So, what's the correct way to do this?

```swift
final class Preferences: Sendable {
    let userDefaults: UserDefaults = .standard // ⚠️
}

```

---

<div class="post-metadata">

**Author:** ![KeithBauerANZ](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/keithbaueranz/32/27897_2.png) [@KeithBauerANZ](https://forums.swift.org/u/KeithBauerANZ)\
**Post date:** [March 14, 2024, 8:59pm UTC](https://forums.swift.org/t/sendable-in-foundation/59577/16 "2024-03-14T20:59:37Z")

</div>

`UserDefaults` isn't `Sendable` because it's `open`, but `UserDefaults.standard` isn't isolated yet either, so you can do:

```swift
final class Preferences: Sendable {
    var userDefaults: UserDefaults { .standard }
}

```

(You should presume that `.standard` will return a new instance on each call, because that's the only way for Apple to implement this safely. However, I don't believe that's actually true. Still, seems like a problem for Apple to solve)

---

<div class="post-metadata">

**Author:** ![vns](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vns/32/37396_2.png) [@vns](https://forums.swift.org/u/vns)\
**Post date:** [March 14, 2024, 9:32pm UTC](https://forums.swift.org/t/sendable-in-foundation/59577/17 "2024-03-14T21:32:01Z")

</div>

I find that misleading. `open` has little to do with it not being `Sendable`. According to documentation, its implementation is thread-safe, so it actually can be marked with `Sendable`. And this could be done via extension:

```swift
extension UserDefaults: @unchecked Sendable {
}

```

That solely is enough to resolve warnings, such as global variable.

Also, presuming that `.standard` will return new instance also not correct due to it being thread-safe (so shared instance could be kept safely as global variable) and [documentation](https://developer.apple.com/documentation/foundation/userdefaults/1416603-standard) which implies it is created once.

Not sure why it isn't marked Sendable (it's actually does, but conformance marked with unavailability attribute) for so long...

---

<div class="post-metadata">

**Author:** ![KeithBauerANZ](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/keithbaueranz/32/27897_2.png) [@KeithBauerANZ](https://forums.swift.org/u/KeithBauerANZ)\
**Post date:** [March 14, 2024, 9:42pm UTC](https://forums.swift.org/t/sendable-in-foundation/59577/18 "2024-03-14T21:42:13Z")

</div>

> [@vns](#):
>
> `open` has little to do with it not being `Sendable`

Whilst I can't speak to Apple's motivations here (see the first post for confusion), in general, `open` has _everything_ to do with a class not being able to be `Sendable`.

Imagine you have this code:

```swift
final class A: Sendable {
    private let _x = OSAllocatedUnfairLock<Int>(initialState: 0)
    init() {}
    func incrementAndPrintX() -> Int {
        let x = _x.withLock { $0 += 1; return $0 }
        print(x)
        return x
    }
}

func doLotsOfParallelIncrements(_ a: A) {
    withDiscardingTaskGroup { group in
        for _ in 0..<1000 {
            group.addTask { a.incrementAndPrintX() }
        }
    }
}

```

`doLotsOfParallelIncrements` sends an `A`, but that's OK because `A` is Sendable.

All good so far. Now we remove `final`, add a subclass and use it:

```swift
// change the declaration above to:
/*nonfinal*/ class A: @unchecked Sendable { /* same as before */ }

class B: A {
    private var xAsString = "0"
    override func incrementAndPrintX() -> Int {
        let x = super.incrementAndPrintX()
        xAsString = "\(x)"
        return x
    }
}

doLotsOfParallelIncrements(B())

```

B isn't `Sendable` (nor can it safely be made sendable without introducing a lock), but it can still be _sent_, when typed as its superclass. And this code will crash (due to concurrent modification of `xAsString`)

---

<div class="post-metadata">

**Author:** ![vns](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vns/32/37396_2.png) [@vns](https://forums.swift.org/u/vns)\
**Post date:** [March 14, 2024, 10:25pm UTC](https://forums.swift.org/t/sendable-in-foundation/59577/19 "2024-03-14T22:25:35Z")

</div>

> [@KeithBauerANZ](#):
>
> Whilst I can't speak to Apple's motivations here (see the first post for confusion), in general, `open` has _everything_ to do with a class not being able to be `Sendable`.

In that case with `UserDefaults` it has little impact on conformance. It is a thread-safe by design, more likely you _won't_ be subclassing it, and even if you will, compiler will warn you by asking to re-instate `@unchecked Sendable` on it. And since a warning could be more misleading, that something better to do.

---

<div class="post-metadata">

**Author:** ![KeithBauerANZ](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/keithbaueranz/32/27897_2.png) [@KeithBauerANZ](https://forums.swift.org/u/KeithBauerANZ)\
**Post date:** [March 14, 2024, 10:35pm UTC](https://forums.swift.org/t/sendable-in-foundation/59577/20 "2024-03-14T22:35:58Z")

</div>

It's not about what you will "probably" do, it's about what you _could_ do that would lead to data races. And since UserDefaults is `open`, you _could_ subclass it and override methods, and that _could_ lead to data races. (Though, as the first post points out, Apple is inconsistent here, and `URLResponse` gets the opposite treatment).

There's no warning for creating a non-`Sendable` subclass of a `Sendable` class, though. Theoretically, there's no non-`final` `Sendable` classes, which is probably why that warning doesn't exist. But given `@unchecked Sendable` can be applied to non-final classes, maybe there should be.

[Next page](https://forums.swift.org/t/sendable-in-foundation/59577.md?page=2)
