02:02 | <zewt> | oh jesus |
02:02 | <zewt> | now nvidia's page is doing clipboard hijacking |
02:02 | <zewt> | browsers just need to drop copy events and mask copies from pages, it's too abused |
06:09 | <annevk> | wanderview: reopened that bug |
06:10 | <annevk> | wanderview: "st" goes to the spec here, Hixie's idea of subdomains for everything works kind of awesome in that respect |
06:47 | <zcorpan> | flash update is downloaded from fpdownload.macromedia.com ... :-) |
07:26 | <annevk> | zewt: not providing pages those tools will have them insist on keeping Flash around :-( |
09:53 | <annevk> | wanderview: put the revised version up on https://wiki.whatwg.org/wiki/Storage and included some examples of how it can be used with IDB and Cache |
11:09 | <annevk> | Clearly I still fail at GitHub. I downloaded xml5_draft with the GitHub client and created a branch I intended to use for a pull request (also available as option in the client these days), but now it claims I have no permission... I'm guessing that means I didn't actually have permission to create the branch, but the pull request should work I think... At least, the repository seems to allow them. |
11:10 | <jgraham> | If you don't have permission to access the upstream you have to create a branch in your fork and make the PR from that |
11:13 | <annevk> | But would the PR button then create a PR on my fork or the original one? |
11:13 | <annevk> | The UI could do all that for me though if it knows I don't have permission... But I guess we're not quite there yet. |
11:14 | <jgraham> | Against the original one |
11:15 | <zcorpan> | trying to spec a DOMMatrixInit where you can use either .a or .m11 but throw if they are both present with different values, becomes a bit messy. maybe i should only support .m11 for the dictionary? |
11:16 | <zcorpan> | https://gist.github.com/anonymous/a8931b3ebac8a418ca23 |
11:17 | <zcorpan> | to fix https://lists.w3.org/Archives/Public/public-fx/2015JanMar/0119.html |
11:21 | <annevk> | zcorpan: that email talks about exposing a-f and m11-m44, but more interesting is what internal slots it has I think |
11:22 | <annevk> | zcorpan: but I guess you might still want to initialize from a-f since it's more convenient |
11:22 | <zcorpan> | annevk: internal slots is m11-m44 |
11:22 | <zcorpan> | annevk: yeah, that my thinking too |
11:23 | <zcorpan> | just needs more work for the impl |
11:23 | <annevk> | zcorpan: https://dom.spec.whatwg.org/#dom-mutationobserver-observe does a bunch of defaulting and throwing as well... |
11:24 | <annevk> | zcorpan: initialization of an object is not where impl cost is though |
11:24 | <annevk> | zcorpan: it's somewhat meticulous work, but not exactly hard |
11:24 | <zcorpan> | annevk: thx |
13:15 | <zewt> | annevk: and i flashblock by default ... not sure i buy the logic that we should give sites the tools to be obnoxious so they use our thing to be obnoxious instead of flash, heh |
13:17 | <annevk> | zewt: a lot of the sites that use it do it because users actually want that functionality as I understand it |
13:17 | <annevk> | zewt: I agree that UAs should offer the ability to block clipboard access |
13:18 | <zewt> | if I select text and copy it, it should copy what i told it to and not add freaking ads to the end |
13:19 | <zewt> | even browser vendors don't always seem to understand that (address bar copying in firefox is a nightmare) |
13:19 | <annevk> | No disagreement there. I'm thinking about YouTube click-to-copy a link, and similar features elsewhere |
13:20 | <zewt> | the main annoying case is that pages can intercept when I copy selected text |
13:22 | <zewt> | (which I know is hard to completely prevent, but it's been made easier rather than harder lately iirc) |
13:22 | <annevk> | I think Firefox offers options to disable that kind of prevention entirely |
13:24 | <zewt> | i see dom.event.clipboardevents.enabled, but that seems like too big of a hammer |
13:42 | <annevk> | SimonSapin: what does https://github.com/servo/rust-url/blob/master/src/format.rs#L65 mean? |
13:43 | <SimonSapin> | annevk: it’s https://url.spec.whatwg.org/#url-serializing with the "exclude fragment flag" |
13:44 | <annevk> | SimonSapin: ah okay |
13:44 | <annevk> | SimonSapin: I thought it was talking about URLs which can't have a fragment |
13:44 | <annevk> | (which don't exist) |
13:44 | <SimonSapin> | ok |
13:47 | <annevk> | SimonSapin: if a Rust function lacks an explicit return, is the last line returned? |
13:47 | <annevk> | SimonSapin: well, last expression looks like |
13:47 | <SimonSapin> | the last expression, if it doesn’t end with ; |
13:47 | <SimonSapin> | `if` and `match` are expressions |
13:48 | <annevk> | Because if it ends with ; I guess the last expression is empty? |
13:48 | <SimonSapin> | right |
13:49 | <SimonSapin> | ; can be viewed as a separator rather than a terminator |
13:49 | <annevk> | I'm trying to figure out how to best approach this parser rewrite in a way that also allows me to tackle the issue of handling URLs such as test://relative/something better... |
13:49 | <SimonSapin> | and the empty expression has type (), the empty tuple aka unit type |
13:49 | <annevk> | But perhaps rewriting it as functional first and then tackling that would be better |
13:50 | <SimonSapin> | annevk: that sounds mostly orthogonal |
13:50 | <SimonSapin> | as in, test://relative/something involves figuring out the data model, independently of the algorithm style |
13:50 | <annevk> | SimonSapin: maybe, would be nice to have all the facts upfront :-) |
13:51 | <SimonSapin> | changing fewer things at a time may also be easier both to do and to review |
13:53 | <annevk> | Yeah, that's certainly true |
13:59 | <annevk> | SimonSapin: such an interop drama that data model |
13:59 | <annevk> | SimonSapin: Chrome does resolve x against test://test/test "correctly", but reports a pathname of "//test/x" |
14:00 | <annevk> | Safari splits it out in host and path |
15:45 | <wanderview> | annevk: should we maintain the "simple v1" option next to this more complex option? |
15:46 | <annevk> | wanderview: v1 would be to do less, but nothing that is incompatible I guess |
15:46 | <annevk> | wanderview: afaict we can ship most of the methods independently |
15:46 | <wanderview> | annevk: hmm... ok... I guess I just don't want the simple proposal to get caught up in bikeshedding the bigger proposal |
15:47 | <annevk> | wanderview: what would you consider a reasonable v1? I could add a "Rollout" section that discusses this |
15:47 | <annevk> | wanderview: v1: these methods; v2: the rest |
15:48 | <annevk> | wanderview: or do you think we need to present it differently? |
15:48 | <wanderview> | annevk: I think that would be reasonable... what you had for v1 before? |
15:48 | <annevk> | wanderview: so everything but boxes? |
15:49 | <wanderview> | annevk: yea, I think so |
15:53 | <annevk> | wanderview: https://wiki.whatwg.org/wiki/Storage#Rollout |
17:04 | <wanderview> | Domenic: annevk: does this address the concerns from yesterday? https://github.com/yutakahirano/fetch-with-streams/issues/30#issuecomment-90647469 |
17:05 | <wanderview> | I think it effectively lets fetch steal the body from the original Request as it does today |
17:09 | <annevk> | wanderview: you probably want to propose it without the shorthand syntax, or does that enable something that is lost on me? |
17:10 | <wanderview> | annevk: you mean without Request.pipeTo()? That is what enables Domenic's approach to see the consumer WritableStream directly |
17:10 | <wanderview> | its a rename of what we were calling setWriter() |
17:12 | <wanderview> | annevk: Domenic: I guess the thing I don't know how to handle with the WritableStream revealer function is a tee() or clone() done by fetch in order to handle redirects |
17:14 | <Domenic> | I haven't had time to read much before heading to lunch but I'll just say that largely the point of separating stream and reader was so we could have this tiered high level/low level access. Building in a third tier seems quite bad from that perspective. Everything body-related should be on the res.body stream. |
17:15 | <Domenic> | Alternately we could give up on separating the "response" and "response body" concepts and make Response subclass Readable(Byte)Stream |
17:16 | <wanderview> | Domenic: but... you're explicitly asking for something to bypass a body ReadableStream so you can see the consumer WritableStream directly... |
17:16 | <Domenic> | But anyway more after lunch |
17:16 | <wanderview> | Domenic: we don't have to call it pipeTo()... I just thought that accurately described the semantics we talked about yesterday... provide a WritableStream sink and begin pushing data there |
17:16 | <wanderview> | bye |
17:25 | <jgraham> | Anyone remember jsbell's GH handle? |
17:25 | <jgraham> | Oh found it |
17:26 | <jgraham> | In related news: https://critic.hoppipolla.co.uk/r/4569 |
17:26 | <jgraham> | wanderview: ^ |
17:28 | <wanderview> | jgraham: awesome! |
17:34 | <annevk> | wanderview: I guess I'll bow out until you guys find something |
17:34 | <annevk> | I think I share tyoshino's ideas |
18:22 | <wanderview> | annevk: I'm not sure where my idea conflicts with his... other than trying to do his "operations" ReadableStream idea... but I'm not sure how a wrapper really helps us here |
18:25 | <annevk> | I wonder where JakeA is |
18:25 | <annevk> | wanderview: dunno |
18:26 | <annevk> | wanderview: what do you think of the formalizing of boxes I did? Was that what you had in mind? |
18:26 | <annevk> | wanderview: I also added the examples you asked for how it would work with IDB and Cache |
18:30 | <wanderview> | annevk: oh... I started to look at that and then got side-tracked... just a sec |
18:33 | <wanderview> | annevk: hmm... would it be too magical if the name of a Cache or IDB matches a box name... then it is a box? |
18:33 | <wanderview> | I guess that would prevent multiple Cache object and IDBs in a single box |
18:34 | <wanderview> | annevk: did you consider an API like StorageBox.add(caches.open("myCache")) ? |
18:35 | <wanderview> | or StorageBox.add(indexedDB.open("myDB")) |
18:36 | <wanderview> | I guess it depends on if we want to be able to move a DB or Cache into a box or not... and if we want to support that from an implementation side |
19:19 | <TabAtkins> | Domenic: There's a `bikeshed debug --print-exports` command that lists exported vs non-exported terms. Note that only "dfn" type definition are unexported by default - all the rest automatically export unless you explicitly tell them not to. |
19:25 | <Domenic> | TabAtkins: do you think it would be useful to have the index section mark exported items somehow? |
19:25 | <Domenic> | maybe it already adds a class and we just need to style it... |
19:26 | <TabAtkins> | Domenic: That's not useful information for a spec reader, so no. I've wanted to expose that more naturally for bikeshed users, but haven't given it enough thought to figure it out. |
19:27 | <Domenic> | It seems useful information for anyone writing a spec based on yours |
19:34 | <annevk> | wanderview: the name matching seems too magical, .add() seems somewhat nice |
19:34 | <annevk> | wanderview: although it requires overloading of sorts on the boxes rather than the other APIs supporting boxes... |
19:35 | <Domenic> | wanderview: now that i read your thing it feels like it's just renaming .setWriter to .pipeTo, so I am less scared. |
19:35 | <annevk> | wanderview: but yeah, should probably tweak that |
19:35 | <annevk> | TabAtkins: any closer to a DOM PR? |
19:35 | <annevk> | TabAtkins: btw, if it could become a single commit in the end that'd be great |
19:35 | <TabAtkins> | annevk: I'm like 1 hour of work away. I was just on vacation without internet for a week. |
19:35 | <annevk> | TabAtkins: that'd avoid spamming Twitter a bunch |
19:35 | <TabAtkins> | And yeah, no problem squishing the commits. |
19:36 | <annevk> | TabAtkins: ah hope you had a blast |
19:36 | <TabAtkins> | I did! |
19:36 | <TabAtkins> | BOARD GAME CRUISE THROUGH THE CARIBBEAN |
19:37 | <annevk> | That's a thing? Haha nice |
19:37 | <jamesr___> | TabAtkins: i forgot to ask - did you play puerto rico? |
19:38 | <TabAtkins> | jamesr___: No, it wasn't brought on board I think. |
19:38 | <terinjokes> | i'm now interested in knowing what board games were played |
19:42 | <TabAtkins> | terinjokes: Tons. There were about 300 on board, chosen by the ~150 people registered for the con. (It was a normal cruise ship, so the other 5k people on board were just normal cruise people.) |
19:42 | <TabAtkins> | I played, let's see... |
19:43 | <TabAtkins> | Pandemic: The Cure, Patchwork, Roll For The Galaxy, Caverna, Royals, Mysterium, Lords of Waterdeep, Castles of Burgundy, Far Space Foundry, Fleet, Xia, Key Market, Onirim, Abluxxan, and Istanbul. |
19:43 | <TabAtkins> | (I wrote down all of them.) |
19:46 | <terinjokes> | wow. i think of those I've only ever played Pandemic |
19:47 | <TabAtkins> | terinjokes: Note that Pandemic: The Cure is a fast dice-based version of Pandemic. |
19:47 | <terinjokes> | been wanting to startup my project of doing a new game on some regular-ish time schedule. i should get back to doing that! |
19:47 | <terinjokes> | ah, then nope |
19:47 | <TabAtkins> | (Like Roll For The Galaxy is a fast dice-based version of Race For The Galaxy.) |
19:48 | <TabAtkins> | All of these were new to me, too, which was part of the point of the cruise. ^_^ We were scoping out a bunch of things we were interested in buying. |
19:51 | <terinjokes> | nice |
20:00 | <Krinkle> | annevk: Hm.. just ran into a fun issue with serialising our editor DOM to html. Comments. |
20:00 | <Krinkle> | createComment results in an invalid/unserializable DOM. |
20:00 | <Krinkle> | https://gist.github.com/Krinkle/1437de41481789ac6c96 |
20:02 | <Krinkle> | We'll probably run html-escape (in addition to special entity scape for '-' so its xml compliant), and then someone decode that on the client side (using either a static map, or by parsing inside a detached <textarea> and retreiving textcontent?) |
20:03 | <Krinkle> | it's weird to html escape a value before passing to createComment though |
20:10 | <Domenic> | I'm not terribly surprised... just more in the category of mismatches between createXYZ() and the parser |
20:13 | <Krinkle> | Domenic: One can basically insert arbitrary HTML in there, including <script> |
20:15 | <Krinkle> | In our case we're not actually appending to innerHTML, that's a terrible practice |
20:15 | <Krinkle> | Just doing that for simplicity sake |
20:15 | <Krinkle> | (and destroys references etc.) |
20:19 | <Krinkle> | having some sort of text accessor on Comment nodes so that we can safely insert arbitrary user input into comment nodes would be useful. |
20:19 | <Krinkle> | And we'd have to either break createComment or create an alternate constructor. |
20:25 | <Ms2ger> | Some DOMs aren't serializable, that's not going to change |
20:56 | <Krinkle> | Ms2ger: Interesting. Any other cases you have in mind? |
21:07 | <TabAtkins> | Krinkle|detached: there are several ways to use DOM to create unserializable documents. It's not too strange. |
21:07 | <TabAtkins> | For example, you can use DOM to insert an <a> child of an <a>, or have lone <tr>s floating around the document. |
21:41 | <Krinkle> | TabAtkins: <a> inside <a> works fine in parsing though. Especially in XML. |
21:41 | <Krinkle> | It's not "allowed" but afaik works fine, no? |
21:42 | <Krinkle> | Ah, interesting. It cuts off |
21:42 | <TabAtkins> | No, "<a>foo<a>bar</a></a>" parses equivalent to "<a>foo</a><a>bar</a>". |
21:42 | <TabAtkins> | Yeah. |
21:43 | <TabAtkins> | XML doesn't have special per-element parsing rules like the HTML parser does. |
21:43 | <Krinkle> | Our content model ensures that doesn't happen though. We treat anchor links the same way as bold/italic/etc. as annotations instead of elements. Which apply to offsets in text nodes. |
21:43 | <Krinkle> | The tree is then created based on that. |
21:43 | <TabAtkins> | Sure, that's reasonable for an editor. |
21:44 | <TabAtkins> | I was just providing some examples of "the DOM can produce something unserializable". |
21:44 | <Krinkle> | but we visualise html comments (which some Wiki pages make heavy use of to leave info blurps to other editors) in our editor as <span>. |
21:44 | <Krinkle> | But ran into this issue where some editors leave comments including "--" in a regular English sentence. |
21:44 | <Krinkle> | and then subsequently, broke our serialisation :-/ |
21:45 | <TabAtkins> | You can escape all - chars inside of comments, I suppose. |
21:45 | <TabAtkins> | No, that'll break viewing source. |
21:45 | <TabAtkins> | Replace them with unicode dashes. ^_^ |
21:45 | <Krinkle> | It needs to round trip :) |
21:46 | <Krinkle> | downstream reports are https://phabricator.wikimedia.org/T95039 and https://phabricator.wikimedia.org/T95040 |
21:46 | <Krinkle> | It seems we're going to be encoding & - and > |
21:46 | <TabAtkins> | Replace every -- with an emdash - they can only occur when the user is in your editor, so that's fine, and you can even roundtrip it by translating back. (That'd make actual em-dashes not *quite* roundtrip correctly, but hey, those are rare.) |
21:47 | <Krinkle> | Not rare if your user is a Wikipedian. |
21:47 | <Krinkle> | :P |
22:38 | <wanderview> | Domenic: has the performance impact of always returning a Promise from read() and write() been discussed somewhere? |
22:39 | <Domenic> | wanderview: yeah. promises are cheap when well-optimized, and certainly cheaper than I/O. |
22:40 | <wanderview> | Domenic: I guess I'm curious about how one optimizes out the object creation and the required async micro-task cost... it seems those are harder things to optimize out than say the generator object creation |
22:41 | <Domenic> | wanderview: yeah you don't optimize out object creation, but VMs are good at creating objects. The micro-task cost we discussed and eventually landed on the fact that most reads are going to be async anyway, so the microtask adds no extra overhead. |
22:41 | <wanderview> | Domenic: I mean.. I'm willing to accept Promise costs periodically... but once every 4096 bytes may be a bit much... |
22:41 | <wanderview> | Domenic: in the case where you have chunks buffered up... it seems like you would want to be able to get all of them synchronously, though... no? |
22:42 | <Domenic> | right, that was the original design with while (rs.state === "readable") { rs.read(); } |
22:42 | <Domenic> | (read() being sync in that case) |
22:42 | <wanderview> | Domenic: I vaguely remember that... what was the issue that forced the change? |
22:43 | <Domenic> | wanderview: a combination of wanting rs.readInto(buffer) + non-epoll streams who do their work in a threadpool or similar means you need something like async read(), or setAllocator |
22:44 | <wanderview> | Domenic: is ReadableByteStream or the new precise-flow-control stuff solving this by letting me say "read up to this much data before resolving"? |
22:44 | <Domenic> | Unclear how setAllocator would work though given that I/O is IPC though, now that I think about it |
22:45 | <wanderview> | Domenic: I/O doesn't have to be IPC... you can open a file descriptor in the parent and then dup(2) it to the child process... then file reads are in the child process |
22:45 | <Domenic> | wanderview: the intent of ReadableByteStream's read(view) is that view.byteLength is at least a hint, although I think we didn't want to make it binding... |
22:45 | <wanderview> | Domenic: network is probably always in the parent process behind IPC, though (because of http 1.1 channels multiplexed on same socket, etc) |
22:45 | <Domenic> | wanderview: ah OK, just was thinking of the other day when you were talking about IPC costs... |
22:46 | <Domenic> | my vision of read(view) was that you'd pass that view pretty directly to read(2) |
22:46 | <Domenic> | so for socket streams you might get back less than view.byteLength |
22:46 | <Domenic> | but for file streams, unless you're at end of file, you'll probably get view fully filled |
22:47 | <Domenic> | IIRC read(2) has an option to not return until the buffer is filled ... but it doesn't work with nonblocking sockets? |
22:47 | <Domenic> | Ah no, it's recv(2). MSG_WAITALL |
22:49 | <Domenic> | we could make the implementation concatenate buffers i guess? or let that be an option!? i don't see any reason why it's impossible, I was just going for the more direct mapping |
22:50 | <Domenic> | it's a latency vs. efficiency thing i guess, which perhaps is best to leave to applications to decide? |
22:51 | <wanderview> | sorry, on phone |
22:51 | <Domenic> | np |
22:51 | <Domenic> | reminds me of this issue https://github.com/whatwg/streams/issues/171 |
22:54 | <Domenic> | It is true in general that browser promise impls are wildly unoptimized. User-land versions regularly achieve 4x performance and 1/4th the memory consumption, and they don't even have access to all the tricks browsers do (like skipping the microtask queue if calling in from C++) |
22:54 | <wanderview> | Domenic: I wonder if we could do something like .read(numDesiredChunks) |
22:55 | <wanderview> | and the promise resolves when that many are available |
22:55 | <Domenic> | wanderview: that seems pretty reasonable. Would kind of want to see data that this was a bottleneck, or a non-performance use case, before doing so. |
22:56 | <Domenic> | I'll file an issue to track to see if anyone has non-perf use cases |
22:56 | <wanderview> | Domenic: it seems more appropriate for ReadableByteStream... but might be usable in ReadableStream |
22:57 | <Domenic> | wanderview: maybe for RBS it's .read(view, { waitUntilFull: true }) |
22:57 | <wanderview> | Domenic: thinking of when you are reading some framed protocol... you probably don't want to get woken up until the next frame is completely there |
22:57 | <wanderview> | Domenic: I don't think c++ can skip the microtask, can it? I mean.. it seems like it risks accidentally breaking the micro task guarantee in your API |
22:59 | <Domenic> | wanderview: it's hard to say precisely what I mean here as the area is so complicated. But the main idea is that C++ always enters back into JS from a clean stack, and that's what microtasks guarantee: a clean stack. One way of seeing this is that the very first thing done after transitioning from C++ to JS is to exhaust the microtask queue. So the very |
22:59 | <Domenic> | first thing that happens on the JS side, after doing resolve_promise_from_cpp(cpp_p, cpp_v), is calling p's onFulfilled handler with v |
23:00 | <Domenic> | IIUC SpiderMonkey doesn't actually implement a microtask queue and just uses their task queue, so maybe it is not so efficient in SpiderMonkey. |
23:02 | <wanderview> | Domenic: right... but its still an async runnable even if it skips to the head of the (micro)task queue |
23:02 | <othermaciej> | the spec says to drain the microtask queue between every regular task queue item |
23:02 | <othermaciej> | (if I read it correctly) |
23:03 | <wanderview> | and I guess unwinding and rewinding the stack has noticeable perf impacts when done in too tight a loop |
23:03 | <othermaciej> | and after completing execution of a <script> element |
23:03 | <othermaciej> | I don’t believe it says to do anything on entry from C++ to JS |
23:04 | <othermaciej> | it might be you can do it like that and have no observable behavior difference but it is not obvious how offhand |
23:05 | <othermaciej> | in particular, you can exit JS to C++ and re-enter JS sometimes without having performed microtasks |
23:05 | <Domenic> | othermaciej: hmm, maybe i am confused. But that was my interpretation of the spec, modulo the spec not having any "entry from C++ to JS" concept. |
23:05 | <Domenic> | Oh, that makes sense |
23:05 | <othermaciej> | this will occur if you have multiple event handlers for the same event, for instance |
23:05 | <Domenic> | Or just arr.forEach(cb), where hypothetically forEach is implemented in C++. |
23:06 | <othermaciej> | the spec is closer to saying that microtasks are run on *exit* from JS to C++, except only if you are on a “clean stack” |
23:06 | <othermaciej> | where “clean” == in the top level event loop or in the html parser |
23:06 | <othermaciej> | and also it sometimes drains the queue on times you didn’t just exit from JS, in case right when you exited, you did not have a clean stack |
23:07 | <othermaciej> | that is how I understand it anyway |
23:08 | <Domenic> | I guess the point I was really trying to make was: in Node.js, if you do `fs.readFile(..., result => resolvePromise(p, result))`, resolvePromise has to actually schedule a microtask to ensure p's handlers are called with a clean stack. So we wait for all the rest of the JS in that event loop turn to run, then unwind the stack, then run the microtask queue, |
23:08 | <Domenic> | with several (perf-impacting) C++-to-JS transitions. Whereas in browsers, you don't have to pay that cost. |
23:09 | <Domenic> | JS environments which try to completely control the event queue, like Angular, do similar optimizations |
23:10 | <Domenic> | where they technically run their promise handlers "sync" but if you're programming correctly-according-to-Angular, it's unobservable. |
23:25 | <wanderview> | Domenic: are you trying to add an interface contract definition for ReadableStream and WritableStream in this issue? https://github.com/whatwg/streams/issues/312 |
23:26 | <Domenic> | wanderview: that thread has lost me a bit tbh... |
23:26 | <wanderview> | Domenic: I think it would be really helpful to have definitions of ReadableStream and WritableStream separate from the default implementation adapting JS functions |
23:28 | <Domenic> | wanderview: all ReadableStream instances must necessarily adapt JS functions (or JS manifestations of C++ functions)... other things obeying the "readable stream contract" might work differently though |
23:28 | <Domenic> | the necessity is because myFetchReadableStream.read === myFileReadableStream.read, if both variables are ReadableStreams. |
23:29 | <wanderview> | Domenic: so a DOM created ReadableStream representing some C++ implementation like a file stream has to be created through the ReadableStream Constructor? |
23:29 | <wanderview> | Domenic: why is myFetchReadableStream.read === myFileReadableStream.read a necessity? |
23:29 | <Domenic> | wanderview: I mean, it has to obey the observable invariants; if there are tricks you have for getting around that, use them, but... |
23:30 | <Domenic> | wanderview: if they are both ReadableStreams then they have the same prototype and thus the same method |
23:30 | <Domenic> | wanderview: if one is a FetchReadableStream and another is a FileReadableStream then yeah they can be different |
23:30 | <Domenic> | wanderview: analogy---promises |
23:30 | <Domenic> | wanderview: all C++-created promises are, at least in V8/Blink, created "via the Promise constructor" |
23:30 | <wanderview> | Domenic: I guess what I am saying is, it would be nice if the spec defined the observable invariants instead of making me try to dig them out of a pile of js |
23:31 | <Domenic> | even though the promises will be backed by very different behavior |
23:31 | <Domenic> | yeah, agreed on that. We want that anyway so we can say---or better, programatically test---that ReadableByteStream behaves the same as ReadableStream. |
23:31 | <Domenic> | the templated tests are a start |
23:35 | <wanderview> | Domenic: so you are saying you want JS-created ReadableStream objects to have exactly the same prototype as DOM API created ReadableStream objects? |
23:36 | <Domenic> | wanderview: yeah, exactly, just like Promise. |
23:36 | <wanderview> | Domenic: pretend I don't know much about Promise :-) |
23:37 | <Domenic> | hmm, well, then, yes. The underlying source is meant to provide the customization hooks |
23:37 | <Domenic> | The underlying source could be a JS facade over a C++ object, for sure |
23:37 | <wanderview> | Domenic: I guess then it would be nice to have a source interface definition... and separate out the js-adapter specifics into a separate implementation of that interface |
23:38 | <Domenic> | hmm what's a "source interface definition"? |
23:38 | <wanderview> | Domenic: the underlying source |
23:38 | <Domenic> | https://streams.spec.whatwg.org/#rs-constructor kind of tries |
23:38 | <Domenic> | what are js-adapter specifics? there are no implementations of the underlying source interface in the streams spec |
23:39 | <Domenic> | fetch-with-streams has one |
23:39 | <wanderview> | Domenic: nm... I don't think what I asked makes sense |
23:40 | <wanderview> | Domenic: do you anticipate things like ReadableStream.pipeTo() operating on the public ws.write() method? so allowing monkey patching |
23:41 | <wanderview> | the current text pointing at the ref implementation suggests it does |
23:41 | <Domenic> | An implementation could always do something like ReadableStream.prototype.read = function () { switch (this@[[hiddenType]]) { case "user-created": return userCreatedImpl(this); case "fetch": return fetchStreamImpl(this); } }; where user-created follows more or less the exact spec algorithm and fetchStreamImpl manages to maintain all its observable invariants |
23:41 | <Domenic> | but is implemented differently. |
23:42 | <Domenic> | Then we have to tease out what the observable invariants are. I guess maybe that's what you're asking for. |
23:42 | <wanderview> | Domenic: I'm asking about monkey-patching .write in this case |
23:42 | <Domenic> | sorry I was still on the previous subject |
23:42 | <wanderview> | but I guess .read is the same |
23:43 | <wanderview> | Domenic: I think the "underlying source" model maps reasonably well to the DOM idiom of having an "inner object" |
23:43 | <Domenic> | hmm interesting |
23:43 | <wanderview> | but I guess DOM APIs typically operate explicitly on the inner objects... not on the public APIs |
23:43 | <Domenic> | Ah interesting |
23:43 | <wanderview> | so rs.pipe(ws) would do something like "write data to ws's underlying sink" instead of calling ws.write() |
23:44 | <Domenic> | regarding monkey-patching write and pipeTo... I'm a bit torn on how to handle this. I've probably given up on it using `this.read()` etc.; it can use tamper-proof versions for operating on `this` to reduce complexity. But it seems quite important to allow polymorphic dispatch on the *argument*. |
23:44 | <wanderview> | Domenic: the polymorphism is achieved in this spec by swapping out the underlying sink, no? |
23:44 | <Domenic> | That said as we went through in some thread a while ago it's hard to make that work while still allowing unobservable off-main-thread piping |
23:45 | <Domenic> | wanderview: heh, I guess that is where my argument leads... |
23:45 | <Domenic> | wanderview: my hope was that you could create structurally similar writable streams that obey the same contract without being exactly WritableStreams |
23:45 | <wanderview> | Domenic: going to the inner objects is nice for DOM people like me... but I wonder if its not very javascripty |
23:45 | <Domenic> | Yeah, it's definitely not very JavaScriptey. But neither is off-main-thread piping :P |
23:45 | <wanderview> | Domenic: that seems at odds with requiring prototypes to be exact matches |
23:46 | <Domenic> | wanderview: nothing requires the prototypes to be exact matches, I was just saying, if they are, then they need to be the same impl |
23:46 | <wanderview> | Domenic: if you want pure duck types then I don't think we should require exact prototype matches |
23:46 | <Domenic> | wanderview: you *could* have separate FetchReadableStream that is written from scratch in its own spec and doesn't reference the stream spec at all, except trying to be duck-compatible. |
23:46 | <Domenic> | But that seems like a waste of effort. |
23:46 | <wanderview> | Domenic: like... I think the JS adapter stuff should be in a JSReadableStream that chains from ReadableStream, etc |
23:47 | <Domenic> | Anyway, my hope might be silly, is where I was going with that. |
23:47 | <wanderview> | and there is no spec'd concrete implementation of ReadableStream |
23:47 | <Domenic> | This just feels very silly when you go back to the promise analogy |
23:48 | <Domenic> | We don't have every promise-returning API on the web platform creating their own version of the Promise class just so they can get different backing behavior |
23:48 | <wanderview> | Domenic: I don't think we have the optimization concerns with off-main-thread piping, etc, with Promises that we do here... |
23:48 | <wanderview> | something has to give here :-) I don't think all these requirements are compatible |
23:49 | <Domenic> | I am leaning toward abandoning duck-compatibility for writable streams |
23:49 | <wanderview> | Domenic: what about for ReadableStreams? |
23:50 | <Domenic> | wanderview: unsure, nothing accepts them right now (except their own methods, and JS functions which will operate on a duck level) |
23:50 | <wanderview> | Domenic: but their own methods will operate directly on underlying source? |
23:50 | <Domenic> | wanderview: yeah, definitely. |
23:51 | <wanderview> | Domenic: is there an existing issue for this or shall I write a new one? |
23:51 | <Domenic> | wanderview: well, I was for a while planning on making pipeTo operate in terms of this.read() and friends, but after doing TeeReadableStream I am leaning away from that. |
23:51 | <wanderview> | I think it was partially discussed in the transfer issue, but seems it deserves its own issue |
23:51 | <Domenic> | wanderview: we kind of got sidetracked in the ... web socket issue, was it? into these |
23:51 | <Domenic> | ah yeah |
23:51 | <wanderview> | Domenic: I'll write one |
23:51 | <Domenic> | ok cool |
23:52 | <Domenic> | Hmm, promises enable duck-compatibility with Promise.resolve casting .then'ables ..... that's a more sound model actually. Also a complicated one that we probably don't need to build in to the platform? |
23:53 | <Domenic> | It should be pretty straightforward to write a JS function duckReadableStreamToRealReadableStream |
23:53 | <Domenic> | Then people can use that if they need to |
23:54 | <wanderview> | Domenic: I do think a ReadableStream wrapper constructor would be nice... making it take a duck typed stream would be reasonably |
23:54 | <Domenic> | The promise-esque alternative being that we have ReadableStream.cast = duckReadableStreamToRealReadableStream and every ReadableStream-accepting API does ReadableStream.cast first (like all promise-accepting APIs do Promise.resolve first). Really unnecessary. |
23:54 | <Domenic> | brb cafe closing!! |
23:55 | wanderview | forgot he was in pacific time zone. |