How to directly use an async iterator in an actor isolated function?

3 weeks ago 23
ARTICLE AD BOX

I happened to need to consume only one element of an async sequence, so rather than a `for await` loop, I thought I'd call makeAsyncIterator and then call next to make it very clear that I'm not looping at all.

@MainActor // this method needs to be main actor isolated func f(seq: some AsyncSequence<Int, any Error>) async throws { var iter = seq.makeAsyncIterator() print(try await iter.next()) }

This produces an error,

Sending 'iter' risks causing data races

I understand what it is saying - next is a nonisolated function, so I am effectively sending the main actor isolated iter to not-the-main-actor. Since the async iterator is not sendable, this is an error.

But if I use a for await loop, the code compiles!

@MainActor func f(seq: some AsyncSequence<Int, any Error>) async throws { for try await x in seq { print(x) break } }

The for await loop should just be syntactic sugar for a while loop that calls iter.next() repeatedly, so what does for await do differently?


Side note, I also tried

print(try await seq.first(where: { _ in true }))

which also doesn't compile - first(where:) is nonisolated, so I am sending the non-sendable seq.

Read Entire Article