Marking a class or function as Sendable
ensures it is safe to pass across concurrent boundaries, value types are safe as they implement copy on write, etc. we all find in Swift language documentation. But my point is being Sendable
does not promise that a variable is free of data races. We can have data races even in basic value types such as Int
as demonstrated in code below. So Sendable
does not equate to being data safe from concurrent access/modification, it only means the value is safe to copy across different threads. But my question is what problem does it solve or what is the importance of having Sendable
as a construct then? Can someone please explain it?
var num = 0
DispatchQueue.global(qos: .background).async {
for _ in 0..<100 {
num += 1
}
}
DispatchQueue.global(qos: .background).async {
for _ in 0..<100 {
num -= 1
}
}
2
Answers
As you said,
Sendable
allows the compiler to reason about whether a value is safe to send across concurrency domains. This is very useful, because you often write code that sends things across concurrency domains. The compiler can check whether your code is safe or not. WithoutSendable
, the compiler will either need to disallow any sending (overly restrictive), or allow all sendings (not safe).From SE-0302:
A very simple example to demonstrate how useful
Sendable
is, is:Is this safe? That depends on whether values of
SomeType
are safe to send to the top levelTask
. If it is not safe to send, you might end up with the value ofSomeType
being shared between theTask
and wherever it originally came from. For example, ifSomeType
is a class with mutable properties, this can cause a race:If
SomeType
isSendable
, then the compiler can allow the first code snippet to compile.Here is another example from SE-0302:
doThing
is isolated to the actor, and the actor could store thestring
passed todoThing
in one of its properties. And then you end up with aNSMutableString
being shared between the actor and whoever originally owns it.If we use
String
instead ofNSMutableString
, this code is safe becauseString
isSendable
.String
is copy-on-write, so the actor modifying it will not affect the whoever owns it originally.Purpose of Sendable
When to Use Sendable
tasks or share across threads.
Example: Custom Type Conforming to Sendable
Example: Using Sendable with a Class
For a class to conform to Sendable, all its stored properties must be immutable or themselves conform to Sendable. Also, the class must be marked as final.
If a property is mutable, the compiler will emit an error unless you take explicit measures, like synchronizing access or ensuring exclusivity.