Hi there, I’m trying out share() (from AsyncAlgorithms) in my app and want to pipe the resulting sequence through ServiceLifecycle’s cancelOnGracefulShutdown() before consuming it. As soon as the shared sequence is stored behind an existential, I hit a compile-time error:
struct SharedSequenceHolder {
private let shared: any Sendable & AsyncSequence<Int, Never>
init() {
let base = [1, 2, 3].async
self.shared = base.share()
}
func consume() async {
// error here:
// Member 'cancelOnGracefulShutdown' cannot be used on value of type
// 'any Sendable & AsyncSequence<Int, Never>'; consider using a generic constraint instead
for await value in shared.cancelOnGracefulShutdown() {
_ = value
}
}
}
Relevant APIs:
// ServiceLifecycle
extension AsyncSequence where Self: Sendable, Element: Sendable {
public func cancelOnGracefulShutdown() -> AsyncCancelOnGracefulShutdownSequence<Self> { ... }
}
// AsyncAlgorithms
extension AsyncSequence {
public func share(
bufferingPolicy: AsyncBufferSequencePolicy = .bounded(1)
) -> some AsyncSequence<Element, Failure> & Sendable
}
As far as I can tell, this fails because cancelOnGracefulShutdown() is constrained on Self and returns a type that mentions Self. That makes it unavailable on an existential like
any Sendable & AsyncSequence<Int, Never>.
I tried the usual “open existential via a generic parameter” trick:
struct SharedSequenceHolder {
private let shared: any Sendable & AsyncSequence<Int, Never>
init() {
let base = [1, 2, 3].async
self.shared = base.share()
}
func consume() async {
await _consume(shared)
}
private func _consume<S: AsyncSequence & Sendable>(_ seq: S) async
where S.Element == Int {
for await value in seq.cancelOnGracefulShutdown() {
_ = value
}
}
}
But this does not build and produces a “Call can throw, but the error is not handled” diagnostic (which seems a compiler bug).
Is there a recommended pattern for storing the result of share() (opaque return) while still keeping methods that mention Self available without having to immediately “open” via a generic?
Should ServiceLifecycle also offer an overload that works on
any AsyncSequence & Sendable where Element: Sendable?
Thanks a lot in advance!