Hello, I am a co-author of shiz’s proposal.
I believe it is important to distinguish between whether a type is thread-safe and whether the handling of a type guarantees thread safety.
The concept of whether a type is thread-safe has existed since before the introduction of Swift Concurrency. People have implemented thread-safe types by making member access of classes mutually exclusive using NSLock or DispatchQueue.
Thread safety here means that the type can be accessed simultaneously from multiple threads. This concept is general and not dependent on Swift, as described on Wikipedia:
On the other hand, guaranteeing that the handling of a type is thread-safe is only realized with Swift 6’s Strict Concurrency mode.
However, when a type is Sendable, it means it can be safely sent between concurrent contexts. This property remains the same in both Swift 5 and Swift 6.
For example, consider the following code:
import Foundation
func main() async throws {
var x: [Int] = [1, 2, 3]
DispatchQueue.global().async {
x[0] = 42
print(x)
}
DispatchQueue.global().async {
x[0] = 99
print(x)
}
try await Task.sleep(for: .seconds(1))
}
try await main()
This code reads and writes x concurrently. In Swift 5, the following warning appears but it can still compile:
Mutation of captured var ‘x’ in concurrently-executing code; this is an error in Swift 6
And, of course, there is a risk of data races, precisely because Array<Int> is not thread-safe. However, in Swift 5, Array<Int> is undoubtedly Sendable.
This example confirms that conforming to Sendable and being thread-safe are separate facts.
In the section we propose to change, it is written as follows:
A type that conforms to the Sendable protocol is a thread-safe type: values of that type can be shared with and used safely from multiple concurrent contexts at once without causing data races.
It says “can be shared with and used safely from multiple concurrent contexts,” which may not be accurate. As demonstrated in the above example, sharing would cause data races.
One way to achieve Sendable is by making the type thread-safe and shareable. However, another way is to make the type non-thread-safe but copyable so it can be sent to another context.