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!