AsyncZip2Sequence
‘s AsyncIterator
cannot be implemented with value semantics using async let
, Task, or TaskGroup due to mutation of captured parameter self in concurrently-executing code
. What am I missing? Wouldn’t it be safe to have them mutating at the same time assuming exclusive access to each (other than false sharing issues)? How is stdlib going to implement it?
Furthermore in the class-based implementation async let
errors out with call can throw, but it is executed in a non-throwing autoclosure
and call is to 'rethrows' function, but a conformance has a throwing witness
. Try and change the tasks to async let
s.
Here’s the working one.
public struct AsyncZip2Sequence<Sequence1, Sequence2>: AsyncSequence
where Sequence1: AsyncSequence, Sequence2: AsyncSequence
{
public typealias Element = (Sequence1.Element, Sequence2.Element)
let sequence1: Sequence1
let sequence2: Sequence2
public class AsyncIterator: AsyncIteratorProtocol {
var iterator1: Sequence1.AsyncIterator
var iterator2: Sequence2.AsyncIterator
init(_ _iterator1: Sequence1.AsyncIterator, _ _iterator2: Sequence2.AsyncIterator) {
(iterator1, iterator2) = (_iterator1, _iterator2)
}
public func next() async throws -> Element? {
let task1 = Task { try await iterator1.next() }
let task2 = Task { try await iterator2.next() }
if let value1 = try await task1.value,
let value2 = try await task2.value {
return (value1, value2)
} else {
return nil
}
}
}
public func makeAsyncIterator() -> AsyncIterator {
AsyncIterator(sequence1.makeAsyncIterator(),
sequence2.makeAsyncIterator())
}
}