AnyAsyncSequence

If you read swift-evolution/0358-primary-associated-types-in-stdlib.md at main · apple/swift-evolution · GitHub you will find out why it is not yet available.

2 Likes

Has there been any updates on this? This is something sorely needed. Especially if you use something the AsyncAlgorithms package.

For example, something simple like this already becomes super unweildly:

private var testSequence: AsyncMapSequence<AsyncCombineLatest2Sequence<AsyncStream<String>, AsyncStream<Bool>>, String> {
    let stream1 = AsyncStream {
        return "Test"
    }

    let stream2 = AsyncStream {
        return true
    }

    return AsyncCombineLatest2Sequence(stream1, stream2)
        .map { (string, bool) -> String in
            if bool {
                return "\(string) is true"
            } else {
                return "\(string) is false"
            }
        }
}

you could do something like this, but then you lose access to type information without casting:

private var testSequence: some AsyncSequence {
    let stream1 = AsyncStream {
        return "Test"
    }

    let stream2 = AsyncStream {
        return true
    }

    return AsyncCombineLatest2Sequence(stream1, stream2)
        .map { (string, bool) -> String in
            if bool {
                return "\(string) is true"
            } else {
                return "\(string) is false"
            }
        }
}

private func test() async throws {
    for try await value in testSequence {
        // value is (some AsyncSequence).Element
    }
}
4 Likes

I agree, for now it is very annoying to use AsyncSeqence crossing api boundaries. As a workaround, I always use AsyncStream (feeding it the values from another AsyncSequence) as a return type. I really hope we will get primary associated types for AsyncSequence soon.

4 Likes

Do we know whyAsyncSequence doesn't have a primary associated type? Is it hard to implement for that particular type or are there other concerns?

The problem is about error handling. @hborla summarized it well in the SE-0346 review thread:

See also the Pitch thread of SE-0358:

1 Like

Primary associated types have been helpful, but they're still a band-aid, and they don't even yet cover all synchronous cases that should be expressible with multiple somes. E.g.

import typealias Algorithms.StridingSequence

public extension Sequence {
  /// Distribute the elements as uniformly as possible, as if dealing one-by-one into shares.
  /// - Note: Later shares will be one smaller if the element count is not a multiple of `shareCount`.
  @inlinable func distributedUniformly(shareCount: Int)
  -> LazyMapSequence<Range<Int>, StridingSequence<DropFirstSequence<Self>>> {
    (0..<shareCount).lazy.map {
      dropFirst($0).striding(by: shareCount)
    }
  }
}

Array((1...10).distributedUniformly(shareCount: 3)).map(Array.init))
[[1, 4, 7, 10], [2, 5, 8], [3, 6, 9]]

We need full constraints for opaque return types.