Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stdlib]: better align Async{Throwing}Stream implementations #76571

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jamieQ
Copy link
Contributor

@jamieQ jamieQ commented Sep 19, 2024

Removes some of the discrepancies between the throwing & non-throwing variants of AsyncStream. In particular, adds multi-consumer support to the throwing variant, and updates the docs. Additional minor refactoring of existing implementation to streamline the code.

Fixes #76547

Removes some of the discrepancies between the throwing & non-throwing
variants of AsyncStream. In particular, adds multi-consumer support to
the throwing variant, and updates the docs. Additional minor refactoring
of existing implementation to streamline the code.

Fixes swiftlang#76547
Copy link
Contributor Author

@jamieQ jamieQ left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FranzBusch @ktoso i'd again appreciate your insights on the proposed changes here, if & when you have some time. thanks in advance!

@@ -356,11 +356,6 @@ public struct AsyncStream<Element> {
@available(SwiftStdlib 5.1, *)
extension AsyncStream: AsyncSequence {
/// The asynchronous iterator for iterating an asynchronous stream.
///
/// This type doesn't conform to `Sendable`. Don't use it from multiple
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the 'this type isn't Sendable' assertion is still accurate, but i'm not sure it's particularly relevant or helpful to call out. the other warnings and references to fatalError() are no longer correct.

Comment on lines +129 to +134
// Presence of continuations implies no pending elements.
// TODO: which assertion flavor should be used?
assert(
state.pending.isEmpty,
"Continuations should imply no pending elements."
)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would appreciate feedback on a reasonable way to enforce this invariant. per the docs regarding assertion flavors in the stdlib, i would be inclined to think that _internalInvariant() is maybe the most appropriate function to use here. however, that symbol isn't visible in this context since this code resides in the Concurrency module. any thoughts on this, or references to prior art would be appreciated!

unlock()
continuation.resume(returning: toSend)
} else if state.terminal {
if state.terminal {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

per @FranzBusch's prior observation, the branches in which we were handling cases that implied both pending elements and outstanding continuations should in fact be dead. the rationale is that elements should only be buffered if there are no awaiting consumers, and continuations are stored only if there are no pending elements. sanity checks appreciated regarding this analysis, however.

@@ -287,7 +267,7 @@ extension AsyncThrowingStream {
}

struct State {
var continuation: UnsafeContinuation<Element?, Error>?
var continuations = [UnsafeContinuation<Element?, Error>]()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

primary behavioral changes to make AsyncThrowingStream better match AsyncStream's existing behavior start here.

@@ -437,41 +437,257 @@ class NotSendable {}

// MARK: - Multiple consumers

tests.test("FIFO delivery order with multiple consumers") {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not sure this delivery order is ever publicly stated as a guarantee of these types, but it is how they currently work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

AsyncStream & AsyncThrowingStream behavioral divergences & misleading documentation
1 participant