The issue is related to a sequence type (for example Array
, or a variadic parameter T...
) whose elements will be passed in as sending
, but the sequence itself is not recognised as sending
.
The code below demonstrates the issue in a more clear way:
struct Foo<Event> {
func send(_ event: sending Event) {
// this is fine
}
func send(events: sending [Event]) {
for event in events {
send(event) // ERROR: Sending 'event' risks causing data races
}
}
}
The detailed error provided by the complier:
- 'event' is used after being passed as a 'sending' parameter; Later uses could race.
- Access can happen concurrently
Technically, iterating over a sequence involves copying the elements.
If I understand sending
correctly, this violates the sending requirement and the compiler (must) fail to compile this.
Intuitively, I would have written:
...
func send(events: [sending Event]) {
for event in events {
send(event)
}
}
where sending
for the parameter events
will be inferred.
However, [sending T]
does not compile.
It seems, this is a rather common use case. Is there a solution (other than constraining Event
to Sendable
) ?
A complete scenario:
Summary
import Testing
struct Foo<Event> {
typealias Stream = AsyncStream<Event>
let stream: Stream
let continuation: Stream.Continuation
init() {
(stream, continuation) = Stream.makeStream()
}
func send(_ event: sending Event) {
continuation.yield(event)
}
func send(events: sending [Event]) {
for event in events {
send(event) // Error: Sending 'event' risks causing data races
}
}
}
struct Test {
class NonSendable {}
@Test
func testA() async throws {
let nonSendable = NonSendable()
let foo = Foo<NonSendable>()
foo.send(nonSendable)
}
@Test
func testB() async throws {
let nonSendables = [NonSendable(), NonSendable()]
let foo = Foo<NonSendable>()
foo.send(events: nonSendables)
}
}