-
Notifications
You must be signed in to change notification settings - Fork 160
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
explicity operate on underlying source and sink instead of public methods #321
Comments
In IRC @domenic also suggested that we could add a WritableStream cast function if duck-typed WritableStreams are found to be needed. |
We planned to introduce a generic pipeTo function that interacts with public reader / writer APIs and specific ones implemented natively. What's wrong with the idea? |
I mean, the existing (planned) pipeTo can handle arbitrary streams correctly and can handle specific ones (that possibly includes ReadableStream and WritableStream) efficiently. Your proposal seems to drop the former property and I don't see what we get instead. |
So, the current reference implementation is generic on both I think the genericness on The genericness on One argument against genericness on I then had an epiphany, which @wanderview alludes to above. All along I have been trying to make the analogy that promise is to promise executor function as readable/writable stream is to underlying source/sink. What I was missing was to further extend this analogy to the way in which promises handle genericness. Which is, they always "cast" incoming duck-promises (called thenables) into real promises, using PromiseResolve (exposed as If we want genericness over writable streams, we should do the same thing. As a bonus we would get a guarantee that the writable stream obeys the correct invariants (currently there is the possibility of bizarre failures that we would in theory want to detect and add errors for, like And with this in mind, there's no reason to define So, I have kind of changed my opinion on all this a lot. |
What do you mean by "specific ones implemented natively"? I think we want to be able to do this piping off-main-thread:
But if pipeTo() operates on public methods, then this cannot occur with:
Code working with streams should not have to do an "if native, call different functions" switch. Trying to detect a function override complicates optimizations and also comes at a perf cost due to constant checking on every call. |
Oh. I forgot an important caveat. It's not yet clear whether the (Readable|Writable)ByteStream versions will be a subclass or a separate duck-compatible class. Subclass means they could pass the brand check; duck-compatible means we'd either have to make them aware of each other (e.g. pipeTo doing a brand check for either WritableByteStream or WritableStream and allowing both), or we'd have to do structural matching, or we'd have to cast WritableByteStreams to WritableStreams :-/. So, that's a bit tricky. |
Unless we expect a proliferation of stream types, this does not seem a terrible problem. I think you would want ReadableByteStreams to understand WritableStream+WritableByteStream, but ReadableStream might only understand WritableStream underlying sink. It seems this can be done by just looking for the right sink duck types, no? |
I think it would suck if you couldn't pipe a ReadableStream to a WritableByteStream. |
You absolutely could, but it would use whatever path WritableStream.write() method uses on that object. (The underlying sinks are un-specc'd, but it seems there must be a way to do a simple write.) |
I guess I would recommend creating "Write to sink" algorithms that are associated with the stream. Then ReadableStream.pipeTo() could say "using destination streams Write to sink algorithm...". A ReadableByteStream.pipeTo(), however, might say "using destinations Optimized Byte Write To Sink algorithm, if available, or falling back to Write To Sink algorithm, ..." |
OK, but then we need some way for ReadableStream.prototype.pipeTo to recognize that if
|
Right... it needs to check the type which I guess you called a brand check. I'm used to getting this for free through the use of webidl.
|
Sure, but that's pretty crappy and non-extensible layering, making ReadableStream explicitly aware of WritableByteStream. That's my "Hard code knowledge of BTW we're not going to exactly interface with the underlying sink because that means you could do writes out of order. More like, we're going to use abstract operations that take WritableStreams or ReadableStreams as parameters, and use those. Effectively it goes directly to the underlying sink, but also with all the guarantees you would get through a (non-monkey-patched) use of the public API. See e.g. EnqueueInReadableStream for an example. I anticipate having a WriteToWritableStream with similar properties. |
That sounds like |
Ok. I guess I don't really care how its spec'd as long as it lets the implementation operate on the underlying sink without going through a potentially-monkey-patched public interface. |
Oh hey, this is finished now that pipeTo is specced to not operate publicly. |
Certain optimizations like piping off-main-thread are much more difficult in a world where the public methods of a ReadableStream and WritableStream can be monkey patched with js. To enable UAs to implement these optimizations the spec should be written such that it operates directly on the underlying sources and sinks.
For example, ReadableStream.pipeTo(ws) should not call ws.write(), but should write data to ws's underlying sink.
This makes the API a bit more "DOMy" and a bit less "JSy", but makes it much easier to create efficient implementations in multi-threaded browsers.
The text was updated successfully, but these errors were encountered: