SE-0388: Convenience Async[Throwing]Stream.makeStream methods

+1, this is much needed and the shape looks good.

I was initially advertising for the new type, mostly because returning tuples like that is pretty yucky IMHO but it seems people are not too bothered by it. I would not mind the tuple version making a comeback.

1 Like

FWIW I had been following this closely but realised the other day that most or all of what I’m currently using AsyncStream for would probably be obviated by the new Observable concept, if/when that happens. In the context of an ObservableObject and its @Published properties, I often want a few more properties that I can easily listen to but that don’t trigger objectWillChange, and ideally I like the interface to use Swift concurrency rather than Combine.

So, having had strong opinions about this API because I thought it would end up everywhere in my code, it looks likely that I’ll only be using it in certain cases the Observable implementation doesn’t cover, and I’m far less bothered about its exact shape.

My Use Case
class Speech: ObservableObject {

    @Published var transcript = Transcript()

    //

    public var sessions: AsyncStream<Session> { sessionStream }
    
    private let sessionStream: AsyncStream<Session>
    private let sessionContinuation: AsyncStream<Session>.Continuation

    //
    
    public init() {
        (sessionStream, sessionContinuation) = AsyncStream.create()
    }
    
    // ...
    
}

Thanks for the great feedback from everyone already. I am myself also not super tied to the new type approach so let's evaluate the feedback in the end.

I would prefer a tuple, just because it allows destructuring.

2 Likes

I'd like to amend my +1 to say I also think a tuple (with or without a typealias) would be preferred over an entire new type. If we do use a typealias, I still would vote in favor of a name other than NewStream.

How about ´Subject´ or ´Pipe´ instead of ´NewStream´

i don't think pipe would be the right analogy because you can have lots of copies of the continuation that all yield to the same stream output.

+1 For sure. I've definitely run into cases where I needed this and escaping the continuation out of the callback always felt wrong.

I would vote for returning a tuple though, especially if that means this can be back deployed.

+1 for this as solving a usability problem with the current API and +1 to some sort of backward deployment.

+1 with a preference for the tuple.

Great, I think async sequence now is too low level and confuse. We need more simple things for common use cases.

I can’t judge what is best in this case but I definitely agree that the possibility of back deployment should NOT factor in the decision. Swift will be with us for a long time.

I prefer the tuple approach over an entirely new type. Type-aliasing it is fine, I think, but the “NewStream” name is a bit awkward since it’s not itself a stream. Something like “StreamCreation” may be clunky, but it properly conveys that the “thing” in question is an auxiliary, not a stream in its own right. Does anyone else have naming ideas?

Using a tuple seems more consistent with what we've previously done elsewhere in the standard library. If there's a docs tooling issue with documenting the different elements of a result tuple, that seems like something we should look into improving rather than having it affect library design. CC'ing @swift-documentation-workgroup

15 Likes

I’m not much of a fan of tuples, but this seems like an obviously a proper use of them – a bundling of two values with no natural name and no pair-specific API. If we don’t use tuples in a case like this, what are they even there for?

5 Likes

I also think tuples are the best fit for this purpose and the best motivation for it the use of return value destructuring at the call site.

what is the motivation for documenting the tuple elements separately, instead of documenting the method itself?

I don't mean separately from the method — in fact, that's one of the main problem with the struct return here, that it moves what's logically the documentation of a single function's return value to a different place. What I mean is that someone documenting the return value of a method that returns a tuple ought to feel like they have an acceptable way to talk about the different elements of the tuple. They can, of course, always just write stuff like "The first element of this tuple is the newly-created widget, which...", and maybe that's good enough and there's nothing else we need to do. But if there's an identifiable problem with that which is leading people to instead suggest returning a struct, I think we need to fix it so that people can continue to use tuples when otherwise appropriate.

6 Likes

what would be the alternative to doing as you suggest and just writing "the Nth element of this tuple"? i'm not sure how helpful symbollinking something like ``0`` would even be.

I'm not sure; I didn't raise the original documentation concern. I'm asking the docs workgroup to engage and figure out what the right thing to do here is, even if that's nothing.

I expect the tuple in this case would be labeled, though.