2025-11-03 [14:27:20.0064] nicolo-ribaudo: re https://bugzilla.mozilla.org/show_bug.cgi?id=1950211, the "Don't call well-known Symbol methods for RegExp on primitive values", I'm having trouble inferring the status from the bug tracker. Did FF ship? Or just ship telemetry? And is there telemetry? [14:27:40.0138] Looks like V8 implemented without a flag and will just ship it whenever main makes it up to stable for them [14:27:52.0235] same in webkit [14:28:01.0474] not sure if this means we should land the PR or wait for FF [14:34:14.0067] I don't remember, I'll get an answer in the next days [15:20:58.0959] * I don't remember, I'll get you an answer in the next days 2025-11-04 [06:38:54.0687] It looks like we just shipped the telemetry. I think at this point if webkit and v8 are shipping, we should just remove the telemetry and ship the change. nicolo-ribaudo do you want to make the updates, or would you like me to take it over? [06:44:47.0645] I don't know if either of the other browsers are shipping to stable, to be clear [06:47:08.0460] > <@dminor:mozilla.org> It looks like we just shipped the telemetry. I think at this point if webkit and v8 are shipping, we should just remove the telemetry and ship the change. > nicolo-ribaudo do you want to make the updates, or would you like me to take it over? Mh yeah it looks like I ended up not finishing that patch because somebody was refactoring the same code at the same time šŸ˜… I am not able to type for a few weeks, please go ahead :) I'd be curious to see the telemetry data we have so far [07:12:02.0835] bakkot: do you have links handy for the webkit and v8 changes? It would be helpful for coordinating shipping. [07:13:36.0272] Linked from the ecma262 issue iirc, I can dig them up when I'm at a computer next [07:13:49.0298] Or the pr rather [07:16:42.0512] Got them, thanks! [09:02:09.0545] There's an interesting discussion here on native error objects in Wasm - https://github.com/WebAssembly/custom-descriptors/issues/80. The driving motivation is Wasm GC objects being used as throwable errors, by being able to somehow relate the Wasm GC error object's descriptor to make it a real error object. This discussion comes under the proposal umbrella of turning "opaque" GC objects into real objects with descriptors. In particular the `Symbol.underlyingError` could be interesting to get feedback for from a TC39 perspective. [09:10:06.0769] @guybedford:matrix.org There's still time to add discussion items to the agenda for the next TC39 meeting. [09:10:51.0781] I'm not personally involved in the above discussion, I'm posting here in the hopes more folks can take these discussions on! [09:15:56.0262] my reading of this is that it would only affect debugger behaviour, which 262 does not constrain [09:16:38.0684] It is an interesting question how hosts should expose their own well known symbols though [09:18:03.0749] TG4 probably has a lot of the interested parties. This person may want to make a presentation to them. Not sure what TC39 could do about it though. [10:57:20.0741] The root problem is basically subclassing Error for Wasm GC objects, which is currently off the table as something in Wasm explicitly. [10:57:39.0297] so if non-Error objects might be able to define a symbol or otherwise to get error-level treatment [11:37:31.0123] Haven't read the thread yet, but why not create an Error at the wasm boundary, with a `cause` being the wasm opaque object ? [14:27:17.0261] Wasm GC objects can be passed around to and from JS FFIs. Is the idea that you'd wrap every FFI call which involved a Wasm GC object to inspect the object and determine if you should substitute a wrapper? [14:27:26.0678] I think that would work but it's probably prohibitively expensive [14:27:37.0964] (possibly I am not understanding the suggestion) 2025-11-05 [18:00:52.0180] are wasm opaque objects exposed directly to JS code? My impression was that there is currently glue code to wrap those. Now of course we could ask the question for when wasm objects are no longer opaque and gain prototypes, and possibly own props. My concern is that I don't want to introduce yet another "kind" of Error that all error aware code out there needs to recognize (not just debuggers). We have Error instances, and I guess we're also getting objects extended with `Error.captureStackTrace`. [18:03:20.0600] especially now that we have `Error.isError`, I think it'd be a mistake to introduce something that isn't an error but behaves like one. It's already unfortunate enough we have to standardize captureStackTrace [18:19:01.0275] Mathieu Hofman: the wasm custom descriptors proposal turns the opaque objects directly into objects with descriptors allowing getters and setters etc. [18:19:34.0448] they thus effectively become resource types, backed by a wasm gc managed struct or array [18:23:15.0327] I'd have thought the solution though would be to call out to `wrapErr(scalaErr) => Object.assign(new Error(), { gcError: scalaErr })` through to JS when there is an error to have a JS error type wrapping a scala error type instead of the converse, but I haven't thought about it deeply enough to have a strong opinion [18:32:22.0332] Right, even with custom descriptors support, this is effectively purpose built glue code creating JS objects to expose wasm things. In that case, I would find it natural to create a `new Error()` and define on it a `cause: wasmThrowable` property. 2025-11-10 [11:47:37.0414] Would it be possible to get some folks from the runtimes that have implemented Explicit Resource Management to help finish the reviews on the remaining Test262 PRs? I've been trying to get some eyes on these three PRs for a few months, but the Test262 maintainers seem to be spread very thin: - https://github.com/tc39/test262/pull/4482 - https://github.com/tc39/test262/pull/4480 - https://github.com/tc39/test262/pull/4478 2025-11-11 [18:41:01.0566] nicolo-ribaudo: thanks for putting together slides for the export-\*-as PR. while we're here, I noticed in https://tc39.es/ecma262/multipage/ecmascript-language-scripts-and-modules.html#sec-resolveexport step 9.e.iii.1 that it says "Assert: There is more than one \* import that includes the requested name". That should be "\* _export_", surely, yes? [19:16:06.0464] Yep you are right [19:57:03.0310] I'm testing on SpiderMonkey. there's some issue with the expectation around how "asyncTest" should interact with "negative". not yet sure if it's on our side or in the test side [19:58:41.0470] also there are 3 tests that expects behavior before https://github.com/rbuckton/ecma262/pull/14 , for using in switch [20:03:05.0224] ljharb: I am confused by https://github.com/tc39/agendas/commit/61962210dd2547d194eae2bb9cdf8669421a4f98; when did this get stage 2.7 and where are the tests for it? [20:04:18.0749] Thanks, I'll take a look tomorrow [20:21:14.0703] added comments to the PRs [20:23:09.0662] Oh you’re right, my bad. I’ll revert that commit. It’s 2 and I’m going for 2.7 [20:24:08.0211] not sure why i got confused there [09:58:59.0418] If anyone wanted to ask questions about Composites ahead of plenary I'll be dialed into the legacy "R&T Monthly" zoom call on the [TC39 events calendar](https://github.com/tc39/Reflector/issues/290) that starts in one hour from now (19:00 UTC) [14:28:37.0062] Thanks. These should all be addressed now 2025-11-12 [01:20:39.0089] ljharb It was MF from my laptop :) 2025-11-16 [17:49:16.0609] draft schedule is up! see Reflector issue for link: https://github.com/tc39/Reflector/issues/564 [17:56:23.0320] Day 1 afternoon there are a bunch of stage 4 advancements and my low priority topic. I wonder if we could squeeze some time off the advancements (that tend to be very quick), and replace my low priority topic with a different 30 min one? I'm very happy to present, but I'm feeling a bit like I'm wasting time by presenting it when there are things currently scheduled to overflow šŸ˜… [18:04:26.0957] sounds like you are volunteering to move your topic to the bottom of schedule priority. we can certainly do that [18:04:46.0391] Well it was already marked as low priority in the agenda [18:04:53.0948] I mean the one about other module stuff on the web [18:05:12.0855] Which is just an informative topic, not something for our specs [21:48:54.0041] Is https://tcq.app working for anyone? It seems to be _broken on my side of the internet_ [21:51:06.0919] internal server error 😭 [21:56:30.0700] `/summon` bterlson [22:18:04.0512] Chris de Almeida: Didn't know you were here in person. :) [22:29:50.0706] Can we try with the V2 this time? šŸ˜… [22:37:50.0011] we just might! Christian and I are trying to reproduce the bugs we found from using it last time and we can't reproduce... [23:49:04.0085] Brian is also debugging TCQ: Legendary Edition [23:54:24.0546] Rob Palmer: If you could get him, to give away the stats of his setup (VM cpu cores, ram size), I could reproduce this at least as an approximation. I very very highly assume, that there are various race conditions in his original code (that TCQ reloaded, simply re-uses) - having an environment that is more close to his original, might "solve" the currently reported bugs for TCQ reloaded, which we could not reproduce now. [02:41:38.0295] It's hosted on app service D1 plan, 1GB ram, some slice of a vcpu not sure if multicore 2025-11-17 [23:41:50.0160] Rob Palmer: I quadrupled (always wanted use that word) QUAD DAMAGE the resources for https://staging.tcq-reloaded.com and after some small tests, I will deploy prod too this evening (during the Karaoke night, when I know you are not needing TCQ :D). [00:50:06.0889] Ashley Claymore: https://github.com/tc39/proposal-string-dedent/issues/75 [13:16:31.0949] > Now of course we could ask the question for when wasm objects are no longer opaque and gain prototypes that would be with https://github.com/WebAssembly/custom-descriptors [15:27:20.0905] Chris de Almeida: I am on the agenda as the last slot for today; per my schedule constraints I can't be present after 1600 (ideally 1500). could I be moved to a later day? [15:27:32.0393] if not it's not an urgent item and can get removed [15:28:35.0360] If you want we can swap our slots [15:29:08.0745] (the export defer one) [15:30:10.0253] I'm hoping a later day works anyway because I am sick today and may not be up to presenting that item today 2025-11-18 [16:47:36.0895] is tcq still dead? [16:47:58.0216] i guess the website is still intermittent [16:49:22.0385] ah i see a link was posted mere moments ago [17:00:59.0720] meeting is starting, for anyone else who is remote and not paying enough attention to the clock [17:02:13.0249] I must be blind, but I can't find the google form to get the video chat link? [17:02:38.0885] https://github.com/tc39/Reflector/issues/564 [17:03:03.0170] You are the second person asking, we should make it more visible in the issue [17:03:06.0529] it is under the "Video Conference" heading [17:03:11.0683] in said thread [17:04:00.0376] woot woot another japan meeting begins [17:04:43.0570] break at 10:00? [17:06:30.0628] who doesn't love starting with a break [17:22:15.0555] sorry about that, I will fix [17:23:11.0808] TCQ is buggy af.. I am struggling [17:23:51.0431] 1. move agenda topic 2. wait 3. reload page 4. hope the item is where it's supposed to be 5. GOTO 1 [17:29:16.0764] lol `[[IsLockFree1]]` would be a little silly [17:29:40.0335] What was the change in the copyright? [17:29:57.0062] Comparing 262’s and 426’s copyright text, it looks the same. [17:30:00.0940] the copyright notice was just some random copyright text that we have no idea where it came from [17:30:04.0573] we hadn't used the alternate copyright for either standard [17:30:20.0025] @justingrant:matrix.org are you comparing the yearly releases or the editors' drafts? [17:30:39.0391] we've already updated the editors' drafts [17:30:51.0542] Shhhh we are dealing with it, Aki noticed one second after saying yes [17:30:55.0423] 426 is also incorrect [17:31:00.0478] Comparing the published specs [17:31:07.0701] @nicol [17:31:16.0808] * @nicolo-ribaudo:matrix.org just said it was already correct [17:31:56.0662] https://github.com/tc39/agendas/blob/main/2025/tc39-2025-049-Rev1.pdf [17:31:59.0106] I was wrong [17:32:02.0648] it's is wrong [17:33:00.0886] You are welcome to prepare another vote. I think we could get through it very quickly. [17:33:03.0964] that's the wrong link [17:33:09.0547] https://github.com/tc39/ecma426/pull/237 [17:33:57.0452] if my work focus hadn't changed, I would be likely interested in editor group :-/ (but then timezones would also be messy) [17:35:44.0764] https://github.com/tc39/ecma262/pull/3701 [17:35:51.0752] Diff: [17:39:10.0485] It would be a very uncontroversial vote, but given it's not urgent maybe we should wait until next time? I assume the same things I said about stage advancement materials also apply to votes materials [17:39:46.0810] (I would be happy to "vote" yes now though) [17:40:28.0128] I actually just turned the PR to a draft bc I want Samina's eyes on it before I change anything formal. [17:42:06.0436] `[[IsLockFreeToo]]` [17:56:00.0761] Is this only an error if a named export is requested, or if the module in question is imported? [17:56:30.0647] * Is this only an error if there's an ambiguous named import, or if the module in question imports two conflicting bindings? [17:56:43.0969] only if you actually request the name [17:56:57.0196] ruh roh engine262 [17:56:58.0239] This is actually news to me [17:57:37.0446] ambiguous exports like this are actually stripped from namespace exports, which is fun too [17:58:44.0108] ljharb: note the `export * from` in `//library` [17:58:50.0003] it is exporting all bindings from both left and right [17:58:58.0238] but both of those export a `ns` binding [18:00:31.0556] I'm pleased we at least chose to drop clashing export * rather than something more fun like "first one wins" [18:01:56.0656] Do I understand right that we have yet another concept of equality defined by multi-path-importability? [18:02:48.0444] sort of! but it applies only to bindings, not to values [18:04:12.0601] So like, _really_ equal. [18:04:13.0894] What if it exported a live array of all the values [18:05:20.0888] cue adding quadruple equals to the language for stage 1 [18:05:39.0199] Hey, you said it, I only thought about it. [18:08:14.0706] there's lots of equality symbols we could add! `≅ ā‰Œ ≔` etc [18:09:13.0958] puttin' the https://en.wikipedia.org/wiki/J_(programming_language) in JS [18:09:22.0476] hamburger operator [18:09:28.0368] oh, forgot this wasn't the temporal dead zone [18:09:38.0086] ☰ ftw [18:09:49.0156] * ☰ ftw (i have that one on autocomplete) [18:09:51.0792] oh wait J is APL-like but ASCII [18:09:56.0686] RIP my joke [18:09:59.0576] * ☰ ftw (i have that one on autocomplete, i'm incapable of typing the name of that sandwich now) [18:12:59.0565] it's do be like the sometimes [18:13:11.0818] * it's do be like that sometimes [18:13:19.0567] Unicode U+2630 ... so close ... if only it had been U+2620 [18:13:27.0388] is the thing being described here fuzzing or something else? [18:14:20.0050] I guess it's not quite fuzzing in that there is no randomness? [18:14:24.0385] If I understand correctly it's doing all possible combinations of some things, deterministically [18:15:46.0672] are you really into the I Ching? [18:16:31.0077] lol nah it's the trendy menu icon on mobile apps before it was a grid of 9 squares [18:18:19.0600] we are very efficient this morning [18:19:31.0751] right, I would describe it as a kind of metamorphic testing [18:21:32.0520] agreed, not fuzzing, though related I guess? [18:27:18.0242] return override does not add internal slots [18:27:25.0690] and cannot be used to add internal slots [18:27:34.0745] it can be used to add private fields, but those are slightly different [18:28:36.0356] all objects are created with an internal slot which stores a list of their private fields; that list is what gets updated when fields are added to an object, rather than the object itself getting a new slot [18:30:25.0421] thank you, I was trying to look through the spec to confirm that claim [18:34:15.0293] I think it's just editorial though and we would just stick the slot on every object in MakeBasicObject [18:34:47.0525] we wouldn't do a new thing (adding an internal slot to an object after its creation) unless we really had to [18:43:09.0578] The title of this is incorrect on https://github.com/tc39/agendas/blob/main/2025/11.md "Into Locale Info API for Stage 4" - it made it hard for me to find [18:43:52.0849] https://github.com/tc39/agendas/pull/2011 [18:46:09.0397] Frank's art is very intimidating [18:46:17.0646] * Frank's art is very intimidating :D [18:50:28.0516] Clearly van gogh. [18:51:41.0162] Just reviewing the note, the transcription today is missing quite a bit. [18:52:03.0166] Does it require a point of order or is it ok now? [18:53:33.0449] I'm not paying close attention enough, was just reviewing what I had said [18:55:21.0517] tfw _too_ efficient [19:38:24.0837] we are making good time thus far and have already been able to move some overflow topics into the schedule consequently, topics have been shuffled around quite a bit, so please consult for the latest information [20:13:09.0081] I have been wondering what the use case is here [20:14:59.0575] for `maximumFractionDigits`? [20:17:53.0171] Not plenary related. Is there a way we could set proposal repos so that any tc39 member could create and push to branches (and probably branch protection to only allow direct push to main for champions). Would really love to avoid forking for simple contributions. [20:19:04.0647] no sorry I think i was lagging a bit behind, it was a curiosity around trailing zeroes from the user code perspective. not meaningful for this technical discussion. [20:21:37.0761] gentle reminder: please do not tap on the microphones. šŸ™ [20:33:01.0388] remind me whether we've discussed Array#zip before [20:33:12.0489] we have [20:33:17.0812] * remind me whether we've discussed Array.zip before [20:33:32.0493] https://github.com/tc39/proposal-array-zip [20:33:53.0385] excellent, thanks [20:34:00.0044] I personally can't actually imagine a use case for it though [20:34:26.0421] in the sense that zip kind of implies you're gonna iterate? [20:34:32.0690] exactly once, yes [20:34:48.0858] true that I can't think of a case where that wouldn't be so [20:35:03.0850] * true that I can't think of a case where that wouldn't be so, offhand [20:35:34.0432] ljharb: Richard Gibson: I mean, we could just merge it literally now if you two are okay with it šŸ˜„ [20:35:42.0088] go for it :-) [20:36:36.0831] Not supporting trailing zeros is the only blocker for a digit string representation of a number to be able to fully represent a numeric value together with a precision. Effectively we're trying to fix a small overlooked formatting bug here. [20:36:51.0702] I'd like to give it one more look, but let's set a timeout for the end of this meeting [20:38:34.0427] oh god, who did this? [20:39:17.0134] (oh also, belated, for Joint Iteration, https://npmjs.com/es-iterator-helpers also implements it in quasi-spec text and it passes all tests) [20:39:28.0819] no snitching in plenary [20:40:11.0309] you should mention that in the test262 PR [20:40:41.0445] yes please do, I find that helpful at least [20:47:44.0277] certainly Guy's concerns would not affect Stage 3, they would be Stage 2.7 [20:48:12.0538] I think he's maybe just not familiar with our process [20:49:16.0091] if anything, they sound more like concerns for which we'd consider reverting to Stage 1 to me [20:56:04.0453] the proposal is moving way from the thing on the screen [20:56:10.0925] TIL "barrel file" [20:56:32.0677] iow I am confused by the observation that barrel files are bad for performance, given that the point of this proposal is, now they would not be bad for performance? [20:57:12.0555] if your problem with barrel files is that they have bad performance, making them not have bad performance seems like... it solves the problem? [20:57:24.0766] only if they were all created with defers all the way down [20:57:33.0030] which i think is a pretty big presumption [20:58:02.0289] iow, someone who's that vigilant would in theory be avoiding barrel files in the first place. [21:02:02.0636] Barrel files are good for DX, bad for perf. Let's fix perf [21:07:34.0385] i don't agree they're good for DX [21:07:56.0041] i mean people using them in spite of the performance issues kind of proves the dx, no? [21:08:54.0744] Why do we have two @erights Mark Miller (Agoric) MMs on the Zoom call? [21:09:06.0520] Second that. We can argue all the way about them, being devilish, fact is they are used pretty often. [21:10:12.0467] he likes to join via phone as well [21:11:25.0374] eemeli: I think that has to do with space time. [21:13:07.0783] ... and not e.g. with "them, being devilish"? [21:14:11.0465] devilish referred to barrels and space time to two marks. [21:20:47.0580] agreed with @bakkot:matrix.org, in a vacuum we would treat it as if undefined was passed, not throw [21:21:12.0552] so diverging just to do the not-ideal thing seems not good [21:21:25.0647] I too agree [21:21:27.0086] if we are branching on presence anyway I guess I don't really care about throw vs no-op [21:21:41.0869] it could also mean they're an attractive nuisance. [21:22:32.0285] I thought most IsObject check for receiver was because some later operation was relying on looking up slots or similar on an object [21:22:49.0272] * I thought most IsObject check for receiver were because some later steps are relying on looking up slots or similar on an object [21:25:15.0877] indeed [21:26:11.0031] idk what this means [21:28:14.0586] it means they're something people _think_ they want but has subtle or unknown consequences they aren't aware of but wouldn't like [21:28:30.0497] iow, "choice" shouldn't ever be conflated with "informed choice" [21:28:36.0628] wait wtf there's slides now? [21:29:15.0797] not on the agenda there's not [21:29:58.0939] ```js { let bar = foo.bar; if (bar) { ... } } ``` [21:30:21.0803] but those consequences are not to the developer, they're to the user. [21:30:31.0889] yes I literally do that because I hate having my bindings visible outside where they should be used [21:30:32.0063] I wonder if V8 implemented during-function GC… [21:30:37.0547] * ```js { let bar = foo1.bar; if (bar) { ... } } { let bar = foo2.bar; if (bar) { ... } } ``` [21:30:52.0468] It seems Decl in cond proposal doesn't change anything compare to the version 5 years ago? [21:30:59.0017] depends on the function [21:30:59.0377] which is *worse* because in the priority of constituencies, users rank higher :-) also because the dev is even less aware of the harm they cause [21:31:20.0611] sure, i'm just clarifying that its still good DX, even if the UX is bad [21:31:50.0602] (and ideally, DX and UX should be aligned, but obviously that is not always the case) [21:33:18.0359] fair clarification [21:33:33.0861] i'd stretch to say that good DX that leads to bad UX is itself bad DX, because it begets angry users later [21:35:33.0383] But we can make good DX also good UX [21:35:54.0920] i am absolutely shocked that anyone would want them to bind in other branches [21:37:02.0650] snek: I think this presentation didn't really cover all the contours. it's relevant that the proposal also includes an expression form: ``` if (let x = foo; condition(x)) { } else { } ``` [21:37:15.0908] there's a lot more reason for `x` to be visible in the `else` here [21:37:19.0328] that said I still think it should not [21:37:19.0484] I have certainly wanted to access the binding in the `catch { }` block [21:37:27.0276] no that should just be declared above if statement [21:37:29.0605] I think Devin's `a && b` example is a convincing example why someone might want that [21:37:31.0382] also the fact that this is included is not at all obvious from the state of the proposal repo [21:37:32.0525] * no that should just be declared above the if statement [21:37:37.0656] what if it's a `using` [21:37:50.0556] in fact the specific ability to put `using` here is the main reason I want this proposal at all [21:38:00.0097] yeah I didn't realize the `;` addition was coming [21:38:01.0857] then wrap it in a block [21:38:07.0101] that seems way simpler to understand [21:38:10.0774] do the wrapping [21:38:13.0076] it's not trivial at all [21:38:16.0985] you want disposal before the `else` [21:38:31.0177] `let foo = maybeThrows(); try { … } catch { }` is a non-starter. [21:38:32.0404] no i mean if you want to use it in both branches [21:38:34.0831] it should be above the else [21:38:39.0811] oh! [21:38:40.0415] yeah [21:38:41.0206] agreed [21:38:42.0765] strongly [21:38:51.0672] cool [21:38:52.0282] I want `try (let foo = maybeThrows()) { … } catch { }` [21:39:07.0927] I'm fine with or without the `;` but I feel strongly about the non-exposure to `else` [21:39:27.0285] Doing `let foo; try { foo = maybeThrows(); … } catch { }` feels ikcy [21:39:30.0489] * Doing `let foo; try { foo = maybeThrows(); … } catch { }` feels icky [21:39:58.0054] * I want `try (let foo = maybeThrows()) { … } catch { console.log(foo) }` [21:40:05.0281] * Doing `let foo; try { foo = maybeThrows(); … } catch { console.log(foo) }` feels icky [21:40:13.0899] * `let foo = maybeThrows(); try { … } catch { console.log(foo) }` is a non-starter. [21:41:12.0907] The spec is only missing entering/exiting a new block scope right? [21:41:20.0918] Because right now the variables leak outside of the if/loop [21:41:27.0601] Even if they are defined in the head [21:42:14.0643] well, and like [21:42:16.0714] semantics for the if [21:42:31.0537] * semantics for the `if` [21:42:33.0477] Oh right the semicolon version [21:42:42.0114] either version [21:42:51.0911] declaration have empty completion values [21:42:57.0356] I agree with bakkot , for `if (decl; cond)` there are too many use cases require decl is availabe. But if no cond, there is no use case. This is the bad smell for the design. [21:43:01.0115] None of the new forms have semantics in the spec [21:43:10.0146] ``` if (let { data, error } = ...; data) { // use data } else { // use error } ``` [21:43:35.0061] danielrosenwasser: just put the declaration above the `if` in that case [21:43:37.0146] wait what, analogous to `for`? [21:43:44.0685] this seems like a better motivation for the pattern matching proposal [21:43:48.0492] I was *very* surprised about `else` scope, but have written a good amount of code that uses it [21:43:49.0287] than trying to shove that into this [21:43:49.0477] that's actually more of a head-scratching statement to me [21:44:04.0416] * I was _very_ surprised about `else` scope, but have written a good amount of code that uses it. It's nice. [21:44:08.0247] a `for` is an initialization which runs first, then a test, which runs second. this is the same pretty much! except the init has to be a declaration, but whatever [21:44:22.0813] The point is to avoid 2-3 `data` and `error`s :D [21:44:45.0114] ... I don't understand? the obvious rewrite where you put it above doesn't have any more [21:45:02.0464] ``` let { data, error } = ...; if (data) { // use data } else { // use error } ``` [21:45:17.0402] or if you really care about scope, ``` { let { data, error } = ...; if (data) { // use data } else { // use error } } ``` [21:45:19.0878] are we talking about only have a single `;` permissible. Because if you have multiple `;` it gets confusing again compared to `for` [21:45:21.0014] And I also think if we introduce such syntax, we should not copy c++, but swift/rust instead. [21:45:29.0418] I don't understand why the two have to be at odds? [21:46:00.0513] * I don't understand why the two (pattern matching and variable-scoped `if`) have to be at odds with each other [21:46:18.0507] yes, zero or one [21:46:33.0629] i'm fine with conditional declarations and pattern matching both existing [21:46:49.0608] just no conditional declarations being visible in alternatives. i am strongly against that. [21:46:51.0413] I don't think it's fair to block this on a controversial sub-proposal of a Stage 1 proposal; even within the pattern matching space, I have _very_ mixed feelings about `is` [21:47:01.0435] this proposal is way more basic than pattern matching [21:47:29.0902] I don't like the proposal in current form, but I will offline soon. If it was asked to enter stage 2, i will vote for no. I think we should wait for pattern match proposal. [21:48:21.0003] switch head visible to bodies is fine, that block encloses the cases [21:48:23.0687] I used to not really have an opinion on visibility, but with the inclusion of `using` I now feel strongly that the `using` binding must be disposed before the `else`, which implies the binding should not be visible in the `else`. rust actually changed their behavior to make disposal happen before the `else`! https://github.com/tc39/proposal-Declarations-in-Conditionals/issues/3#issuecomment-3458395454 [21:48:39.0207] +1 Ron, I want to see the significant cross-cutting concerns fully explored before this proposal moves to Stage 2 [21:48:40.0250] rust does not like to change things but this repeatedly caused nasty bugs in production [21:49:52.0998] wasn't expecting a `switch` discussion šŸ¤” feel like ljharb would have some strong opinions [21:50:24.0355] there it is [21:51:11.0608] actually droppable braces is another argument against propagation to else [21:51:24.0629] * actually droppable braces is another argument against propagation to else, confusability-wise [21:51:41.0244] We should also add this to `with` statements. /s [21:53:15.0992] I think the curly braces is a good argument, can't come up with an example, because I do not do my if-clauses w/o curlies. Hold on! [21:53:58.0975] I find extra curly a visual nuisance, and avoid them unless really necessary [21:54:10.0247] * I find extra curly / blocks a visual nuisance, and avoid them unless really necessary [21:54:23.0345] fwiw JSC has a hard "_never_ braces for a one-line body", just so that we're clear on that being an intentional styleguide option [21:55:11.0467] is the queue advancing broken? [21:55:21.0502] i'll only grumble quietly as long as a consistent linter-enforced decision is made, but omitting braces - that's how you get [gotofail](https://www.blackduck.com/blog/understanding-apple-goto-fail-vulnerability-2.html) [21:55:36.0463] no? there's just a lot of stuff on the queue [21:56:22.0600] oh i see, olivier started with the other topic [21:56:30.0882] i got confused and thought daniel was talking [21:58:12.0936] For me it is about visual pattern recognition, whenever I see an if without curlies, I have to adjust and I do not want to that. I prefer solutions, that always workā„¢. [21:58:38.0117] it also means more diff churn when converting between 1 and 1+ statement constructs [21:58:46.0047] @devsnek:matrix.org never misses [21:58:48.0181] same reason why arrow function args always have parens in the airbnb styleguide [21:58:54.0786] * same reason why arrow function args always have parens in the airbnb styleguide, even single-arg ones [21:58:55.0068] This brings up another question, is there short-circuiting? [21:59:38.0683] dunno if Ben Lickly is in the chat, but the answer to the question is, ``` while ((match = tokenRegex.exec(input)) !== null) { // ... } ``` vs ``` while (const match = tokenRegex.exec(input)) { // ... } ``` [21:59:55.0726] I mean, what Gus said, is supposed to be the other way around... the condition must come after the declaration... [22:00:11.0233] To clear up my statement, I don't want to add free-standing blocks inside/outside other blocks that are attached to statements [22:00:27.0352] * dunno if Ben Lickly is in the chat, but the answer to the question is, ``` let match; while ((match = tokenRegex.exec(input)) !== null) { // ... } ``` vs ``` while (const match = tokenRegex.exec(input)) { // ... } ``` [22:00:45.0555] definitely dislike optional blocks, except for arrow functions [22:00:49.0465] sure, but that's an aesthetic preference that presumably is more important to you than the lexical availability of bindings? [22:01:21.0104] if it was something like a TDZ, it couldn't even be anything like a regular TDZ [22:01:22.0004] No path to stage 2 right now but that felt like a good plenary conversation? [22:01:34.0581] because you'd have to somehow undeclare the value [22:01:38.0246] Putting curly braces is bad because it increases file size, making websites slower for users [22:01:44.0835] Ashley Claymore: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#temporal_dead_zone_tdz [22:01:47.0867] The reason I dislike is because I associate blocks to control flow, and free standing blocks do not contribute to control flow (if you ignore labels) [22:02:26.0625] That makes sense. Thanks for the example [22:02:35.0334] Re tdz: I think we should be careful with new TDZ after V8's feedback a whole ago [22:02:37.0317] Ok, I did not think about the `if (...; cond)` syntax. In my mind the binding was just `false` in the `else` case. So with that I see the appeal of not having it in else.... [22:03:30.0535] but yeah, I am still worried about more TDZ [22:03:35.0270] I'm confused, the `if (...; cond)` is exactly why it's useful to have the binding in the else - as in the better diagnostics example of _why_ did the condition fail? [22:04:34.0287] Steve Hicks: maybe `if (const response = await response; response?.ok)`? [22:04:45.0750] * Steve Hicks: maybe `if (const response = await fetch(…); response?.ok)`? [22:05:32.0312] i think this motivates pattern matching, not having the binding available outside the consequent [22:06:03.0378] * Steve Hicks: maybe `if (const response = await fetch(…); response?.ok)`? ignore me, I'm tired [22:06:34.0885] Pattern matching is cool, but other languages have this feature with no pattern matching as well. There are plenty of times you want to bind a variable and check some specific condition that has nothing to do with truthiness [22:06:36.0484] better diagnostics argues for, but `using` argues against, and I think is much stronger (since for diagnostics you can of course just put the binding outside). I want to be able to write this, and have the resource be disposed before the `else`. I invite you to rewrite it assuming that the binding lives through the `else`. I can't make it pretty! ``` if (using resource = getResource(); resource.needsUpdate) { resource.update(); } else { await postMessage('no updates required'); } ``` [22:06:36.0951] I really hope the champion understands the breadth of work required to actually prepare this proposal for Stage 2. It's a lot. [22:06:48.0968] * Pattern matching is cool, but other languages have this feature independent of pattern matching. There are plenty of times you want to bind a variable and check some specific condition that has nothing to do with truthiness [22:06:54.0494] best I've got is this: ``` let neededUpdate; { using resource = getResource(); if (resource.needsUpdate) { neededUpdate = true; resource.update(); } } if (!neededUpdate) { await postMessage('no updates required'); } ``` [22:06:58.0026] * Pattern matching is cool, but other languages have this feature independent of pattern matching. There are plenty of times you want to bind a variable and check some specific condition that has nothing to do with truthiness or a type check. [22:06:58.0511] We discussed scoping awhile back in the pattern matching meetings with respect to `is` and `let` patterns. One of the problems with not having the binding be visible to an `else` has to do with inverting a condition, i.e., if you start with `if (x) A else B` and refactor to `if (!x) B else A`, you have to completely change how you write the code to bind the value [22:10:49.0524] It is a little funny that we might say "this thing can't be seen in an `else` but it's fine to see it in the `default` of a `switch`" [22:11:36.0908] I really think the argument from `using` against having the binding visible in the `else` is extremely strong, such that I would be opposed to the proposal going forward if the binding is visible in the `else`. Does anyone who thinks it should be visible in the `else` have thoughts on that specific topic? [22:11:54.0229] they're all standing in a circle talking rn [22:12:31.0218] I think I would have to do some reading on your concern there - is [this comment](https://github.com/tc39/proposal-Declarations-in-Conditionals/issues/3#issuecomment-3458395454) the right starting pint? [22:12:33.0797] * I think I would have to do some reading on your concern there - is [this comment](https://github.com/tc39/proposal-Declarations-in-Conditionals/issues/3#issuecomment-3458395454) the right starting point? [22:12:48.0556] the one above that, really, yes [22:12:55.0875] also https://github.com/tc39/proposal-Declarations-in-Conditionals/issues/12#issuecomment-3517821049 [22:13:02.0901] Or with a helper function: ``` function getResourceIfNeedsUpdate() { using stack = new DisposableStack(); const resource = stack.use(getResource()); if (resource.needsUpdate) { stack.move(); return resource; } return null; } if (using resource = getResourceIfNeedsUpdate()) { resource.update(); } else { await postMessage('no updates required'); } ``` [22:14:35.0010] Or more generalized: ``` function holdResourceIf(acquire, test) { using stack = new DisposableStack(); const resource = stack.use(acquire()); if (test(resource)) { stack.move(); return resource; } return null; } if (using resource = holdResourceIf(() => getResource(), res => res.needsUpdate)) { ... } else { ... } ``` [22:15:00.0344] I shouldn't have said TDZ, really my Q should have been: would it be a syntax error to access the binding in the else? Or are the use cases conditional-shadowing-within-true-branch [22:15:19.0916] yeah, I think those examples make it very clear why it's better for the syntax to help out here [22:15:21.0668] Ron mentioned pattern matching not supporting using - maybe this is where the two don't overlap? I assume pattern matching would allow scoping something to the entire block, so if you wanted access in both branches you could use that, and if you need `using`, you use this? [22:16:27.0949] And that generalized form is not unlike what a condition variable might do. [22:16:30.0949] i don't think its ever a syntax error to reference an undefined variable. [22:16:47.0709] * i don't think its ever a syntax error to reference an undeclared variable. it would be a reference error, unless something above the if had declared it. [22:18:40.0515] IMO if you introduced bindings in `if` they would be similar to per-iteration bindings in a `for` loop, so scoped to the `if` statement (which might be considered to include the `else` clause) [22:19:30.0621] maybe `if (var)` can be the escape hatch for people who want the variable in their else branches [22:19:34.0442] * maybe `if (var x = ...)` can be the escape hatch for people who want the variable in their else branches [22:19:37.0402] I don't think there's good use cases but personally I would not make it a syntax error; just leave it to linters. I can imagine someone wanting to write ``` let data = whatever; if (let data = updateOrNull()) { console.log('updated', data); } else { console.log('not updated', data); } ``` or something. probably they shouldn't but I don't think it's the language's place to forbid this [22:20:08.0637] It's a good point, it's a huge pain to make that resource dispose early. Definitely frustrating that the two use-cases are at odds. [22:20:50.0480] yeah but the use case when you want the binding visible is much, much easier to solve [22:20:54.0557] you just do the thing you'd do today [22:21:08.0519] whereas it's an actual significant upgrade on the use case where you want the binding not visible [22:21:37.0609] i don't understand why you would use a conditional binding but also want it to not be conditional. its not even the clearest way to write that code [22:23:40.0151] ``` let x = true; if (let x = false) {} else {log(x)} ``` [22:25:35.0661] that is some yucky code [22:26:18.0090] you can write `let i = 4; for (let i = 0; i < 10; i++) {}` [22:27:16.0584] ``` let e = 0; try { throw 1; } catch (e) { console.log(e) } finally { console.log(e) } ``` that's just how bindings work! [22:27:56.0238] sure, I am saying that it is easier to understand visually where you refer to which binding... [22:28:01.0245] Why are we _still_ doing paper attendance sheets? [22:28:04.0425] (if it exists in the else) [22:28:23.0186] Programmers are known for making computers not work [22:29:00.0434] Btw. we have a similar case in for. If the following was valid syntax: `for (let x = false; x; false) { } else { x }`, then `x` would be out of scope in the `else` case. But it is not valid syntax... [22:29:27.0906] How did I get onto the queue twice? [22:29:42.0156] twitchy fingers! [22:29:44.0649] probably request retry with no protection for that [22:29:57.0237] or - highly unlikely - a race condition in TCQ. [22:29:57.0656] I'm not that fast at typing. [22:32:24.0062] FWIW if you accidentally double-clicked the submit, it gets send twice, because there is no logic in TCQ preventing that. [22:33:17.0065] ooh [22:33:24.0555] see now that deserves a bug report [22:34:00.0183] because Ecma, that's why. do not question the Ways of the Ancients [22:34:22.0127] Oh, but I do. [22:34:29.0165] over-eager web sockets [22:34:57.0311] Samina and I are choosing our modernisation battles carefully. Neither of us cares to die on the hill of paper sign-in sheet. [22:35:24.0477] what's crazy is that the paper sheet gets mailed out to all remote attendees to sign and send back to Ecma [22:36:24.0140] and they don't even include postage [22:39:50.0739] Ugh. Never got them. [22:39:56.0537] also it helps me get accurate numbers for the social dinner [22:41:24.0938] At least one physical sheet is now filled out completely next to Shane. [22:44:55.0030] > <@olivf.o1o.ch:immer.chat> Btw. we have a similar case in for. If the following was valid syntax: `for (let x = false; x; false) { } else { x }`, then `x` would be out of scope in the `else` case. But it is not valid syntax... Since that syntax doesn't exist, it's arguable in either direction. [22:46:00.0389] https://es.discourse.group/t/proposal-for-else-also-while-else-statement/934 [22:46:12.0309] The only other statement with split syntax like this is `do...while`, but there's no variable scoping involved [22:46:24.0782] there would be with the relevant proposal, tho [22:46:55.0216] `try {} catch (e) {} finally {}` [22:47:14.0591] `try {} catch (e) {} finally {} andthen {}` [22:48:15.0962] `finallyer` [22:48:19.0223] IMO, `catch` is a bit of a weird case, and `finally` is executed in *both* branches so it's not indicative [22:48:52.0738] ``` for x in range(3): print(x) else: print('Final x = %d' % (x)) ``` [22:49:14.0429] TIL [22:49:32.0800] (I've done almost zero python dev) [22:50:16.0356] haha, as I C programmer I was expecting it to print final = 3 [22:50:26.0213] * haha, as a C programmer I was expecting it to print final = 3 [22:51:10.0547] I did not realize that was in Python [22:51:31.0260] I wasn't expecting the else to run at all. I thought `for-else` would be _for_ when the loop block never runs [22:52:09.0711] oh wow yeah [22:52:17.0469] "Do this in an infinite loop, or else if you cannot go forever do this" [22:52:20.0425] that's a broken use of a keyword if it doesn't mean that [22:53:08.0540] halt-or-else [22:53:31.0816] that would be identical to just putting it after the loop? [22:53:56.0506] yeah but it's less a utility question and more a "what does the word else mean" question [22:54:00.0211] if `using` had stuck with Java's `try`-with-resources then we might have a case. IIRC, In Java: ```java try (FileReader r = new FileReader(...)) { } catch (IOException e) { // r is not reachable } ``` But control-flow based on exceptions isn't quite the same as `if...else` [22:54:03.0456] they should've chosen a different word [22:54:16.0008] * if `using` had stuck with Java's `try`-with-resources then we might have a case. IIRC, In Java: ```java try (FileReader r = new FileReader(...)) { ... } catch (IOException e) { // r is not reachable } ``` But control-flow based on exceptions isn't quite the same as `if...else` [22:54:23.0694] namely finally [22:55:10.0161] it only runs if the loop does _not_ early exit [22:55:13.0983] it's for searching [22:55:53.0723] ah thanks. so `break` would skip the else [22:56:10.0982] ``` for x in range(3): if x == 2: break else print('not found') ``` [22:56:12.0126] yeah [22:56:19.0232] it make sense in this context and only this context [22:56:24.0486] it's a bad choice of keyword though [23:08:53.0921] should the tcq be advanced/ [23:08:59.0990] * should the tcq be advanced? [23:11:28.0759] "some files don't use UTF-8" is extra relevant at the Japan meeting [23:16:05.0326] I think we should just assume UTF-8, and let `import bytes` to get a different encoding. [23:21:26.0519] consider windows-1252 @sffc:mozilla.org [23:28:23.0090] Would it be simpler to merge the proposals at some point? [23:28:25.0353] To have a single PR [23:28:39.0696] The implementation would probably also be done at the same time [23:29:01.0328] i don't think "one PR" is of much value personally [23:29:13.0678] It's for the champions, they will conflict in half of their changes [23:29:26.0316] And they are both incredibly small, reviewing them together would not be a burden [23:29:27.0480] i'm happy to do the rebasing, nbd [23:29:31.0291] either way [23:30:57.0244] Hmm, ok, I am confused about the import text proposal I think. A string can only contain utf-8 chars right now, right? at least string literals. So what would happen if you create a string with non utf-8 chars with import text? [23:31:19.0151] no, string literals in javascript are not limited to utf8 [23:31:41.0173] String literals allow unpaired UTF-16 surrogate pairs [23:31:48.0423] But I think that's beyond the point of the discussion [23:31:55.0028] `'\xc3\x28'` is not UTF8 and is a valid JS string, eg [23:31:59.0046] * `'\xc3\x28'` is not UTF8 and is a valid JS string, eg (i believe) [23:32:31.0645] JavaScript strings are sequences of UTF-16 code units (numbers between 0 and 65535, inclusive) [23:32:39.0445] The question is: given some bytes, do we extract the charcodes out of them with UTF-8 rules, or do we allow following multiple encoding rules? [23:32:41.0099] I'm surprised more people don't think of them this way [23:32:44.0602] * The question is: given some bytes, do we extract the code units out of them with UTF-8 rules, or do we allow following multiple encoding rules? [23:33:21.0502] That's not the question though? It's just up to the host. [23:33:41.0813] https://tc39.es/ecma262/#sec-literals-string-literals [23:33:42.0782] The question was whether we want to give host guidance for these imports, no? [23:34:00.0155] "A string literal is 0 or more Unicode code points enclosed in single or double quotes. Unicode code points may also be represented by an escape sequence." [23:34:02.0357] they already have to do that for modules, no? [23:34:35.0266] the normative requirement should be exactly "construct a javascript string". how the host implements such a construction is out of scope for ecma262 itself [23:34:41.0612] the transcription quality is struggling.. not sure if that's worth stopping or just finish the rest of today? [23:34:46.0164] Let's say you have an encoding where A is 0x00, B is 0x01, ..., and you import a file that contains 0x00-0x01 that has that encoding. Is it fine if it results in the string "\u0000\u0001", even though it was meant to contain the string "AB"? [23:34:49.0577] Who is asking that question? [23:34:54.0329] That's what I understood the question to be [23:34:55.0324] Shane? [23:35:08.0948] If not, I did not understand what Shane was saying [23:35:39.0099] of course, you made your own homegrown encoding. you read it as text or bytes and interpret it yourself in that case, no? [23:35:43.0331] you and I both know literals are not the only way to construct strings [23:36:00.0349] It was for an example, assume it's some other known encoding [23:36:10.0422] To be clear, I want it to be UTF-8 only. I'm not representing my opinion [23:36:14.0158] It's what I got from the discussion [23:37:31.0027] I think the question was more like "is there something better we can do when the host uses the wrong encoding to decode the text?" and the answer is pretty easily "no", right? [23:38:52.0702] If what people are saying about JSON imports being required to be UTF-8 is true, then a JSON file that is encoded on disk as UTF-16 BE will start with a NUL byte (or perhaps a BOM), which is invalid JSON, so the error happens early. But with import text, the conformant behavior would be to convert those bytes to replacement characters, and developers won't find out that there was an encoding problem. Implicit wrong encoding problems cause errors across many generations. Everyone here has seen garbled text on websites that results from the wrong encoding being used when reading bytes from a database or data file. [23:39:37.0562] CSS imports also assume UTF-8, but CSS is much more lenient and doesn't throw an error as far as I know [23:39:58.0690] I mean `type: "css"` [23:40:10.0956] @sffc:mozilla.org that's specifically with a mix-up between UTF-16LE and UTF-16BE, but there are many other encoding mixups that will cause mojibake in your string but overall still be valid JSON [23:40:36.0569] i'm very confused about where utf-8 is coming into this conversation for type text, is it because of type json? [23:40:51.0634] that's why I said consider windows-1252 and code points between 0x80 and 0xFF above [23:41:27.0358] JSON is itself a text-based encoding. The first code point is { or [ or " or another syntax character, and it has the same encoding as the string values contained inside the JSON. This is different from binary encodings. [23:42:03.0031] But you need to first get that text from some bytes, no? [23:42:36.0713] It's bytes->text->json. You are saying "it's fine if bytes->text does the wrong thing because you are catching it at the next step", but MF pointed out that you won't always catch it at the next step [23:44:02.0466] yes and some encodings encode `{` and `[` and `"` the same as another encoding but encode `Ā£` and `Ʀ` the same [23:44:40.0572] Yeah, like Latin-1, but not UTF-16 [23:44:43.0534] so it's still valid JSON but the string data of the string that's encoded in the JSON is different because the wrong encoding was used to decode the JSON [23:45:21.0215] no, a latin-1 and UTF-16 mixup would not have this kind of behaviour [23:45:25.0998] we have been doing so well on time and have had to move a lot of topics up. the downside is at this time, the day 2 and day 3 schedules are in rough shape. we will update, but please be patient [23:45:35.0707] i feel like this conversation is being confused by the difference between abstract strings and utf8/utf16/etc strings [23:46:01.0522] wtf is an abstract string [23:46:19.0945] A UTF-8 JSON parser might not fail on JSON stored as Latin-1. It should fail on JSON stored as UTF-16 [23:46:57.0736] agreed, and? [23:47:30.0382] And, then if the JSON file is encoded as UTF-16, then the error happens early [23:47:34.0868] a windows-1252 JSON parser will accept all JSON stored as latin-1 but some of it will have strings in the result that *are different* [23:47:51.0855] its not a thing in computer memory, its the theoretical characters. like the mathematical concept of numbers vs the concrete implementation of floating point. [23:47:56.0850] meaning there are no early errors [23:47:57.0595] idk if there's a better term [23:48:06.0030] it's just as fraught as text [23:48:38.0654] USV strings, or sequences of code points (ish) [23:48:48.0865] (ps, "the iterator protocol is crazy slow" is a strong use case for Array.zip) [23:49:13.0328] compelling case for engines to actually optimise their impleentations [23:49:29.0694] sequences of infinitely large code points, i guess? its not just restricted to how many characters there are in utf32 for example [23:50:00.0903] Unicode only defines 0x110000 code points [23:50:12.0161] i wouldn't think about it in terms of computer memory [23:50:22.0323] * i wouldn't think about it in terms of computer memory or numbering characters [23:50:35.0681] so you mean... text? [23:50:59.0043] You're saying that, since Windows-1252 encodes JSON syntax characters the same as UTF-8, then import type JSON gets a late error, which is the same as what will happen with import type Text. I agree that this is a true statement [23:50:59.0886] if that's the term for it [23:51:53.0672] OMG byte offset is awful [23:52:06.0700] i'm not gonna hold my breath [23:52:14.0978] Process-wise, sffc is there any change you _maybe_ would want to see in the proposal itself, or is this about guiding the HTML integration? [23:53:32.0301] The "true statement" above doesn't address my concern, other than asserting that one of the most likely environments where there would be an error (reading text files on Windows) already has this behavior with other import types [23:54:50.0976] @sffc:mozilla.org can you state your concern? @nicolo-ribaudo:matrix.org and I were unsure about what it was [23:56:06.0228] In plenary, I made an assertion that import type text has error cases that other import types don't have. The statement about Windows-1252 reduces the number of cases where this happens, but it is still happens for encodings like UTF-16 BE. [23:56:19.0006] * In plenary, I made an assertion that import type text has late-error cases that other import types don't have. The statement about Windows-1252 reduces the number of cases where this happens, but it is still happens for encodings like UTF-16 BE. [23:58:37.0838] if something "sometimes has a problem", it means we always need to consider the problem if we want to do it right [23:59:03.0700] so given there exists at least one pair of encodings where this problem could happen, it's just as important of a problem as the text mixup [07:40:41.0895] I really do not understand the conversation above. There's no requirements that hosts even represent modules as bytes at any point. It would be perfectly valid for a host to allow importing you to do `import text from 'my sample text' as { type: 'text' }` and have that result in the text `'my sample text'`, for example. [07:41:19.0488] Some hosts do represent modules as bytes, in a variety of ways, but that's entirely out of our scope [07:41:29.0927] * I really do not understand the conversation above. There's no requirements that hosts even represent modules as bytes at any point. It would be perfectly valid for a host to allow you to do `import text from 'my sample text' as { type: 'text' }` and have that result in the text `'my sample text'`, for example. [07:42:48.0651] * I really do not understand the conversation above. There's no requirements that hosts even represent importable resources as bytes at any point. It would be perfectly valid for a host to allow you to do `import text from 'my sample text' as { type: 'text' }` and have that result in the text `'my sample text'`, for example. [07:42:55.0138] * Some hosts do represent resources as bytes, in a variety of ways, but that's entirely out of our scope [09:39:32.0917] * I really do not understand the conversation above. There's no requirements that hosts even represent importable resources as bytes at any point. It would be perfectly valid for a host to allow you to do `import text from 'my sample text' with { type: 'text' }` and have that result in the text `'my sample text'`, for example. [09:46:43.0781] More realistically, something like Graal or other cross-language interop runtimes could allow consumers to define text to be importable from JS, and these would be presumably defined in terms of strings, not bytes. Compartments could be extended to do something similar. There's just no relevant notion of "encoding" a string to be imported from the perspective of these sorts of things. It doesn't make sense for the ES spec to concern it with the subset which happen to have the host doing translation from bytes. [09:47:27.0035] I'm sure HTML will specify how bytes from the network are translated to text to be imported, because it's a host, which is the appropriate layer to define those semantics. 2025-11-19 [17:00:06.0885] And we begin day 2! [17:11:05.0305] I think array iterators not closing when you call `return` was a mistake [17:12:12.0280] i think `return` was a mistake [17:13:05.0488] the generator protocol maybe, but return is fine [17:16:30.0970] separately, i'm not actually sure when you'd want to close the database connection - in most apps i've worked in, the database stays open and the connection is shared/pooled, and times out eventually [17:33:20.0602] Michael Ficarra: Sorry, accidentally deleted your topic while clearing the +1s [17:33:30.0752] these 1 or 2 or 2.7 presentations are a pretty amusing modern TC39 phenomenon [17:35:03.0850] that and conditional consensus [17:35:17.0941] its nice we have ways to speed things up though [17:35:28.0462] conditional consensus is good efficiency [17:37:05.0789] @bakkot:matrix.org Can you link your async iterator slides when you’re done [17:38:28.0996] Dumb question: Where is CreateAsyncIteratorFromClosure defined? (re: async interator helpers-- it links to the main spec where I can't find it) [17:39:56.0646] @mgaudet:mozilla.org https://github.com/tc39/ecma262/pull/3628 [17:40:47.0896] thanks :) [17:44:15.0644] What happens if you get an infinite loop inside a spec function? Is there any defined behavior? [17:45:38.0058] I guess the algorithm would just never terminate until the host process does [17:46:22.0979] i don't think any spec function current or proposed lets you get into a true infinite loop, they all dispatch on user code [17:46:55.0166] * i don't think any spec function current or proposed lets you get into a true infinite loop, they all predicate on user code [17:51:30.0069] sorry the async iterators item was so incoherent, I'd meant to do prep this weekend but I was/am down with some sort of horrible virus and am not able to think clearly enough for reasoning about concurrency code [17:51:53.0723] No special casing for infinite loops; the spec technically just says you have to keep doing it forever [17:52:03.0160] this is part of its general refusal to admit any resource constraints [17:52:07.0014] maybe, but not if we introduce a built-in infinite iterator [18:03:19.0015] forgive me for my naiivety (or for the lack of knowing the proper spelling), but composites are tought to be immutable, aren't they? [18:03:48.0170] Yes [18:03:50.0957] Shallowly [18:04:09.0848] Shallowly? [18:04:22.0673] They can contain mutable stuff [18:04:25.0776] is implementation concern the only factor for interned vs unique? or are there other constraints? [18:04:27.0069] c1.wallet.amount is not immutable? [18:04:33.0249] correct [18:04:36.0331] * `c1.wallet.amount` is not immutable? [18:04:51.0889] You can make wallet a composite too [18:05:27.0023] can but shouldn't, wallets have identity [18:05:36.0503] my wallet is not your wallet just because we both have no money [18:05:59.0863] @keith_miller:matrix.org Is spec convienence causing real slowdowns for TAs? [18:07:02.0320] so `let c1 = Composite({wallet: amount: 20}); let c2 = Composite({wallet: amount: 20}); c1 === c2; // true c1.wallet.amount+=20; c1 === c2 // ?? ` [18:07:25.0289] i would hope that composites are never mutable [18:07:28.0772] in either case [18:07:33.0260] No, those two wallets are different objects, so the composites are different [18:07:36.0007] You need nested composites, right? [18:07:38.0167] * so ``` let c1 = Composite({wallet: amount: 20}); let c2 = Composite({wallet: amount: 20}); c1 === c2; // true c1.wallet.amount+=20; c1 === c2 // ?? ``` [18:07:59.0060] But these would be the same: ``` let wallet = Composite({ amount: 20 }); let c1 = Composite({ wallet }); let c2 = Composite({ wallet }); ``` [18:08:05.0991] * But these would be the same: ``` let wallet =({ amount: 20 }); let c1 = Composite({ wallet }); let c2 = Composite({ wallet }); ``` [18:08:09.0414] The alternative is `wallet = { amount: 20 }; c1 = Composite({ `… Nicolo beat me to it. [18:08:23.0104] * But these would be the same: ``` let wallet = { amount: 20 }; let c1 = Composite({ wallet }); let c2 = Composite({ wallet }); ``` [18:12:11.0659] Yeah, 100% [18:12:22.0238] Mathieu Hofman: We also have current _custom Iterability_ with `Symbol.iterator`. [18:12:22.0939] please do not look at the current spec, it means nothing [18:12:24.0510] I should remove it [18:12:38.0595] @olivf.o1o.ch:immer.chat Does V8 have this same problem? [18:12:38.0871] In particular because you have to do n shape checks for each of the different views [18:12:59.0092] Should we be splitting the methods onto the sepcific TA subtype classes? [18:13:01.0315] That is ok-ish. The place it shows up in syntax (array spread) was a mistake [18:13:44.0628] Sometimes it will get inlined enough that we can prove only one shape shows up but there's many examples I've seen where that doesn't happen [18:14:34.0186] my memory of v8 is that it generally does a switch over different object kinds. i guess that could be compiled to a bunch of if/else branches but hopefully it does better than [18:14:39.0613] * my memory of v8 is that it generally does a switch over different object kinds. i guess that could be compiled to a bunch of if/else branches but hopefully it does better than that [18:15:12.0352] which is certainly still some overhead, but its not a function of the number of things you're switching over [18:15:37.0047] Mathieu Hofman: `Array.prototype[Symbol.iterator] = function* () { yield 2; yield 3; }` [18:15:45.0211] The problem is that you also need to make the index access polymorphic [18:15:58.0442] So it's not just a check you're in bounds and load [18:16:13.0541] It's a switch over the element size then pick the right load for the active size [18:16:24.0872] yeah it remains polymorphic until it can be found to be exactly 1 kind [18:16:49.0387] Right but that wouldn't be a problem if each of the views had their own copy of the various methods [18:17:35.0801] Mathieu Hofman: What I am trying to say, and I am leaning towards some, what I think Ron said, custom equality is not a bad thing per sĆØ. We already have so many things in the language, that are powerful. [18:17:38.0873] Let’s fix that. Doing something for convenience in the spec is much less important that actual impl difficulties. [18:18:01.0386] its definitely web reality at this point [18:18:02.0863] There's some compatibility risk although I don't know how high it is in practice [18:18:32.0867] i've seen code in the wild using TypedArray.prototype.foo.call [18:18:53.0340] actually i guess that doesn't actually preclude adding more methods [18:19:04.0110] Maybe you could just shadow the current one [18:19:05.0199] * actually i guess that doesn't actually preclude adding more methods on the subclasses [18:19:19.0585] It would be weird but I doubt anyone would really know [18:20:03.0225] we did a similar change moving around where some error properties were located in webkit and chrome and no one noticed [18:20:16.0293] That's just prototype pollution. Which is a much more general problem. But yeah you could have an array instance with an shadowed Symbol.iterator that does something weird, and I don't like that array spread would be affected by that. [18:21:29.0626] I think it is not weird to get custom behavior when spreading an object which happens to be IsArray but which has a custom `Symbol.iterator` [18:21:58.0076] as to the Array prototype Symbol.iterator pollution problem, I have a proposal for fixing that! [18:22:19.0247] ah actually it was the opposite direction https://github.com/WebKit/WebKit/commit/96efcf1f1c011efd5946d053272581e0a3d6c3b2 (my only webkit commit šŸ˜„) [18:35:35.0208] What exactly is the spec convenience we are talking about? That they all share a common proto? [18:35:42.0722] Looks like, _native equality_ comes quite at some cost, of those _interned objects_ not being so _native_ anymore... [18:39:03.0574] Yah, and the methods are defined on the common proto [18:40:00.0351] Though apparently index access is also slower than it should be [18:43:44.0648] Would this be a first for the language? Is there any object, that is specially handled somewhere, somehow, besides being an object, I mean apart from `null`? [18:43:47.0103] It's probably not our main worry for TA... But in principle all for not doing convenience in the spec if it makes implementation harder. [18:46:24.0613] also worth mentioning that a lot of TA baggage comes from khronos :P [18:46:41.0338] * also worth mentioning that a lot of TA baggage comes from khronos, not necessarily people making convenient spec decisions :P [18:48:41.0342] `document.all` [18:49:06.0689] khronos? [18:49:46.0648] > "Khronos typed arrays" refers to the JavaScript Typed Arrays specification, which was originally developed under the Khronos Group for use in its graphics APIs like WebGL (google ai summary) [18:50:20.0258] yes they were developed for webgl and later merged into ecma262 [18:50:45.0597] that's the origin of all the detachedness f-ery [18:51:08.0187] ljharb: In what context? This is a DOM API. [18:52:14.0000] https://tc39.es/ecma262/multipage/additional-ecmascript-features-for-web-browsers.html#sec-IsHTMLDDA-internal-slot [18:52:28.0207] ā€œIs HTML Document Dot All" [18:52:47.0122] In the case ljharb describes, where developers know about weirdness or already have something wrong, throwing seems better? [18:53:07.0883] throw as early as possible [18:53:08.0357] Like I cannot imagine wanting to leak here, on purpose [18:53:25.0636] If someone doesn't know about this they should learn by the language telling them [18:53:51.0643] Not by mysterious leaks [18:53:54.0232] i mean an alternative would just be, require composites to have at least 1 object [18:54:03.0957] That is also terrible [18:54:07.0761] why? [18:54:17.0964] because it breaks them [18:54:29.0777] no existing code uses composites, how does that break anything [18:54:30.0907] Because you want to be able to use them for, like, pairs of numbers [18:54:33.0217] if you want a composite of primitive types you then need to keep around some special identity object to put in them [18:54:39.0861] Coordinates in a map, eg [18:54:58.0266] make one symbol and stick it in every composite [18:55:31.0744] That is so bad [18:55:44.0215] I find waldemar argument convincing. If we have _prior art_ of handling something specifically (although I think the `document.all` to be very _exotic_ (hihi)), then I'd rather prefer a _fail-fast_ approach, then having to accept memory leaks. [18:55:53.0504] imo it's far less bad than making some objects not be weakable [18:56:01.0666] The benefit of keeping the consistency for weak maps is so, so far from being with the cost of having to do that [18:56:32.0147] IsHTMLDDA is like, one of the most horrifying things in the web platform, to be certain [18:56:34.0431] As you already pointed out, weak maps are super niche! [18:56:34.0566] to me this all seems to lead back to "they need to be primitives or they shouldn't exist in the language" [18:56:53.0170] * The benefit of keeping the consistency for weak maps is so, so far from being worth the cost of having to do that [18:56:54.0161] * document.all is like, one of the most horrifying things in the web platform, to be certain; that's why [[IsHTMLDDA]] is a sort of resentment-coded name [18:57:20.0219] we shouldn't commit minor crimes just because the thing we want to add shouldn't be an object but is forced to be one [18:57:57.0540] Ok that is a position you could have, but at that point this question does not matter [18:58:03.0732] i don't find weakmaps to be the fundamental primitive by which i decide what a value is. rather weakmap is a somewhat strange api that exposes the reality of values. [18:58:09.0687] * i don't find weakmaps to be the fundamental primitive by which i decide what a value is. rather weakmap is a somewhat strange api /becausae/ it exposes the reality of values. [18:58:12.0277] We are talking about what happens assuming that isn't the world we're in [18:58:42.0597] I have a feeling, that the discussion is very academic. What would be a real-world library using WeakSets that would be easily affected by this? [18:58:48.0398] * i don't find weakmaps to be the fundamental primitive by which i decide what a value is. rather weakmap is a somewhat strange api /because/ it exposes the reality of values. [18:59:13.0838] also what would be a real-world application where this would be the biggest memory leak in the app [18:59:14.0517] kinda feel sorry for Yusuke's queue item getting shoved to the bottom [18:59:18.0284] fwiw most use of weak apis do not deal with arbitrary values [18:59:28.0308] * fwiw most use of weak apis do not deal with arbitrary values, they are almost always contained within a single layer of an application [18:59:33.0609] * fwiw most use of weak apis do not deal with arbitrary values, they are almost always contained within a single layer of a codebase [18:59:43.0473] why is Yusuke's topic kept pushing down the queue? [19:00:41.0633] * why is Yusuke's topic kept pushing down the queue? feel like new topics are added before Yusuke's [19:00:53.0411] Next time we talk about this I vote implementations get priority [19:01:22.0684] We should really not add objects that cannot be collected. Websites running out of memory is really a terrible issue to debug for all parties involved. [19:01:29.0317] I care a lot more about what is implementable than about our design opinions unconstrained by implementation reality [19:07:40.0496] it is easy to imagine, for example, something which is serializing values to be passed to and from a worker, and uses a WeakMap to cache the serialization, with the serializations happening very frequently (it's a common pattern when splitting some computations to be done off the main thread, for example), and then it starts passing Composites some of the time, and now it is leaking a lot [19:08:11.0003] that is an unusually _easy_ example of a leak to track down, and is also very much a thing which would happen with totally normal use of WeakMaps [19:08:29.0061] throwing is much, much better here, so that the developer learns that actually WeakMaps do not work for Composites. [19:41:36.0343] Congratulations to eemeli and Ashley Claymore for being the only speakers yesterday—including myself—who made sure the appropriate info was recorded in the notes. [19:43:52.0368] bakkot, ryzokuken , ptomato , Mikhail Barash , FYT, nicolo-ribaudo , Richard Gibson , dminor , Michael Ficarra , ljharb , and James M Snell : here's what's missing https://kdrive.infomaniak.com/app/share/1777368/c4d6dca3-6847-4674-bf1d-87d2d0370871 [19:45:58.0760] fwiw speakers generally aren't the ones who add the link to the slides, I don't typically check for that after having done my presentation [19:46:04.0405] (usually note takers do) [19:46:19.0010] Yeah the notes are in _really_ rough shape this meeting. [19:46:36.0645] anyway added slides link to editor update item [19:47:40.0087] sometimes an agenda item was added without a link to slides. In this case, note takers are not able to add the link for the speakers. Please add the link after done the presentation [19:48:04.0261] * sometimes an agenda item was added without a link to slides. In this case, note takers are not able to add the link for the speakers in the notes. Please add the link after done the presentation [19:54:06.0436] what on earth is kdrive, i was so confused when i wasn't logged in to google sheets and then i realized it wasn't sheets [20:04:45.0801] it jumps to labels: https://github.com/v8/v8/blob/638e32793f854790284bf613eca204550e1c8e56/src/builtins/builtins-collections-gen.cc#L211-L215 [20:06:19.0207] that's just an if/else though. i was referring to these more: https://github.com/v8/v8/blob/638e32793f854790284bf613eca204550e1c8e56/src/builtins/builtins-typed-array-gen.cc#L546-L601 [20:06:39.0687] One motivation for them to be objects is to allow them to contain mutable objects. That is not acceptable as primitives [20:07:52.0078] that leaks in a worse and more subtle way. Which is why I don't want the answer to be: every composite must contain something non-forgable [20:08:27.0687] Membrane style libraries that keep an association from any object to another object they created. We also have a classification library where we'll check the shape of a deeply frozen object and remember the classification. [20:08:41.0937] * that's just a single branch though. i was referring to these more: https://github.com/v8/v8/blob/638e32793f854790284bf613eca204550e1c8e56/src/builtins/builtins-typed-array-gen.cc#L546-L601 [20:09:53.0238] I requested during my presentation that we keep the conversation to the slides, and not extend the conversation to a wider conversation. I would rather do that in a separate meeting that specifically talks about that - with prepared slides to reference. [20:12:08.0479] it should still be called Semaphore šŸ’¢ [20:13:05.0258] it seems like Governor would be a confusingly disconnected name if it's located right on globalThis but not sure whether that's the intent [20:14:10.0642] I think `Semaphore` is the right name, but only if its API is usable both for async coordination and thread coordination (with shared structs), which is certainly feasible. [20:20:58.0944] I _think_ the only thing necessary to make it work for thread coordination is for it to be structured-cloneable? [20:21:11.0570] with the internal state not being shared not cloned, obviously [20:21:24.0776] I guess the spec would require some atomics stuff, probably [20:21:43.0270] No, it wouldn't be structured clonable, it would be shared (just like Mutex, Condition) [20:21:58.0846] Structured cloneable isn't shareable [20:24:24.0102] Ideally it would be the same kind of object as we want Mutex to be (shared with a per-realm prototype). [20:24:42.0727] structured cloneable includes shared values [20:25:21.0912] Structured clone requires postmessage. Shareable only requires assignment [20:25:59.0478] You can't assign a structured clonable object to a property on a shared struct, only primitive and shareable values [20:26:29.0432] oh you are referring to a new category of value based on shared struct ok [20:26:33.0803] Yes. [20:27:03.0417] sorry, I meant prior to shared structs existing [20:27:04.0685] You could make it structure clonable, and when we have shared struct redefine is as a shared object, the distinction is not observable without shared structs anyway [20:27:08.0608] Mutex and Condition both fall under this category and are essentially shared structs. [20:27:12.0469] we need inter-thread coordination even without shared structs [20:27:24.0906] and this proposal will probably go forward before that one [20:27:32.0378] oh, I see "resource governor" is a SQL thing, so that must be the origin of this terminology? [20:28:08.0117] IMO we shouldn't make it structured clonable, we should make it frozen and specially handled in postMessage. [20:28:10.0624] fwiw structured cloneable is a superset of basically everything, except host resources that explicitly can't support it [20:28:16.0738] That would allow us to hedge [20:28:58.0859] The difference is that something structured clonable will create a *new* instance in another worker thread. A shared thing is the *same* instance in another thread. [20:29:53.0039] https://github.com/v8/v8/blob/638e32793f854790284bf613eca204550e1c8e56/src/builtins/builtins-collections-gen.cc#L1887-L1898 has more branches - haven't looked at exactly what this compiles to - if it's a jump table [20:29:54.0029] is SharedArrayBuffer a sharable value? [20:30:14.0017] No [20:30:23.0962] Unfortunately [20:30:27.0862] SharedArrayBuffer is cloned, i.e. posting it back and forth doesn't preserve equality, but it points to a shared internal thing [20:30:47.0754] well then we can make up whatever rules we want in the structured clone algo for "shared" values [20:31:01.0513] but yeah i see your point [20:32:33.0609] Also, Shared Structs is already at Stage 2. Its delays have been mostly been as a result of both champions having major job changes in the past few months. [20:33:02.0025] Again I maintain that having an object being sharable over postMessage doesn't prevent it from also becoming directly a shared object [20:33:46.0588] I'm hoping to dedicate more time to getting it to Stage 2.7 in the coming year, though ideally I would like someone from V8 to take on @syg's co-champion role as he's indicated he is unable to participate regularly going forward. [20:33:49.0619] (except maybe for all the exotic SAB stuff) [20:34:33.0984] rbuckton: you might want to chat with Olivier Flückiger [20:35:54.0151] Minor point: The audio coming from the room is very quiet compared to those joining remotely, so I either can barely hear the room or my speakers are blown out by remote attendees depending on who I adjust the audio for. [20:36:40.0792] ... huh, audio's fine for me [20:37:03.0696] The issue with structured clone is that a value going from thread A to thread B and back to thread A will not produce the same instance. [20:37:20.0809] Seems fine? [20:37:29.0075] I don't actually see a reason why that would matter for this. [20:37:33.0052] That isn't what happens for shared structs. [20:37:37.0989] ... OK? [20:37:47.0591] So if you change it from being cloneable to shareable, that's an observable change [20:37:50.0700] i don't particularly care what structured clone does as long as i get some sort of native shared state out of it, like SAB [20:38:02.0541] New topic: how is the quality of the original transcription for the notes today? We had quality drop-off at 16:15 yesterday. [20:38:14.0717] how ? [20:38:44.0048] doing fine so far [20:39:45.0648] Correct me if I'm wrong, but you can't currently rely on reference equality for something like SAB bouncing between two threads, can you? \ [20:39:47.0930] * Correct me if I'm wrong, but you can't currently rely on reference equality for something like SAB bouncing between two threads, can you? [20:39:52.0998] you can not [20:40:05.0684] and i don't care about it maintaining reference equality [20:40:08.0857] You can rely on reference equality for this case with Shared Structs [20:40:21.0006] i care about it for shared structs, sure [20:40:48.0547] I care about something like `Semaphore` behaving like a shared struct, so maintaining reference equality. [20:41:23.0917] If it starts out behaving like SAB, we have to be ok with changing that behavior later. [20:41:46.0405] yeah i have no strong opinion over whether it behaves like a shared struct or not [20:42:11.0854] either way it can be shared between threads somehow [20:42:15.0958] that's good enough for me [20:42:33.0417] I think we can work out a solution that hedges towards availability of shared structs. [20:42:43.0835] right but if you admit there can be multiple objects identities that are back by the same internal thing, all these objects could be shared, it's just you cannot rely on identity to differentiate them, which I don't think is a requirement? [20:42:52.0554] * right but if you admit there can be multiple objects identities that are backed by the same internal thing, all these objects could be shared, it's just you cannot rely on identity to differentiate them, which I don't think is a requirement? [20:43:23.0472] I think you need to be able to rely on identity. [20:43:34.0465] what's the use case? [20:43:38.0570] We can't do SAB because it has quirks like this. [20:43:56.0341] sorry, who's talking? for the notes [20:44:05.0045] Oli [20:44:10.0349] bakkot: +1 on everything there with AbortSignal... if you want some help on getting that proposal going in WHATWG, I'm more than happy to help [20:44:19.0042] Not having `Semaphore` behave differently than `Mutex` when writing code. It's a major quirk that you would run into regularly. [20:44:36.0445] note, thanks, will probably take you up on that [20:45:35.0612] IMO, with structs at Stage 2 we should renew the effort to get that proposal to Stage 2.7 and perhaps we won't run into a timing issue. [20:45:49.0594] I'm missing the context around the can of worms / current issues with the state of AbortSignal, is there anything good I can read to get up to speed? [20:46:14.0889] Or we ship this proposal without `CountingGovernor` since it can be implemented in userland until such time as both proposals have hit stage 4. [20:46:53.0591] there's a bunch of things, some of it here: https://matrixlogs.bakkot.com/WHATWG/2025-09-25#L18 [20:47:04.0597] I can discuss some of my concerns at length after the plenary, if you'd like. [20:47:10.0294] just negate all of those bullets and that's how it currently works [20:47:17.0222] Is it just me or do people have wildly different mic volumes today? [20:47:26.0081] that was blastingly loud, yeah [20:47:33.0892] not just you [20:47:54.0784] rbuckton: I understand how identity preservations is important for actors, but these seem like very specialized tools purely meant to implement low level synchronization, and I fail to understand the use case where identity preservation matters here. I do understand it may be beneficial to in the future share these tools over existing shared object instead of postMessage [20:47:55.0486] yeah, but a lot of the presenters have had extremely low mics today [20:47:58.0118] bakkot: How is your audio OK? I can barely hear michael with my audio set to a level where Steve Hick's audio doesn't make my ears bleed. [20:48:14.0704] maybe my computer or browser is doing some equalization? idk [20:48:16.0580] can you adjust audio per-person? [20:48:25.0243] Not that I can find [20:49:20.0093] I think there's a fair number of folks potentially interested in this discussion. Maybe organizing a call would be worthwhile? [20:50:59.0299] bakkot: I'm interested in the abort controller stuff [20:51:20.0953] (I'm the original author of the abort controller spec. pls don't hate me) [20:51:25.0900] Me too [20:52:19.0567] I don't hate you, I just wish you'd given userland the nice behavior that the web platform gets, is all [20:52:32.0125] users deserve nice things too [20:52:36.0204] Kris Kowal has opinions too [20:53:06.0405] bakkot: is the behaviour gap documented anywhere? [20:53:28.0422] I just wish AbortSignal wasn't an EventTarget. [20:53:46.0713] But I also use it on the web all the time and thanks Jake Archibald for adding it! [20:53:50.0765] lots of random griping on the web, but the best place I've got to hand is https://matrixlogs.bakkot.com/WHATWG/2025-09-25#L18 [20:54:17.0106] specifically, for the web, you have these things: - someone manually doing a dispatchEvent on the signal won't trigger your callback - another listener doing stopImmediatePropagation won't prevent your callback from being triggered - the callback is automatically released once the signal is aborted - adding a callback after the signal is already aborted won't do anything (and in particular won't hold a reference to your callback) users consumers of AbortSignal don't get any of those [20:54:31.0161] Grab the pitchforks everyone... we know who to chase down [20:54:31.0988] I'll admit I've had a number of gripes (some vocal, some not so) with the `AbortController` API, but my biggest frustration was that it felt very rushed out while I was in the middle of trying to get cancellation into the core language. [20:54:41.0283] * specifically, for abort listeners added from web machinery instead of userland, you have these things: - someone manually doing a dispatchEvent on the signal won't trigger your callback - another listener doing stopImmediatePropagation won't prevent your callback from being triggered - the callback is automatically released once the signal is aborted - adding a callback after the signal is already aborted won't do anything (and in particular won't hold a reference to your callback) users consumers of AbortSignal don't get any of those [20:55:01.0038] I'll put together a doodle poll early next week and post it to get a call set up [20:55:03.0523] if we add EventTarget and DOMException to 262 this becomes a very simple problem to solve [20:55:09.0885] what i wish is that abortsignal hadn't been shipped before notifying TC39 that it was happening :-/ [20:55:24.0113] https://en.wikipedia.org/wiki/Governor_(device) [20:55:39.0759] whoa [20:55:48.0307] That's precisely one of my gripes. [20:56:41.0763] rbuckton: interesting. I was told at the time that cancellation primitives has been abandoned in TC39. Hm. [20:56:51.0871] I refuse to write a standard library function which has as one if its steps "and then call `.addEventListener('abort', fn)`" [20:57:01.0008] even DOM consumers of AbortSignal don't stoop to that [20:57:22.0943] * I refuse to write a standard library function which has as one of its steps "and then call `.addEventListener('abort', fn)`" [20:57:26.0475] Certainly not. See https://github.com/tc39/proposal-cancellation [20:58:06.0905] I feel like `keyCount` reads less awkwardly than `keysLength`. [20:59:00.0481] that's a reasonable thing to bikeshed within stage 2 :-) [20:59:02.0976] or generally xsLength -> xCount [20:59:24.0072] sign me up for the abort call plz šŸ˜„ [20:59:37.0898] Promise cancellation as a 3rd state was abandoned, not cancellation [21:00:35.0179] do web-machinery things also remove their listener once their task has finished? A thing I've come across is: long lived abortSignal with lots of shortLived user tasks and it leaks listeners [21:00:42.0714] yes [21:00:53.0850] I think `getOwnPropertyNameCount` is actually worse šŸ˜… [21:00:54.0984] My major concerns with AbortController were: - Dependence on DOM-specific eventing/exceptions. - DOM APIs privileged over user code - Poor separation of concerns (user listeners for `abort` can be fooled by `.dispatchEvent`) - No single use `abort` for user code (again, due to `dispatchEvent`) - No cancellation graphs (somewhat addressed over the years, but not well), so memory leaks abound [21:00:58.0611] see https://dom.spec.whatwg.org/#run-the-abort-steps [21:01:04.0791] * My major concerns with AbortController are: - Dependence on DOM-specific eventing/exceptions. - DOM APIs privileged over user code - Poor separation of concerns (user listeners for `abort` can be fooled by `.dispatchEvent`) - No single use `abort` for user code (again, due to `dispatchEvent`) - No cancellation graphs (somewhat addressed over the years, but not well), so memory leaks abound [21:01:11.0602] I'm gonna totally lose track of everyone interested in this chat. I'll post the doodle link likely on monday and will send invites to anyone who responds [21:01:15.0859] "Empty signal’s abort algorithms." is the bit which removes existing web-machinery listeners [21:01:18.0509] bakkot: The reason AbortSignal uses events is just because that's kinda the standard on the web platform for callbacks. But given there are other benefits to avoiding events, your proposal seems reasonable [21:01:46.0720] Almost always when I find a need to call `Object.keys(...).length`, all I really want to know is whether I have an empty `{}` object, or something else. [21:01:49.0290] or, wait, I think I read your question backwards? [21:02:07.0023] I don't actually know but I don't think it's observable, because the listeners are purely internal [21:02:33.0546] Can you imagine if DOM shipped `Future` using DOM events instead of `then`? IIRC, that wasn't even on the table for `Future` before it was adopted by 262 as `Promise`. [21:02:54.0133] What is there to be gained? Is this really totally un-optimizable for implementers, if it such a common pattern? [21:03:05.0424] I kinda want abortSignal listener add to have Symbol.dispose [21:03:23.0135] TCQ doesn't let me add a reply [21:03:42.0111] see Nic's clarifying Q :) [21:03:46.0757] hey! I hoist the options bags [21:03:49.0774] yeah this completely perplexes me [21:04:08.0706] refresh? I had to re-auth recently [21:05:34.0776] static interned inline composites could be safely hoisted by tools šŸ˜Ž [21:05:44.0792] bakkot: > I don't understand why the web platform uses a completely different set of infrastructure for abortables Web specs never use events internally. [21:05:49.0979] I mean apart from a theoretical point of view, how often is this used in critical paths? [21:06:04.0383] * bakkot: > I don't understand why the web platform uses a completely different set of infrastructure for abortables Web specs never listen to events internally. [21:06:06.0526] well... but like... why [21:06:27.0709] like if it's recognized that web platform should get to use better infrastructure... why doesn't userland get to use better infrastructure? [21:06:38.0648] reply button is back! šŸŽ‰ [21:06:50.0174] My proposal originally had something like: ``` class CancelSource { constructor(...linkedTokens: CancelToken[]); token: CancelToken; cancel(): void; close(): void; } class CancelToken { static canceled: CancelToken; static none: CancelToken; subscribe(cb): CancelSubscription; // disposable get canceled(): boolean; get canBeCanceled(): boolean; } ``` [21:06:50.0667] the many many use cases that ruben and i looked over were definitely not just needing that simple a semantic [21:07:24.0873] bakkot: it's not a better vs worse thing. It's the same reason why internal methods are called rather than directly calling exposed interfaces. [21:08:08.0871] this discussion as a whole feels very like, supportive of a problem statement and not a solution, hm [21:08:25.0153] it could be using entirely internal methods and still same the same machinery, though [21:08:29.0101] keith_miller: what was that 40% metric specifically? [21:08:32.0403] so it is about counting keys, properties or symbols and wether they are enumerable or not, how about them configurable? :D [21:08:35.0345] Any idea what sort of percentage is testing the value against 0, vs. doing somethign else? [21:08:56.0519] there's no reason that AbortController needs to have a separate privileged list of web-platform things to trigger on abort, instead of just adding web-level things to the existing list of callbacks to call [21:09:00.0528] bakkot: similar to JS, if you override `globalThis.Array`, that isn't called by internal JS things that create arrays [21:09:05.0105] the vast vast majority where it's just counting care about enumerable properties and/or symbols [21:10:04.0926] Code that goes through the optimizing compiler [21:10:05.0873] I'm not asking about literally doing `.addEventListener`, just about having only a single internal list of things to trigger on abort, instead of having two lists [21:10:14.0398] the one place this does happen (which is evil) is `Array.prototype.toString` dynamically looks up `Array.prototype.join` - not the original. [21:10:17.0437] bakkot: basically, it isn't a deliberate choice to give web devs something bad and retain something good for internal use - and taking it to the WHATWG with that as an immutable assumption will get in the way of progress [21:10:30.0449] tip for newcomers: some people find it a bit rude to look ahead on the queue and make assumptions about what somebody is going to say (and pre-reply, putting words in their mouth) [21:10:38.0728] 40% of code on internal page loads or Speedometer get to optimizing tiers yeah [21:10:58.0802] * My proposal originally had something like: ``` class CancelSource { constructor(...linkedTokens: CancelToken[]); token: CancelToken; cancel(): void; close(): void; } class CancelToken { static canceled: CancelToken; static none: CancelToken; get canceled(): boolean; get canBeCanceled(): boolean; get reason(): unknown; subscribe(cb): CancelSubscription; // disposable throwIfCanceled(): void; } ``` [21:11:23.0746] bakkot: otherwise I understand your proposal and it seems reasonable. I'm just giving context for why things were designed as they were [21:11:31.0513] sorry, to be clear I didn't think it was deliberately good for web and bad for users! just that the actual effect of splitting the machinery is that it has had the consequence that the user things are stuck with something with a bunch of bad properties which the web gets to avoid [21:11:45.0223] yes, thank you, I appreciate the context [21:12:01.0399] Infomaniak, swiss hosting [21:16:44.0564] I ended up implementing something like this (`@esfx/canceltoken`, docs here: https://esfx.js.org/esfx/api/canceltoken/canceltoken.html#_esfx_canceltoken_CancelToken_class). It even theoretically works in place of `AbortSignal` on the web as it repurposes an `AbortSignal` instance with custom `[[Prototype]]`. [21:22:00.0343] chipmorningstar: https://bugzilla.mozilla.org/show_bug.cgi?id=1914502 shallowEquals in react is one of the hottest functions, and uses this pattern [21:22:17.0613] bakkot: It'd be nice to keep `throwIfAborted()`. I guess JS will need an `AbortError`. As long as it passes `err instanceof Error && err.name === 'AbortError'`, that seems fine [21:23:45.0218] Yeah chipmorningstar I am totally with you. And giving what nicolo-ribaudo said, I think we have to see real usages in the wild with actual numbers in critical paths. [21:23:51.0343] I'd also considered `source.cancel(reason)` so you could cancel with a specific reason, not just `AbortError`. [21:24:26.0043] it can also be `HostCreateAbortError()` [21:24:54.0343] rbuckton: `controller.abort()` has that too [21:25:31.0947] snek: yeah that's fine, I'd just like there to be a cross-platform way to tell an 'abort' from other things. [21:25:39.0759] Can we just have a cancellation protocol (`obj[Symbol.subscribeForCancellation](cb)`), and have web AbortSignal do that? And the web AbortSignal uses the good algorithm for it [21:25:45.0451] And then our APIs can just use that protocol [21:25:53.0594] rbuckton: https://dom.spec.whatwg.org/#dom-abortsignal-abort [21:26:20.0904] See https://github.com/tc39/proposal-cancellation/issues/22. Back in 2018 the answer ended up being "No" [21:26:37.0159] * rbuckton: https://dom.spec.whatwg.org/#dom-abortcontroller-abort [21:27:41.0356] The more time passes without a solution happening, the more people need to relax their constraint (if we gree that want some solution to happen) [21:27:43.0796] Jake Archibald: if you haven't seen it, here is the Stage 0 cancellation proposal from 2017: https://github.com/tc39/proposal-cancellation/tree/master/stage0 [21:28:00.0669] I don't think the API name (in this proposal's case) is a Stage 2 concern [21:28:07.0621] But I don't see in that issue why the answer ended up being no [21:29:11.0880] is there a reason to want this to be a symbol-named protocol instead of a string-named protocol? Because my plan was to add a string-named `whenAborted` or something to AbortSignal, which does the good algorithm, and have consumers like Governor do a call to the user-observable `.whenAborted`, which would make it de-facto a protocol [21:29:20.0447] also percent of spec text that the name occupies does not make one bit of difference [21:29:24.0597] I think symbol-named protocols are good for things where you want the protocol implemented on arbitrary objects [21:29:28.0044] like iterator [21:29:34.0079] but don't see much reason for symbols for cases like this [21:29:39.0052] I'd been working with Domenic Denicola on a solution and ended up being told later that the protocol idea was not going to be accepted and only thing WHATWG would consider would be a host hook. [21:29:40.0758] eemeli: do you know why Map & Set don't use `count`? [21:29:42.0304] * but don't see much reason for symbol-named protocols for cases like this [21:29:54.0397] That the web API already has one way to register, and it can be confusing to have two [21:29:56.0776] you think it needs to happen before stage 2? [21:30:01.0882] * you think it needs to be decidd before stage 2? [21:30:02.0917] I don't want to object but this really feels premature [21:30:03.0680] * you think it needs to be decided before stage 2? [21:30:06.0292] Unless we want every of its users to consider the event-based API to be deprecated [21:30:12.0950] * Unless we want every of its users to consider the event-based API to be basically considered to be deprecated [21:30:16.0550] @ljharb:matrix.org no I was objecting to @eemeli:mozilla.org's objection [21:30:18.0361] * Unless we want every of its users to consider the event-based API tobe deprecated [21:30:22.0145] * Unless we want every of its users to consider the event-based API to be deprecated [21:30:36.0513] uhhhh yeah that's pretty much what I'm hoping for [21:30:51.0085] Then a string-based protocol is good [21:30:54.0059] it's got a bunch of footguns so that's desirable anyway [21:31:07.0779] See https://github.com/tc39/proposal-cancellation/issues/22#issuecomment-916548469 [21:32:13.0644] It seems like the motivation there is that we have a good API on the web and we shouldn't use a second one. Kevin is now saying that it'd be good to provide a second API on the web (which would be good regardless of the ECMA-262 interop) [21:32:31.0454] oh oops I see, I mistook the conclusion. I'm definitely okay with the conclusion Jordan stated [21:33:10.0029] No; I don't find their `size`s awkward though. Is the story relevant here? [21:33:29.0784] One reason why splitting doesn't really make sense to me [21:33:57.0463] eemeli: just that it's another word the platform uses for "number of items" [21:33:59.0106] @rbuckton:matrix.org What was the proposal that prompted you to create Cancellation? [21:34:08.0297] I remember there being something that needed the ability to cancel [21:34:11.0352] I've always contended that we have a less than adequate API on the web with numerous footguns. We can possibly address the footguns, but that requires deprecating older parts of the API [21:34:39.0499] Justin Ridgewell: on the web side, a lot was driven by cancellable fetch [21:34:58.0468] `Promise` and `async function`. [21:35:29.0056] Wasn’t there something more recent than that? [21:35:39.0167] Those both predate my joining the committee [21:35:43.0834] I remember there being something [21:36:08.0714] Not really, I started working on the proposal before `async function` was finalized. [21:36:15.0794] A standard CancellationAsyncContext [21:36:25.0179] also if Observables was done in TC39 [21:36:36.0775] I think this would still count as the same API, just a different way of using it, and fwiw I think domenic agrees er https://matrixlogs.bakkot.com/WHATWG/2025-09-26#L7 [21:36:44.0067] * I think this would still count as the same API, just a different way of using it, and fwiw I think domenic agrees per https://matrixlogs.bakkot.com/WHATWG/2025-09-26#L7 [21:37:30.0891] Tbf my stated preference continues to be for `isEmpty`, but `keysLength` rubs me the wrong way because "keys length" is not grammatically correct English. [21:38:00.0640] I'd already been using cancellation in .NET for years, and had an early implementation of `Promise` for JS back in 2015. When `Promise` was proposed for JS, I wanted cancellation for async programming. [21:39:47.0472] I wanted cancellation for `new Promise(init, token)` and `Promise.prototype.then(onfulfill, onreject, token)` as a way to unregister callbacks as a more memory friendly version of `p.then(() => { token.throwIfCanceled(); ... })`. I also wanted it for dynamic `import()`. [21:40:58.0549] What held up cancellation to the point that WHATWG shipped something before we could standardize, was a number of delegates wanting cancellation to be somehow transparent, which I was strongly opposed to. [21:41:28.0202] i don't love cancellation at the promise layer specifically, I think it leads to a footgun of stopping listening when you meant to stop the actual work that is happening, but cancellation in general seems quite nice. [21:42:58.0315] I based that consideration on my experience with .NET's `new Task()` and `Task.ContinueWith()`, which both accept a cancellation token as a way to cancel work up-front and avoid memory leaks due to holding on to closures longer than necessary. [21:44:44.0795] detaching promise callbacks also seems useful [21:44:56.0955] That's the same reasoning why I think `AbortController`/`CancelSource` needs a `close()`/`[Symbol.dispose]()` that unregisters all callbacks, to avoid memory leaks from entire cancellation graphs that can no longer be canceled. [21:44:57.0217] * One reason why splitting proposals doesn't really make sense to me [21:45:08.0101] Isn’t this effectively what `fetch({ signal })` does? [21:45:44.0293] fetch's signal can actually cancel the native operation [21:45:57.0240] right. the signal should be given to the producer - not the result [21:46:06.0405] promise != task. promise = result [21:46:27.0413] * promise != task. promise == result [21:46:32.0097] a Promise is a producer of calls to its `.then` listeners [21:47:09.0092] program-counter++ is a producer of progress [21:47:27.0874] The .then callback can do actual significant work [21:47:47.0418] Ignore the names. A .NET `Task` is virtually the same as a JS `Promise`. The only difference is that a .NET `Task` can delay starting. [21:48:02.0180] that's a big difference [21:48:06.0001] In .NET, a `Task` generally represents an eventual result. [21:48:41.0996] Yes, but in the Venn diagram if Task and Promise, Task covers Promise entirely. [21:48:51.0003] an `async function` that was lazy would have been very different [21:48:51.0435] * Yes, but in the Venn diagram of Task and Promise, Task covers Promise entirely. [21:49:11.0142] I think you’re confusing promise `p1` and the callback’s returned result `p2` in `p2 = p1.then(() => work())` [21:49:20.0687] I agree that tasks have results [21:49:28.0585] my concern is when people write `fetch(url).then(cb, { signal })` instead of `fetch(url, { signal }).then(cb)` these do very different things while being very similar [21:50:11.0488] I also I think both use cases are valid [21:50:19.0277] I'm saying that even though a task can be a promise, that doesn't mean it's better. Restrictions are powerful [21:50:26.0282] @erights Mark Miller (Agoric) MM: IIRC, you had strong opinions on WeakRef and the [[KeptValues]] list. Do you have thoughts on relaxing the behavior to match JSC in https://bugs.webkit.org/show_bug.cgi?id=301334. [21:50:57.0068] Perhaps TG1 & WHATWG could take some inspiration from TG2 & W3C I18N: TG2 stage advancement requires _asking_ for a horizontal review from W3C I18NWG, but does not require _receiving_ it [21:51:18.0552] TL;DR JSC only keeps the target alive as long as there exists some WeakRef that has `deref()`ed the target this cycle is still alive [21:51:18.0843] How do I add myself to the end of the queue? [21:51:24.0273] Imagine a .NET `Task` being something like: ```js function Task(init, opts) { if (opts?.delay) { const { promise, resolve, reject } = Promise.withResolvers(); promise.start = () => init(resolve, reject); return promise; } const p = new Promise(init); p.start = () => {}; return p; } ``` [21:51:32.0638] It keeps inserting my topic before James's [21:51:57.0575] It's been doing that all day, that is *not* the normal behavior, right? [21:52:13.0066] It's now TCS instead of TCQ [21:52:34.0926] People who submit New Topic's early during the presentation are kept at the bottom and often don't get to speak [21:53:00.0147] splitting them doesn't change that all the names will have to be consistent full stop [21:54:36.0606] is this an observable difference? [21:54:46.0930] (didn't read the issue yet) [21:54:54.0686] let's chat on the break [21:56:20.0188] Only when you have two WeakRefs that point to the same target. My thinking is that's probably impossible to mentally model that two WeakRefs point to the same target correctly anyway. [21:56:56.0212] I also think (once you know the GC of a given engine) that the current behavior is a communications channel [21:57:30.0248] So we're admitting we want the other methods? The `Count` suffix for the longer Object methods don't read well to me. Advancing keys separately opens the risk it advances with Count [21:57:51.0646] * So we're admitting we want the other methods? The `Count` suffix for the longer Object methods don't read well to me. Advancing keys separately opens the risk it advances as keyCount [21:57:54.0818] it doesn't [21:58:05.0850] I am admitting no such thing [21:58:07.0937] keysX won't advance with any X that wouldn't also be palatable for all the other methods [21:58:17.0672] * keysX won't advance with any X that wouldn't also be palatable for all the other methods, that would violate the "cross-cutting concerns" part of stage 2 [21:58:28.0156] * keysX won't advance with any X that wouldn't also be palatable for all the other methods, that would violate the "cross-cutting concerns" part of stage 2 (whether we have the other methods eventually or not) [22:03:11.0482] I wrote out an example of loading JSON with ESM and non-UTF-8 encodings at https://github.com/eemeli/proposal-import-text/issues/6. It has the behavior I described yesterday: early error, triggered by syntax. I also collected some examples of prior art: https://github.com/eemeli/proposal-import-text/issues/5#issuecomment-3550911025 [22:03:42.0501] @sffc:mozilla.org I don't think that makes a difference [22:04:52.0895] there are occasions when you *won't* get an early error, even though you have the wrong encoding, so any warning you want to convey to hosts about mismanaging the encoding for text also applies to JSON because it's the exact same error [22:05:23.0151] and we don't have such a warning about JSON, and I don't think we need it [22:06:17.0364] the `encoding` option doesn't make sense here because there is no reason to assume the resource is backed by bytes from the perspective of the importing machiner [22:06:20.0259] * the `encoding` option doesn't make sense here because there is no reason to assume the resource is backed by bytes from the perspective of the importing machinery [22:06:30.0705] MIME types could include a universal `codecs` sub-parameter or similar [22:06:40.0481] that assumption is true in e.g. HTML, but whatwg is pretty dogmatic these days about interpreting any text over the wire as UTF-8 in any new APIs, so I don't think they'd be on board with allowing specifying any other encoding anyway [22:06:48.0305] Could HTML only support UTF-8, but throw if it detects somehow a non-UTF-8 encoding? [22:06:58.0098] and we could add a way to include the expect mime type [22:07:22.0045] The Content-Type header is already mime type + charset [22:07:23.0891] * and we could add a way to include the expected mime type [22:07:46.0580] that's what i meant; re-using that if possible [22:08:45.0410] Btw, the scope of the proposal in TC39 is "if an import with type:text succeeds, it must return a string". HTML doesn't actually need our proposal to do type:text, our proposal just prevents returning random stuff there [22:14:51.0725] nicolo-ribaudo: are there slides for your "Module-declarations-like proposals in other areas of the web platform" topic? it sounds interesting but I might be asleep [22:15:17.0326] I recently added them to the agenda [22:15:37.0216] oh nice, just hadn't refreshed [22:16:05.0125] It's mostly code snippets though, I was planning to just say the descriptions out lound [22:21:41.0627] https://tc39.es/proposal-object-keys-length/, thanks eemeli and james [22:24:53.0393] Spec text lgtm [22:26:18.0464] I'm gonna be real upset if this presentation doesn't mention call stack limit [22:27:53.0881] it does not [22:28:13.0750] or arguments limit [22:29:06.0579] there used to be a limit of unique `Symbol.for` calls in v8 but I think that's fixed now [22:29:35.0718] strings have a limit of 2**53 - 1 code units, but what happens when trying to exceed that is not specified: https://github.com/tc39/ecma262/issues/2623 [22:30:13.0060] and engines fail before getting to that length too right [22:30:18.0199] * and some engines fail before getting to that length too right [22:31:54.0852] all of them; it's a big limit [22:34:30.0023] i don't know how we can discuss any of these questions without a more concrete problem [22:34:31.0314] like [22:34:43.0090] basically every single expression in js can cause an oom [22:35:04.0000] what is the scope here [22:35:31.0262] i think it's less about avoiding OOMs and more about, in the presence of sufficient memory, knowing what ranges are guaranteed vs impossible vs "up to the implementation" [22:35:52.0453] what is sufficient memory [22:35:57.0039] it's an open-ended discussion [22:36:45.0693] assume infinite memory [22:36:52.0106] also assume a spherical frictionless cow [22:36:59.0241] well now we don't need any limits [22:37:25.0199] yes, I have proposed exactly that in TDZ [22:37:34.0045] IMO it would be nice to have the spec define minimum upper bounds [22:37:47.0548] otherwise how are you supposed to program this crazy machine? [22:38:06.0406] you will immediately have non-conformant impls, no? [22:38:26.0965] MIMUMUM upper bound [22:38:33.0319] * MINIMUM upper bound [22:38:34.0995] so like if a system doesn't have enough memory for that, and it can't throw a rangeerror up front, it has to just oom? [22:38:40.0218] test262 implicitly defines certain minimum limits - maybe those could be turned into spec limits to make them explicit [22:38:51.0896] having a non-orientable surface, too? [22:38:57.0846] it should never even start if it can't support the minimums [22:39:13.0966] test262 has some quite expensive tests which are skipped even on production-grade engines [22:39:51.0345] > Moddable XS has a minimum RAM requirement of approximately 6-7 KB for a basic virtual machine [22:40:06.0942] https://github.com/v8/v8/blob/37adb436086fca29284fea8b8440bcda73bbb0fb/test/test262/test262.status#L393 [22:40:34.0454] Summary of my chat Mathieu Hofman was that changing this seems not-insane so maybe we should think deeper thoughts about this [22:40:59.0531] For example, I make function calls with more than 1 argument sometimes. For some number of arguments N (N > 1), it's unsafe to do that because browsers may OOM. As a programmer, I'd like to know that my argument list length is less than N so that won't happen. [22:41:10.0471] @erights Mark Miller (Agoric) MM: I should note that one of my current background tasks is investigating exactly this change [22:42:29.0479] The function body is fine, but the name is not: It needs to unpack into something that's valid English, and "keys length" is not. [22:42:46.0867] this number depends on the current size of your stack, so, good luck with that [22:43:38.0564] fair, I guess this is a more difficult limit than some of the others [22:43:59.0050] honestly you could make N=5 there and just encourage people to write nicer code [22:44:42.0823] oh wait I'm thinking of formal params and not concrete args [22:44:43.0781] `array.push(...vals)` is nice! [22:44:52.0225] yeah, never mind [22:45:09.0794] oh yeah we should limit you to 5 formal parameters, I'm on board with that [22:45:23.0675] we have a function in our codebase which takes 13 and I feel bad every time I look at it [22:47:14.0584] I don't feel very bad about functions with excessively long parameter lists, in the same way I don't feel very bad about variables with excessively long names [22:47:32.0799] some things are just complicated and pretending otherwise just makes things worse [22:48:27.0964] Yeah, but **13** params! [22:48:44.0353] I can count to 13 [22:48:51.0673] https://en.wikipedia.org/wiki/Sorites_paradox [22:49:15.0005] How? I only have 10 fingers! [22:49:35.0664] your parents didn't teach you to count binary on your fingers? [22:50:39.0103] My dad showed me how to open a beer bottle with my eye hole basically anything. We had nothing! [22:50:55.0834] 10 fingers and 10 toes, that should get you up to base 20 [22:51:00.0047] Chrome doesn't seem to kill the whole agent. If I OOM in a web worker in chrome, only the worker crashes [22:51:11.0896] the fail fast proposal was the whole agent cluster right? [22:51:13.0963] * My dad showed me how to open a beer bottle with my eye hole basically anything. We had nothing! [22:51:21.0383] yes [22:51:28.0120] count each knuckle too [22:51:35.0064] * yes, because of SAB [22:52:22.0796] I suspect that's likely the disagreement that @erights Mark Miller (Agoric) MM was remembering [22:52:29.0124] as a guess [22:53:22.0252] might be able to say only crash the set of agents that have a SAB shared with [22:53:39.0825] crashing the main thread is the bad one [22:53:50.0800] as that's where the website is [22:53:53.0206] but I also remember something about the OS killing interfering with that [22:53:53.0800] :D [22:54:56.0693] if the main thread shares a SAB with a worker that failed, it's likely unsafe to let it continue [22:55:14.0967] yeah but as a user I prefer that to my whole tab crashing [22:55:43.0089] if the website is a random blog post, I don't want it to crash even if the analytics library has a bug [22:55:43.0777] as a user you like your applications to misbehave ? [22:55:47.0048] OOM's in V8 can be problematic. They do have a host hook to handle them but new OOM paths that crash instead of using the hook pop up a lot. In workers we have to actively watch out for these since we have thousands of isolates all in the same process... crashing hard is not really an option. [22:55:56.0987] when it's not critical, yes [22:56:04.0475] do you? the alternative might be that the JS can now read uninitialised/reclaimed memory [22:56:17.0927] some bugs in games actually lead to fun qwirks [22:56:24.0554] I like my applications to not crash more than I care about them maintaining arbitrary other invariants, yes [22:57:01.0078] there are very few webpages that I use where I would prefer a page crash over the sort of bugs likely to arise from a worker crashing, even a worker with access to a SAB [22:57:10.0868] if the web page is show your wallet balance, and the balance is incorrect rather than crashing due to worker failure, it would cause human panic I think [22:57:36.0393] it is true that there are some very few applications where a crash is preferable, but they are _very_ few [22:58:07.0922] ooh isn't that how some cultures did base 4 or 8 or something? [22:58:15.0727] server side there are way more cases where crash is absolutely preferable [22:58:48.0974] we very much advocate for a host hook. I didn't understand yusukesuzuki 's point because I would think host hooks are not affected by JS heap limits (unless they themselves decide to delegate to JS) [22:58:56.0308] often way better to just crash, throw away current state, then start fresh [22:59:19.0192] I mean you can always catch RangeError and terminate the process in node when you get it, not? [22:59:43.0647] Ah, sorry for misleading. I was mentioning to delegating to user defined logic after that. [23:00:14.0271] And those webpage cannot be simply reloaded? I mean what page hold important state that would suffer and yet can sustain corruption ? [23:00:27.0853] yeah, our host hook for OOM definitely does not defer to user code. We actually hard terminate the isolate and force a cold start fresh [23:00:28.0590] But also, if it is coming from system allocator exhausting memory, it is hard to guarantee that the handler can work safely too. [23:00:38.0120] * And those webpage cannot be simply reloaded? I mean what page hold important state that would suffer from a reload and yet can sustain corruption ? [23:01:37.0740] no because other code might catch it before it reaches the process handler [23:01:45.0640] * no because other code might catch it before it reaches the process unhandled handler [23:02:17.0831] sure, but if it catches it then it takes responsibility to correctly handle it. [23:04:05.0023] Yes, but there are, of course, cases where we just can't let the user code do that. Lots of cases where "correctly handle it" *is* a hard crash and cold start [23:04:23.0385] lib A trigger OOM and let it throw, lib B made the call to lib A and handles the thrown error. lib A is now in inconsistent state. App has no clue of what happened [23:05:54.0282] B should not have caught it if it can't ensure A stays consistent. How is that different from any other exception that is thrown by A. [23:06:33.0698] yeah B shouldn't, lots of code out there doing things it shouldn't, and inflicts pain on the rest of the app [23:06:45.0336] Unfortunately not that straightforward. some frameworks unconditionally catch in an attempt to be "helpful" [23:07:12.0546] Looks like we need uncatchable Errors in JS too. [23:07:20.0498] sure, but now you want a crash on all errors proposal? [23:08:09.0930] oh no no ... never that. just don't want an All Failures Are Catchable proposal [23:08:17.0704] we did advocate for a userland `panic()`. We are concerned about situations where invariants go out the window [23:09:01.0896] ooh interesting, I did not see this on the agenda [23:11:44.0225] I see. I still think that websites seem to be doing fine with handling range errors. [23:12:24.0382] Websites yeah, I agree that's different. I'm largely thinking about server-side cases [23:13:14.0904] web apps "think" they're doing fine, but they really have no clue. web sites could just reload [23:17:07.0046] Right, I acknowledge this in my post. With non-UTF-8 JSON imports, you get an error _sometimes_: almost always when the source encoding is utf16, and occasionally when the source encoding is latin1. However, with non-UTF-8 Text imports, you get an error _never_. Sometimes is better than never. [23:19:23.0511] why would it necessarily be an error case tho [23:20:32.0896] Sure, but some expressions are much more likely to cause an OOM than others. [23:21:15.0068] right that was my point [23:21:37.0536] that i thought the whole topic is too vague [23:22:11.0179] * shane, why would it necessarily be an error case tho? [23:23:21.0641] definitely needs to be grounded a bit more. there's lots of nuance that gets lost without more detail [23:26:01.0854] wait, we have 50 min of topic left for 35 min of day? [23:26:14.0582] * wait, we have 50 min of topic left for 30 min of day? [23:27:50.0824] Huge props to everyone who does note-taking. The transcription can be _very hard_ to follow sometimes! [23:31:28.0444] Right, I agree with this type of sentiment. Ideally, I think the spec authors should use their judgement to decide a minimum for these things (such as length of a bigint/amount). An engine _could_ throw errors for anything that would exceed the minimum and be compliant and also be able to run 99.9% of programs. But, engines are permitted to allow more than that. [23:32:49.0909] the schedule says we have 15min overflow [23:34:35.0251] i'm still just like... you can make usable bigints in v8 that are larger than the entire minimum heap size for xs. so do we set the minimum really really low? if the minimum is too low it becomes kind of useless [23:34:57.0426] * i'm still just like... you can make usable bigints in v8 that are larger than the entire minimum heap size for xs. so do we set the minimum really really low? if the minimum is too low it loses the point for having it [23:35:43.0994] Ok `for (const el of divergences) { …; break; }` would be `first` mode. [23:35:48.0784] * Or `for (const el of divergences) { …; break; }` would be `first` mode. [23:36:53.0204] One of the things I was hoping to get out of the discussion today was just this. My position is that the spec should be more explicit when it comes to acknowledging implementation constraints. But, _where_ or _under what conditions_ should the spec be more explicit? This was question 1: "Under what circumstances should an implementation-defined limit be preferred over a spec-defined limit, and vice versa?" [23:37:55.0813] this is why i mentioned that it would be helpful to have a more concrete problem statement. [23:38:08.0877] like some sort of program you want to write but can't due to platform divergence [23:39:08.0911] yep, understood. unfortunately I think it's too hard to talk about the general case. I think likely best to focus on a smaller set of specific cases with a definitive problem statement, then try expanding whatever decision we make there out to the other cases [23:39:29.0766] one example given was arr.push(...other) [23:40:08.0189] i would generally not write that code because i would assume it would throw somewhere [23:40:12.0903] or to close the iterator (if that matters) `divergences.take(1).next().value` [23:40:14.0044] so that could be something to explore [23:40:54.0278] but a solution to that could be adding array.extend rather than setting a minimum number of arguments [23:40:58.0994] i don [23:41:14.0408] * i'm not pushing for anything in particular here, just pointing this out as an example [23:42:01.0929] My "problem" is that I am an implementer and I want to write code that can make assumptions about how big a thing can be. I don't want to be forced to write code that is less efficient for the 99.9% case because the spec requires me to keep growing until I panic. [23:42:36.0977] do you have examples of this less efficient code? [23:42:53.0236] Does `take()` close immediately, or during the next `.next()` (that returns `{ done: true }`) [23:44:00.0024] Yes, for example, I have the metadata of ICU/ICU4X decimals bitpacked into a u32, because I am able to make assumptions about how big the number can be. [23:44:36.0602] i think on the `next()` [23:44:50.0580] you mean to fit safely into the bitwise safe range of js? [23:44:58.0074] On the GitHub post, I show that importing a UTF-16 JSON file currently triggers a SyntaxError. [23:45:02.0584] * you mean to fit into the bitwise safe range of js? [23:45:18.0981] right but i mean, if i'm choosing to import utf-16 text. why would that necessarily be an error [23:45:29.0144] * you mean to fit into the bitwise safe range of js numbers? [23:47:33.0131] I have to agree that this presentation seems very "solution before problem statement" [23:51:50.0110] deep-equal has 23m downloads a week and that's just one package this proposal would obsolete. dequal has 28m. [23:52:06.0076] I think this would actually work if the chars were > 256 code units [23:52:24.0971] The repo leads with the problem statement, but this presentation does not. [23:52:32.0000] But " and { are not, right? [23:53:41.0965] Correct, so you can’t use `ā€`. But you could use `0x22 …` [23:53:49.0950] The problem is `ā€` writes `0x00 0x22` [23:53:58.0717] * The problem is `ā€` writes `0x22 0x00` [23:54:16.0672] And the JSON parser will error on that unescaped nil char (because it’s a control char) [23:54:28.0055] You need a " at the beginning and one at the end [23:54:34.0060] So one of the 0x00 will be out of the quotes [23:54:37.0818] No, you need `0x22` at the beginning [23:54:41.0700] That will open the string [23:54:51.0782] The problem is the `0x00` that immediately follows [23:54:53.0460] But then you need to close the string [23:55:08.0012] That’s also possible with a high code unit char [23:55:42.0109] Oh you are saying if JSON was not ASCII-based for its separators? [23:55:49.0887] With 100% confidience, I can fool this JSON parser using utf16-le [23:55:58.0097] My position is that spec authors should decide whether such bigints are _useful_. The minimum shouldn't be "too low". The authors are in a better position to communicate that than implementers who want to make assumptions to improve memory use or performance. [23:56:15.0397] It will parse, it won’t result in code points that the input actually feeds it [23:56:51.0462] I just need to feed it a byte stream that can parse when interpreted as UTF-8. [23:57:09.0205] That’s completely possible within utf16-le. [23:57:18.0525] ljharb: But only if we are to standardize the same equalityAlgorithm as deepEqual. There are several mechanisms for deepEquality, as presented before. [23:57:30.0180] What would the bytes be? If you have a string you need to close it. The string `""` encoded as UTF-16 would result as either 0x22-0x00-0x22-0x00 or 0x00-0x22-0x00-0x22, which when decoded as UTF-8 is either `"\0"\0` or `\0"\0"`, both of which have a 0x00 out of the quotes [23:57:37.0889] * ljharb: But only if we are to standardize the same equalityAlgorithm as deepEqual. There are several algorithms for deepEquality, as presented before. [23:57:45.0899] * What would the bytes be? If you have a string you need to close it. The text `""` encoded as UTF-16 would result as either 0x22-0x00-0x22-0x00 or 0x00-0x22-0x00-0x22, which when decoded as UTF-8 is either `"\0"\0` or `\0"\0"`, both of which have a 0x00 out of the quotes [23:57:51.0638] This might be true and is why I used the language "almost always" instead of "always" for utf16le causing a SyntaxError to be thrown [23:57:53.0133] You cannot use the literal chars `ā€` or `{`/`}`. [23:57:54.0166] i maintain at least 2 of them. but it's not actually all that important in practice which one is chosen imo, since they all check similar things [23:58:24.0193] Ok, then you can only do either numbers or booleans [23:58:29.0450] Both of which use ASCII characters [23:58:32.0067] But there are other code points that emit the _bytes_ `0x22`, `0x7b`/`0x7d` [23:58:47.0364] Again, it’s an arbitrary byte stream being misinterpreted [23:58:51.0966] I control the byte stream [23:58:55.0400] Oh you are not saying something that is both valid JSON when decoded as UTF-8 and UTF-16, just different results? [23:59:04.0242] * Oh you are not saying something that is both valid JSON when decoded as UTF-8 and UTF-16? [23:59:14.0364] It won’t be valid JSON in UTF-16 [23:59:25.0626] Ok then I do not disagree [23:59:48.0880] But it seems very unlikely that you try to import as JSON that was not meant to be JSON, and it randomly happen to work due to using the wrong encoding [23:59:49.0393] You mean it won't be valid JSON in UTF-8? [00:00:00.0206] * But it seems very unlikely that you try to import as JSON something that was not meant to be JSON, and it randomly happen to work due to using the wrong encoding [00:00:00.0578] I’m saying the opposite. [00:00:25.0457] I can craft a utf16-le byte stream that will be valid JSON when interpreted as UTF-8. It will be invalid when interpreted as UTF-16. [00:00:54.0647] I’m saying that the JSON parser is not actually enforcing UTF-8 encoded input, it’s just a dumb byte parser [00:01:15.0994] Whether the stream is actually UTF-16 or UTF-8 is up to the implementer to decide [00:02:06.0674] ok, yeah. You have UTF-16 that, if interpreted as UTF-8, happens to form syntactically valid JSON. But, if you were to convert the UTF-16 to code points and then to UTF-8, you would get something that is not valid JSON. I agree that such cases exist. [00:02:35.0104] Correct [00:09:08.0533] > <@nicolo-ribaudo:matrix.org> But it seems very unlikely that you try to import as JSON something that was not meant to be JSON, and it randomly happen to work due to using the wrong encoding Unless the author of the file intended for that to happen. But to support your point, there's little to gain with that beyond an error being thrown [00:13:10.0031] which JSON parser is just consuming bytes? The ECMA-262 ParseJSON operates on a sequence of code points (which it gets from interpreting an ECMAScript string as UTF-16 per the normal convention). And even a hand-rolled one would implicitly interpret raw octets as something, be that ASCII, a UTF, EBCDIC, etc. [00:14:24.0293] It’s not, per Shane’s comment. It’s interpreting it as a UTF-8 byte stream [00:14:49.0054] * It’s not, per Shane’s issue. It’s interpreting it as a UTF-8 byte stream [00:24:12.0364] I skipped the problem statements presented last time because they were already agreed last time; the proposal itself was blocked by its dependency on its sibling proposals. That dependency is now removed. This presented a refinement on a potential solution based on quite a lot of feedback from delegates. [02:12:54.0215] > <@sffc:mozilla.org> Yes, for example, I have the metadata of ICU/ICU4X decimals bitpacked into a u32, because I am able to make assumptions about how big the number can be. Also, another key example where a spec limit definitely impacts implementation constraints is the max Temporal date. [09:28:18.0680] the one that returns `{ done: true }`; we discussed this in https://github.com/tc39/proposal-iterator-helpers/issues/219 [10:26:04.0391] * I skipped the problem statements presented last time because they were already agreed last time; the proposal itself was blocked by its dependency on its sibling proposals. That dependency is now removed. This presented a refinement on a potential solution based on quite a lot of feedback from delegates (and userland authors). [10:26:13.0694] * I skipped the problem statements presented last time because they were already agreed last time; the proposal itself was blocked by its dependency on its sibling proposals. That dependency is now removed. 
This presented a refinement on a potential solution based on quite a lot of feedback from delegates (and userland authors). [14:25:02.0566] For the TypedArray Concat and TypedArray Find Within proposals.. the advancement to Stage 1 was contingent on me creating and transfering the github repos... that's been done: 1. Concat -> https://github.com/tc39/proposal-typedarray-concat 2. Find Within -> https://github.com/tc39/proposal-typedarray-findwithin In the coming week I'll be adding the proposed spec text and assuming things are looking good, I do plan to go for Stage 2 (at least) by the next plenary [14:29:31.0945] James M Snell: did you get a chance to talk about some of the other ideas in the slides? in particular I am very interested in have a equals method which (for non-float TAs) can be implemented as a memcmp [14:30:08.0080] (I wasn't able to stay up for the actual presentation, sorry) [14:31:50.0569] Not everything. I wanted to see how these went before pushing my luck further ;-) ... I plan to bring a proposal for `compare`/`equals` for Stage 1 at the next plenary [14:33:21.0607] but I will likely go ahead and start preparing that in parallel with these as it really ought to be pretty straightforward [14:36:10.0675] nice! yeah, I suspect those could probably get straight to stage 2, since the design space is smaller. mostly just: is there a separate `.equals` or just a `.compare` (IMO both for optimizability reasons, plus Temporal has established a precedent for having both) and how does equality float-backed TAs work (IMO SameValueZero) [14:36:31.0165] (though also I would be fine with leaving out `.compare`; it comes up a lot less than equality) [15:03:35.0150] BTW, Shu wrote up the normative change: https://github.com/tc39/ecma262/compare/main...syg:ecma262:strongify-weakref [15:09:33.0385] I, for one, have projects that use usermode versions of both `.equals` and `.compare`. [15:32:17.0615] Yes I'm thinking both. I have use cases where both are used, tho equals Is by far the most common. Tho it is worth noting we can cover equals and compare with just compare if there are concerns [15:37:48.0620] in principle yes but for types other than Uint8Array you can't implement `.compare` with memcmp unless the engine can recognize that you're just checking the `.compare() === 0` case, which it probably can't most of the time, so I would want `.equals` anyway just for performance reasons [15:43:20.0991] Agreed. 2025-11-20 [17:06:33.0717] Chairs, is the decorators update still happening? I believe that there is new information that would be great for the committee to hear, even if Jacob is not here [17:13:55.0580] Reminder that if you presented, you need a summary of the presentation/conversation, and to record any conclusions that were reached. Here's some ongoing tracking https://kdrive.infomaniak.com/app/office/1777368/13 [17:14:38.0859] What's the "Unable to load event that was replied to, it either does not exist or you do not have permission to view it." that this is replying to? [17:15:11.0276] https://matrixlogs.bakkot.com/TC39_Delegates/2025-11-19#L525 [17:15:29.0346] > Does `take()` close immediately, or during the next `.next()` (that returns `{ done: true }`) [17:15:40.0174] hmmm.. with the continuations we have, the schedule is now full again. but we could do it if time allows [17:16:30.0916] Nevermind, I misunderstood and there is much less information that what I was thinking, sorry šŸ˜… [17:16:37.0689] * Nevermind, I misunderstood and there is much less information at the moment that what I was thinking, sorry šŸ˜… [17:19:28.0906] the afternoon second part schedule confuses me. there are two 20min continuations, but the schedule says it's full for 1h40m? [17:19:51.0900] * ~~the afternoon second part schedule confuses me. there are two 20min continuations, but the schedule says it's full foreieceeeheghftfglhinrtfbhclbkcluucrtnfbtdjcve 1h40m? [17:20:08.0577] * ~~the afternoon second part schedule confuses me. there are two 20min continuations, but the schedule says it's full 1h40m?~~ no, actually, it's only 40min [17:20:19.0405] * the afternoon second part schedule confuses me. there are two 20min continuations, but the schedule says it's full 1h40m? no, actually, it's only 40min [17:20:26.0737] * the afternoon second part schedule confuses me. there are two 20min continuations, but the schedule says it's full 1h40m? no, actually, it's only 40min this afternoon after break [17:20:29.0616] * the afternoon second part schedule confuses me. there are two 20min continuations, but the schedule says it's full 1h40m? no, actually, it's only 40min this afternoon after break today [17:21:02.0948] * the afternoon second part schedule confuses me. there are two 20min continuations, but the schedule says it's full 1h40m? no, actually, it's only 40min this afternoon after break today. Today ends at 16:00 instead of 17:00 [17:22:13.0486] maybe the topic should be moved to overflown section, instead of being "discussed" yesterday [17:22:18.0295] * maybe the topic should be moved to the overflown section, instead of being "discussed" yesterday [17:30:03.0068] For Decorators, is there anyone who would like to volunteer to lead the discussion in the likely case that Jacob cannot do it? [17:30:34.0742] I retracted my suggestion to do it anyway, in case you are asking because of my suggestion [17:30:36.0955] Measuring height of person: https://xkcd.com/3164/ [17:58:20.0519] waldemar: Could you coment here on what you would've said with your "disagree" reply? [18:08:16.0828] (I'm confused. Isn't Watt an SI unit for Power, and Joule for Energy?) [18:14:08.0595] indeed: https://www.bipm.org/documents/20126/41483022/SI-Brochure-9-EN.pdf#page=23 [18:14:29.0603] kwh is my favorite si unit [18:19:38.0494] The summary included an incorrect assertion that no one wanted an Amount that only does precision with no units. That's what I disagreed with. [18:20:07.0416] I had earlier stated in the conversation that I would support such a thing. [18:20:53.0624] Would you prefer an Amount that initially did not support unit conversion? [18:21:36.0715] "Paving desire paths" - making existing usage easier and robust [18:21:59.0667] Precision of a decimal number and unit conversion are two very different things. There are plentiful use cases of one without the other. [18:23:19.0989] There exist use cases for both simultaneously, but that doesn't mean that all decimal number precision should be tied to unit conversions and vice versa. [18:23:38.0120] https://www.w3.org/TR/html-design-principles/#pave-the-cowpaths [18:24:54.0713] Relatedly, do we have some connection to stateofjs? [18:25:14.0237] I agree. Do I understand right that you would not be opposed to an initial Amount that also supported unit conversion, provided that we find agreement on the details thereof? [18:25:15.0507] i think the survey owner is in the general channel [18:27:37.0437] not afaik but the person usually solicitcs feedback in #tc39-general:matrix.org before launching [18:28:44.0576] Olivier Flückiger: Does V8 cache the result of the internal equivalent to getNonIndexStringProperties? [18:29:03.0174] Ok, just came to mind re. "surveys are hard". We noticed that in the "pick 3 items" sections the distribution follows almost exactly the order of questions asked. [18:29:49.0259] No, we cache a list of enumerable properties in the order of enumeration. [18:30:38.0865] I have some concerns that each of the new getXYZPropreties will be expected to be cached but that will induce memory overhead in all cases without non-trivial effort [18:31:23.0866] Is that a concern that other engines share? It's not super strong opinion FWIW [18:32:05.0184] I also don't mean the actual cached data itself I mean the pointer to the cached data [18:32:07.0777] Yeah, that is a good point. We would not plan to add a cache. I recently added a fast-path for getOwnPropertySymbols without a cache. That gave about 30% speedup, but same copmlexity class. [18:32:17.0829] * I also don't mean the actual cached data itself I mean the pointer to the possibly cached data [18:32:37.0276] * I also don't necessarily mean the actual cached data itself I mean the pointer to the possibly cached data [18:32:37.0814] But I think anything else than enumeration would not be critical enough to warrant a cache [18:33:36.0777] If this is not cached and requires iterating through the properties, is it actually going to be meaningfully faster than iterating in JS? [18:34:18.0389] Well, same as with counting keys, we would not create the keys array. [18:34:27.0718] and also no regex, but an internal test. [18:35:12.0949] I think it would be faster for us, because we can just walk a shape [18:35:20.0614] * I think it would be faster for us, because we can just walk a shape-lineage [18:35:24.0170] In https://github.com/BridgeAR/array-get-non-index-string-properties I do not see any _real_ use case. We are now talking about "errors", "logging", there is no mentioning of "logging" _neither_ "errors" on the proposal so far. [18:35:40.0954] Node.js' use of this doesn't require caching. I wouldn't expect that at all [18:36:37.0425] fwiw `console.log` is a universal use case for exactly "describing every kind of thing", and the committee spent a TON of effort in ES6 trying to make web behavior implementable in JS [18:37:53.0284] I do think it's interesting hearing from Jordan/Mathieu/Ruben on use cases but the current examples on the proposal repo itself seem a bit contentious to me [18:39:27.0151] Aren't they different big-O with the caching? I don't think you can say either way. [18:39:32.0830] * Aren't they different big-O with the caching? I don't think one can say either way. [18:40:49.0489] As in if you have 1M indexed properties and one named property, even with caching that's gonna be slower than this. But if you have 1 indexed property and 1M named properties the cached array is going to be faster [18:41:07.0062] * As in if you have 1M indexed properties and one named property, even with caching that's gonna be slower than this. But if you have 1 indexed property and 1M named properties the cached array is going to be faster in JS [18:41:19.0058] what if property descriptors had boolean getters telling you all the different categories and whether the property fit that category [18:43:16.0540] Also, does this actually requires a regexp when running in userland? Or can it do `String(Number(d)) === d && d|0 === Number(d)`? [18:43:22.0052] Internal descriptors or JS materialized descriptors? materializing a JS descriptor for that case sems fairly expensive. Why not just a `isIntegerIndexKey(text)` that does the complex test against a key name? [18:43:29.0557] And could it use for-in to avoid allocating the keys array? [18:43:36.0683] * Internal descriptors or JS materialized descriptors? materializing a JS descriptor for that case seems fairly expensive. Why not just a `isIntegerIndexKey(text)` that does the complex test against a key name? [18:43:53.0982] materialized js descriptors. could also be %PropertyDescriptorPrototype% :> [18:44:01.0436] Ruben: I think, would really help here, if there are _actual_ use cases, either in some existing packages or at least in a way of some pseudo-code that would give me more perspective on, what you are trying to solve. For me this is a different language mechanisms like `Object.entries` for example. But feel free to ask me off plenary about that. [18:44:32.0193] the logging case specially needs property descriptors anyway so idk if the overhead would actually be that much in practice [18:44:47.0820] * the logging case needs property descriptors anyway so idk if the overhead would actually be that much in practice [18:45:03.0684] Getting descriptors is not super fast. Pretty big allocation and unrelated information. [18:45:23.0946] I think this is about having a fast-path to _not_ get descriptors when the TA is not weird [18:45:51.0560] Since what you get as the descriptor datastructure is not what the engines will have internally. [18:46:13.0073] logging doesn't always need descriptors [18:46:39.0260] However all of these discussions make me wonder if there would be an alternative proposal route that involves giving a more performance oriented api to descriptors. [18:46:50.0753] the existence of keys is typically the most valuable information, not a key's enumerability or configurability etc [18:47:44.0948] its just very likely in e.g. node's logger that a property descriptor will be materialized for any (non-exotic) properties [18:47:52.0083] That's correct. My worry is about the complexity and details of combining them, but if we can figure that out, that would be a fine outcome. [18:51:30.0983] uhh wait [18:51:42.0533] doesn't that mean it should be retroactively lowered to 2.7? [18:51:48.0584] should I put that on queue [18:52:59.0563] I have replies if it gets on the queue [18:56:36.0372] I agree with keeping Decorators at Stage 3 to reflect the main message that this proposal is in the implementation phase. TS shipped a while ago. We've done a few stage regressions for much more meaningful reasons. [18:56:44.0072] Are any implementers actually excited for this feature? [18:56:50.0159] Are any delegates? [18:57:04.0556] I would love this feature [18:57:05.0359] I’m certainly not… [18:57:10.0562] i'm excited for decorators on bare functions [18:57:16.0823] this feature only scares me, if I'm honest [18:57:34.0652] I definitely would like decorators on bare functions, possibly on bindings too [18:57:42.0864] A fair amount of the developer community is. [18:57:45.0949] more than classes TBH [18:57:55.0463] would this be a kind of implementation feedback, which counts for stage 3 feedback? [18:57:56.0730] browser vendors be like [18:58:38.0688] Yes. But I think we’re getting that feedback now. [18:59:22.0013] Server runtime implementors be like... [18:59:22.0367] I think Frameworks shipping this was a huge mistake, and that’s now influenced the users of those frameworks. [18:59:43.0748] There is a bunch of folk in Node ecosystem waiting for decorators. [18:59:55.0337] While of course decorators depend on your preference for meta-programming or not, those that do meta-programming are really yearning for this feature! [19:00:12.0803] They are used in quite some big frameworks for that matter. [19:00:13.0028] I particularlly hate Java annotations, and this is exactly the same meta programming that makes the codebase impossible to reason about. [19:00:24.0074] I do lots of meta programming and am the opposite of yearning for this feature [19:01:04.0717] Justin Ridgewell: With great power comes, great responsibility, but I'd rather use power wisingly, than having no power at all. [19:01:06.0985] society if meme for if v8 had accepted the edge and deno plan to ship decorators [19:01:44.0158] Great power hides the massive performance impact this’ll have on classes. [19:01:56.0696] I find the JS decorators proposal very different to Java annotation [19:02:00.0590] james is typing but he's not even at his computer, incredible [19:02:02.0785] * I find the JS decorators proposal very different to Java annotations [19:02:24.0594] /me is typing [19:02:38.0648] You can do so much more, than meta-programming with them! I for example use them as tagging decorators (basically Java's) annotation, i.e. those are decorators that have no function body, you can use them to get them easily in the AST. [19:03:11.0060] JS Decorators are functions that you can jump to like any function call and see what it does. Java Decorators were not like that at all [19:03:40.0076] Justin Ridgewell: Proxies also have performance implications, yet teams decide to use them, for better maintainability / clearer architecture / etc. [19:04:13.0139] I was just complaining about this sort of Java 'magic' to Lea last night [19:04:26.0760] Ashley Claymore: I know that Java annotations are laughable, but with JS decorators of course you can do the same thing. [19:04:54.0896] absolutely [19:05:02.0995] people can always do bad things [19:05:06.0972] If you looked at Decorators as used in TypeScript/Babel as an experiment, they are a proven success in the ecosystem. They reduce boilerplate and open up numerous possibilities that often *reduce the need for new syntax proposals* [19:26:13.0034] If anyone's interested, here's the bit of the observables design that I found particularly surprising https://github.com/WICG/observable/issues/216. Seems like I'm not the only one? [19:28:17.0190] Reminder to add your summaries and conclusions to the notes. And links to proposals/PRs/slides if they're missing. [19:29:01.0709] thank you for writing this up, I think this is extremely surprising too [19:57:46.0196] it puts the summary and conclusion in the doc or else it gets Aki's wrath again [20:09:26.0579] Ecma language spotted! [20:11:32.0798] hello spec writers I'm here to sell my ecmarkup language service extension, have a try! It provides code highlight, completion, go to definition, etc... https://marketplace.visualstudio.com/items?itemName=MagicWorks.ecmarkup [20:11:54.0356] Without having looked at the Babel example, I bet it that a _class_ is used as a _namespace_, this is a valid pattern and we will never get rid of it, by not enabling future class composition features. [20:12:33.0511] "really big anything" is an antipattern, but at some point the rubber hits the road and you end up with big classes or big modules or big functions. [20:13:07.0526] nicolo-ribaudo: wouldn't "having a separate class for comparison stuff", for example, make it easier for *users* to find things too, as well as babel maintainers? [20:13:53.0349] classes as a bag of extension points often need to be large [20:13:58.0602] Well then you need to create that class. That class that was on screen is kind of like `Node` on the web, which has a bunch of utilities all for dealing with nodes [20:14:08.0072] like we have https://github.com/shapesecurity/shift-reducer-js/blob/es2019/gen/monoidal-reducer.js [20:14:14.0989] with, what, 99 method? [20:14:18.0024] The plugin author is handled one thing that contains all the utilities on its prototype [20:14:26.0412] but consumers just have like 4 or 5 https://github.com/shapesecurity/shift-reducer-js/blob/es2019/examples/contains-this.js [20:15:22.0396] At one point I was considering proposing something like `partial class` to JS as a more standardized way of patching/augmenting existing classes w/o resorting to manual prototype patching. [20:15:50.0291] If only we had pipeline and module-level functions… [20:16:20.0247] In TS you could always reopen the static side of a class with `namespace`. Reopening the instance side of a class required an `interface` augmentation and prototype patching, unfortunately. [20:17:09.0120] It's possible to emulate multiple inheritance in JS using `Proxy` but its very slow. [20:17:13.0034] Haskell type classes are just Rust traits but with a better type system (HKTs) [20:19:05.0838] Not saying I agree with everything, but I found this talk really interesting: https://youtu.be/Gz7Or9C0TpM [20:19:06.0294] I think Haskell also allows orphan instances but you shouldn't do that [20:19:18.0918] lots in relation to this [20:20:37.0529] the talk covers their current direction for handling ambiguity/clashes when extending a type [20:20:43.0607] this is awesome šŸ‘šŸ‘šŸ‘ [20:21:24.0958] +1, i use it [20:21:26.0548] I wish I'd had more time to keep working on my ecmarkup extension :( [20:22:11.0254] fwiw i am strongly anti-interested in using web components as a design inspiration for anything [20:22:22.0382] This "custom form controls" example could be done with decorators too [20:22:26.0656] With a class decorator [20:23:24.0507] I think that might have been the original idea. There was a lot of interest in decorators from the web components authors years ago. It informed some of the design of the proposal, including `.addInitializer`, IIRC [20:24:08.0638] you know traits.js is good because it has a download button [20:38:08.0041] I removed myself from the queue because I'm afraid we are running out of time [20:40:17.0161] We don't adopt it right? [20:40:20.0677] Some of us do [20:40:32.0007] But not as a committee [20:40:48.0040] (just clarifying that I'm not trying to abuse the queue to throw a point out) [20:40:49.0140] oh man a third overload for PoC [20:43:47.0240] I don't really understand the 'stateful sub-instance' phrase -- does anyone have a definition? [20:48:30.0851] (There's so much confusion caused by talking about prototypical inheritance vs. C++ style/Java style inheritance) [20:48:55.0892] (and `class` doesn't help alas) [20:48:58.0984] prototypial or prototypical šŸ‘€ [20:49:11.0318] erm. [20:49:12.0383] yes [20:49:15.0216] prototypal? [20:49:23.0987] prototypal [20:49:28.0706] what ljharb said [20:49:30.0540] My proto-pal [20:49:32.0170] yeah typo'd that [20:49:43.0694] prototypo [20:50:32.0181] is prototypal/prototypial like aluminum/aluminium? [20:50:43.0525] take it to TDZ! [20:51:02.0565] * šŸ‘® take it to TDZ! [20:55:23.0118] the tightly-coupled use cases are not all that motivated IMO, the whole value is in the loosely-coupled use cases [20:56:24.0744] As I have said, if somebody is interested in **composition** of _MixIns_ with _CustomElements_ then give me a shoutout. Have a `` _structural mixin_ that you can compose with any CustomElement to make it blink. šŸ˜€ [20:58:23.0209] sidebar: we need https://github.com/tc39/proposal-private-declarations [20:58:37.0000] this is the only syntax proposal I think we _actually_ need in the language [20:58:40.0802] well, this and module declarations [20:58:57.0313] notably, neither of those are just sugar [21:00:01.0167] isn't module declarations a sugar for multi-file modules? [21:01:26.0821] Alternatively, `Symbol.geti`/`Symbol.seti` and `WeakMap`: ```js WeakMap.prototype[Symbol.geti] = function(key) { return this.get(key); }; WeakMap.prototype[Symbol.seti] = function(key, value) { this.set(key, value); }; const privateDecl = new WeakMap(); obj[privateDecl] = 1; // -> privateDecl[Symbol.seti](obj, 1); obj[privateDecl]; // -> privateDecl[Symbol.geti](obj); ``` [21:02:27.0119] oof, i wish that had been posted in tdz [21:02:34.0674] i can imagine implementations would love `geti` [21:02:54.0256] plus `Symbol.geti` could work with `Index` and `Range` objects as first class `^1` and `0:1` for index-from-end and slice/splice syntax [21:03:11.0330] no, because multi-file modules have other observable effects (network access, e.g.), and you can't use them from a script such as an inline script [21:03:50.0969] you can do it with blob modules :-p [21:04:09.0095] mlobules [21:04:17.0878] blobules [21:04:23.0509] nope, blob modules are still considered network access from the point of view of CSP [21:04:30.0556] oh weird [21:07:19.0116] they kind of have to be either network access or eval for CSP to work at all [21:07:46.0534] (possibly they should have been considered eval, but either way, same problem here) [21:07:48.0873] ah true, they're more like eval than network imo but either way [21:09:33.0868] This is potentially an example of how a decorator could accomplish the same thing as new syntax: ``` @spreadClass(Foo) class Bar { } ``` Not that I'm opposed to the syntax, per se, but decorators would allow for experimentation with this idea in userland before adoption as syntax. [21:09:55.0718] a useful read (or reread) for folks here might be https://legacy.reactjs.org/blog/2016/07/13/mixins-considered-harmful.html [21:10:49.0027] React is the site, that teaches you, that classes are hard to reason about, for machine and computers, so take that in consideration before reading that... [21:10:54.0773] having flight.js flashbacks [21:11:01.0599] How to specify [Symbol.iterator]() methods in classes? For example, like what we can do with array literals, ``` var obj = { *[Symbol.iterator]() { yield 1; yield 2; } }; var arr = [...obj]; arr.join(',') ``` [21:11:13.0559] the same way [21:11:25.0855] * the same way (like, precisely the same syntax as concise object methods) [21:11:29.0864] React is also the framework, that had stateless function components, before they changed them to functional components. [21:11:53.0853] (they're still stateless tho, useState isn't actually storing state on the component) [21:11:58.0096] according to a quick google search, react is also considered harmful [21:12:15.0083] note i suggested reading the article, not just the headline :-p [21:14:45.0838] just because something's possible doesn't mean it should be encouraged [21:15:31.0452] I think I'd rather have something like `class Foo extends Bar, Baz { }` than `class Foo extends Bar { ...Baz }` [21:15:57.0186] not that i want either one of them, but i agree on the relative preference there [21:16:11.0293] JS is multi-paradigm. It brings many tools to the table. Not all of them are equally "encouraged, everywhere, at once". [21:16:42.0532] some are less encouraged than others tho [21:17:23.0708] Even without progressing the language **any** tiny bit further, you can build the very worst things, (wo)mankind can think of in terms of software design. [21:17:34.0128] IMO, multi-argument `extends` would be sufficient for anything from multiple inheritance to mixins to protocols [21:18:40.0595] Especially considering it's already somewhat feasible with a helper, e.g. `class Foo extends f(Bar, Baz) {}` [21:19:01.0087] what on earth does f do there [21:19:19.0094] return a proxy? [21:19:26.0024] or do composition [21:19:28.0875] Mixins are a reality. [21:19:35.0507] * what does f do there [21:19:35.0697] I used `f` as a placeholder. It could be `mixin(...)` or something else, it doesn't matter. [21:19:50.0791] megamorphic functions will always be slow @ljharb:matrix.org, that's not gonna change [21:20:22.0155] so is `eval`. doesn't mean we should encourage it. [21:20:38.0692] Some implementation of `f` could theoretically do any of those operations depending on the input it receives. [21:22:00.0988] ljharb: `eval()` is a core feature of the language and it is - to me - something that every "interpreted" language has. It has the power to do everything, if you want to have a language, that disallows (i.e. "not encourage") things, go for a DSL that is non-turing-complete. [21:22:56.0342] sure, i'm not saying we shouldn't have it. i'm saying we shouldn't add affordances that encourages its increased use [21:23:02.0536] which is 1000% the case for mixins imo. it' [21:23:12.0378] * which is 1000% the case for mixins imo. it exists but it's bad and we shouldn't make it easier to do [21:23:42.0516] Mixin or NotMixin is not a thing, a language, we as a multi-paradigm language should be encouraging / disencouraging. [21:24:13.0118] hard disagree @christianulbrich:matrix.org [21:24:33.0296] that is entirely part of our job [21:24:39.0636] Michael Ficarra: On what? Mixins specifically? [21:25:02.0553] all sorts of things are bad and we should be giving them better ways to do things to avoid doing the bad things [21:25:10.0914] people shouldn't omit semicolons either, and it's absolutely our place to tell them that. and the spec has a section on ASI hazards for that reason [21:25:35.0628] Michael Ficarra: I agree. But I think, that there is no consensus on "mixins are bad", I am afraid. [21:25:53.0984] @christianulbrich:matrix.org I don't need consensus [21:26:05.0468] we need consensus to advance. if mixins aren't considered bad by *anyone* then mixin features won't advance [21:26:18.0568] this was also made pretty clear i think in the plenary session that introduced the existing mixins proposal [21:26:24.0585] * this was also made pretty clear i think in the plenary session that introduced the existing mixins proposal, back in 2019 or something [21:26:42.0031] Of course it works both ways. [21:26:52.0550] hold up, I'm gonna pull out my slides that eviscerated the mixins proposal [21:27:01.0959] mixins fill a gap in JS. I'm not personally opposed to mixins, but they do have a number of flaws. We can either address the flaws or find better way to fill the gap. [21:27:11.0030] to be clear, this topic is just "openly talking about OOP" as opposed to proposing a specific direction, right [21:27:16.0103] * to be clear, this topic is just "freely talking about OOP" as opposed to proposing a specific direction, right [21:27:18.0619] the flaws are intrinsic, and i'm totally open to finding better solutions [21:27:18.0844] For folks interested in changes to `AbortController` & `AbortSignal`, I've made a discussion-starter here https://github.com/whatwg/dom/pull/1425 [21:27:36.0412] but i'm pretty sure the problem statement here isn't "let's talk about OOP" [21:27:37.0957] This is now talking about a specific thing. [21:27:43.0192] But still time changes. Mixin usage changes. Whether one has a preference for it or not, with for example - web components based on classes, mixins have become a very common pattern to apply common behavior between them. [21:28:07.0196] web component design is not something that we should be inspired by. [21:28:08.0580] The "let's talk about OOP" was the previous item. both are in the same set of slides though. [21:28:11.0968] oh _what_ [21:28:18.0277] * web component design is not something that we should be inspired by. that you have to use mixins with them is part of that [21:28:21.0517] I literally had no idea the topic changed [21:28:28.0265] and wondered why it was already 2:30 [21:29:01.0799] yeah it wasn't announced [21:29:06.0477] Of course not. I gave it just as **one** example, of increased mixin usage. I am pretty certain - without having any data whatsoever - that mixin usage has increased since 2019 across the eco system. [21:29:31.0241] sure. but if you subtract any WC-related usage i do not think this is true [21:29:38.0854] it was but briefly [21:29:52.0487] same presenter and same slide deck made it very smooth [21:30:46.0885] ...and we can and should not ignore usage of patterns, idioms in the eco system. It certainly pushed us, to put things in the language. As `Promise.withResolvers` or `Promise.try` for that matter. [21:30:52.0528] IMO, mixins and protocols both fill the same gap and neither are a perfect fit. Protocols feel like explicit interface implementations in C#. Mixins feel like implicit interface implementation in C#. C# warns you if you have a conflict and lets you pick and choose syntactically whether to use the implicit or explicit implementation. [21:31:12.0888] same deck is fine but when I scrolled quickly through the deck there was no point at which it clearly indicated "here is a proposal" [21:31:19.0023] explicit > implicit [21:31:51.0507] * same deck is fine but when I scrolled quickly through the deck there was no point at which it clearly indicated "now here is a proposal" [21:31:55.0669] * same deck is fine but when I scrolled quickly through the deck there was no point at which it clearly indicated "and now here is a proposal" [21:32:00.0726] the presented slides are different from the link [21:32:10.0372] localhost is being presented [21:33:00.0870] explicit avoids conflicts but is unergonomic. implicit can have conflicts but is extremely ergonomic. I don't believe one is better than the other for every use case. [21:33:03.0982] The protocols proposal is also a solution to this stage 1 problem, right? [21:33:13.0359] that's ok, i do [21:33:28.0283] Which means we already decided that that's the rough solution to this problem [21:33:34.0215] As it's at stage 2 [21:33:34.0410] this seems a little tricky as a problem statement because it seems like spread _is_ the proposal [21:33:35.0147] I feel like there's something around the fact that it's currently impossible to put something in the body of a class to add a property whose value is not a fixed method body and have it end up on either the prototype or the constructor - only the instance (i.e. `field = computeValue()` but you can't for example wrap a method directly inline) [21:33:46.0651] i was curious about this as well [21:33:47.0977] * an abstract problem statement seems difficult here because it seems like spread _is_ the proposal [21:33:55.0467] yeah [21:34:21.0322] is there a replacement note-taker for jkup? [21:34:24.0382] That is what decorators are fore [21:34:27.0757] I was going to say that as well but wasn't 100% sure [21:34:33.0085] * That is what decorators are for [21:34:55.0508] So its not impossible, its just waiting on implementation and test review [21:36:04.0264] yeah I thought there was overlap with class protocols too [21:36:42.0711] which means we already allowed multiple similar proposals [21:38:56.0281] I think the motivation is clear. In ruby you can use `include` to compose somethings into a class easily, in mordern static languages, you have trait/protocol etc. In JS... you have nothing. [21:39:31.0103] I do like protocols. I use a variant of them all over my `@esfx/*` packages. I think the ability to define default non-symbolic implementations is also important, however. [21:40:45.0001] i think that's a necessity yes [21:41:02.0630] no :( [21:41:07.0417] that's how you get shared global namespaces [21:41:12.0271] IMO, if we could find a happy medium between mixins and protocols I think that would be the best solution. [21:41:24.0320] how are the words "shared global namespace" not sufficient in themselves to make you recoil from this concept [21:41:35.0083] `implements EventTarget with strings` [21:41:50.0550] methods can be strings, it already exists [21:41:55.0533] IIUC, withdrawing proposals like mixin will also need to call for consensus [21:42:16.0897] one possibility: ``` protocol X { x() { return 'symbol method'; } 'x'() { return 'string method'; } } ``` [21:42:18.0939] I don't *like* it, but I think I've come around to being okay not nannying [21:42:35.0178] i'm actually feeling like this is probably the best approach [21:42:40.0140] modulo the syntax [21:42:41.0420] * one possibility that lightly encourages symbols but permits strings: ``` protocol X { x() { return 'symbol method'; } 'x'() { return 'string method'; } } ``` [21:42:49.0409] * modulo the precise syntax [21:42:56.0856] meaning the user, not the author, decides? [21:43:17.0512] the consumer decides how it augments their public interface yes [21:43:28.0802] i guess there are conflicting needs pulling in both directions here [21:44:04.0559] but i think the producer deciding is distinctly more class-inheritence like [21:44:23.0915] That seems nice. Or if a conflict is found during mixing, throw an error [21:44:26.0174] deferring to something else vs saying you fulfill a certain contract [21:44:41.0864] I’d prefer to use string names if possible, and use symbols when there’s a conflict [21:44:47.0891] definitely conflicts would need to be loud [21:44:57.0889] Yes [21:46:05.0496] In C#, an interface is by default implemented implicitly: ```cs interface Stringable { string ToString(); } class Foo : Stringable { string ToString() { ... } } ``` But can be implemented explicitly: ```cs class Foo : Stringable { string Stringable.ToString() { ... } } ``` Whether something is implemented implicitly or explicitly is purely up to the consumer of the interface [21:47:15.0552] ^ Can we extend method names with `.` syntax to look up the lexical variable? [21:47:51.0069] Wouldn't that just be `[]`? [21:48:11.0910] Without wrapping [21:49:03.0558] can we advance the queue? [21:49:10.0888] I'd rather just stick with `[]`. without it you run into refactoring hazards [21:49:11.0095] I'd like to reply [21:49:15.0383] it would've been great if all this excitement about protocols had been occurring on the issue tracker some time in the last 8 years [21:49:27.0261] better late than never, I guess [21:49:32.0743] Extension proposal draft has syntax for that. [21:49:34.0121] i've always been excited about protocols [21:49:58.0227] not loudly enough! [21:50:15.0644] gus "snek" "protocols" caplan [21:50:38.0734] I like protocols, though I'm not a fan of the post-hoc `Proto.implement()` approach. [21:51:23.0519] seems like this is an is/ought conflict [21:51:29.0467] the upside of syntactic protocols is that there's the outside chance they can be statically optimized and you can have a self-contained class w/o depending on expression-level mutation [21:51:35.0364] ljharb is saying fields aren't the public shape [21:51:38.0876] protocols "gus" protocols "snek" protocols "caplan" [21:51:39.0834] lea is saying they should be [21:51:49.0109] I find it a very special view on things, saying, that you could remove properties in a constructor, you could remove static fields too. Certainly in TypeScript nobody would expect this, because `Classes` or `Interfaces` are made up of _public_ methods / fields. [21:52:00.0691] i'm 100% fine with a way to explicitly define the shape of an instance. but "the fields" are not the shape [21:52:09.0989] but like... why not [21:52:29.0177] it is true you can do dynamic stuff which makes the realized shape different from the list of fields [21:52:29.0763] because it's increasing the size of my API [21:52:35.0681] Michael Ficarra: do you see yourself having time to champion protocols these days? i may be down to co champion at least but i don't think i could individually spearhead it. [21:52:51.0095] ok, sure, that's a totally reasonable argument which is different from what was said just now, unless I missed it [21:53:01.0727] i did mention it briefly [21:53:04.0207] @rbuckton:matrix.org ^ [21:53:05.0278] that is an "ought" argument rather than an "is" argument [21:53:06.0346] I think it's actually already be public, for example d.ts must include that info. [21:53:31.0018] renaming a variable in my function shouldn't be a breaking change, nor should me moving between a public field and a constructor line [21:53:46.0886] in this context "public" means "to other code", not to build-time tooling [21:54:09.0087] right. through decorators is fine because that's something the class author has to explicitly opt in to [21:54:16.0796] * @rbuckton:matrix.org ^ there's declarative forms and dynamic/imperative forms for everything [21:54:39.0623] again, totally reasonable position but I think lea has a fairly convincing case that (if we want this at all) making public fields part of the contract is the obvious way to do it [21:54:44.0855] and right now you can already make a class decorator that decorates your class with shape info if you like [21:55:00.0185] not implicitly imo. explicitly? maybe [21:55:35.0410] I did not formulate my comment clearly apologies. I think I my next topic will clarify [21:55:45.0139] * I did not formulate my public field comment clearly apologies. I think I my next topic will clarify [21:55:49.0754] To me (and many people) they are one thing, or at least should be consistent. [21:56:23.0625] how do you feel about the argument that moving something between the class prototype vs being added to each instance in the constructor should not be a breaking change? because that feels like exactly the same kind of thing, to me [21:56:45.0909] property placement is part of the API of an object [21:56:53.0044] the way the property got there is notr [21:56:53.0898] * property placement is part of the API of an objec [21:56:55.0799] * the way the property got there is not [21:56:58.0795] * property placement is part of the API of an object [21:57:14.0815] why? I don't think users should think of property placement as being part of the API of objects, as a rule [21:57:19.0927] IMO, public fields *are* part of the public API. IMO, doing `this.x = ` in a constructor w/o some sort of public field declaration is bad practice [21:57:42.0137] if the documented way to use my objects is `foo.bar()`, it's on them if they were doing `Foo.prototype.bar.call(foo)` and that starts breaking [21:57:43.0604] rbuckton: It certainly is in TypeScript. :) [21:58:15.0514] ron that opinion certainly applies to ts but has no observable (aside from override mistake) difference in js [21:59:04.0551] yeah as somebody who's never used TS, that's a pretty foreign opinion to me šŸ˜… [21:59:30.0475] concretely: I don't think "is this property looked up on the instance vs the prototype" is any more obviously part of the API than "is this property declared in the class or dynamically added in the constructor" [21:59:38.0145] Today engines have to manage shape transitions in a constructor/function when you do `this.x = `. A fair amount of the discussion around field decorators came from implementers who wanted classes to have a fixed shape. [21:59:43.0717] What an API is made of, is described its documentation. There is no direct relation between a public field and a public API, it could also be an implementation detail, but let's understand what we are talking about with public API - public API means, that it is "available". [21:59:55.0648] shape is not an observable property in js [21:59:57.0040] * What an API is made of, is described in its documentation. There is no direct relation between a public field and a public API, it could also be an implementation detail, but let's understand what we are talking about with public API - public API means, that it is "available". [22:00:01.0501] Fixed shape also very strongly applies to structs. You *won't* be able to do `this.x = ` in a struct w/o a field declaration. [22:00:02.0288] that's a fair stance to hold. but nobody documents public field usage on their class - at best they document the final shape (which might be the same) in a TS type [22:00:39.0486] that's not entirely true (although semver means that). it's also arguable that anything reachable/observable is the API. [22:00:53.0330] there is almost universal agreement that `.toString` is not considered part of the public API. so "available" is certainly not what _I_ mean by "public API" [22:01:08.0740] * there is almost universal agreement that `function.toString` is not considered part of the public API. so "available" is certainly not what _I_ mean by "public API" [22:01:21.0452] yeah [[SourceText]] is an exception, it doesn't count for anything [22:01:21.0753] It is certainly observable when you hit a performance cliff due to IC cache misses [22:01:44.0996] It's not directly observable in JS as a language, but it is a fact of life in most engines [22:02:01.0719] that has nothing to do with whether its a public api though [22:02:09.0818] you can make your class slow with internal code as well [22:02:48.0659] if our only working definition of public api is hyrum's law how are we supposed to ever model anything [22:03:12.0046] ES5 style constructs have decades of optimizations [22:03:17.0254] * ES5 style constructors have decades of optimizations [22:03:29.0743] Fixed shape is still an important performance characteristic, so much so that it's baked into the `struct` proposal [22:03:41.0139] Maybe the discussion is a little bit too much into what is a "public API" and what not, the question is, whether the Introspection proposal has its usages or not. I think this is the question to answer: > "Is it worthwhile to let users introspect public fields" , regardless whether they are "public API" or not. [22:03:57.0242] and i would say no, not at ll [22:03:58.0304] Which are also often the cause of major performance issues. [22:04:01.0837] * and i would say no, not ata ll [22:04:03.0623] * and i would say no, not at all [22:04:14.0795] Personally I do not find an answer to this question easy. [22:04:25.0808] it definitely might be worthwhile to have class authors explicitly document their instance shape tho [22:04:34.0542] Arbitrary field ordering and partial field assignments are a whole class of performance issue. [22:05:40.0858] also, re the queue, to restate: function toString doesn't count for anything [22:05:51.0105] angular 1 learned that the hard way [22:05:59.0885] ``` constructor(x, y, z) { if (z) { this.x = x; this.y = y; this.z = z; } else { this.y = y; this.x = x; } } ``` this is terrible for performance and happens *everywhere* [22:06:09.0981] Yes, you can have `toString()` _lie_ :). [22:06:32.0183] not `Function.prototype.toString.call` tho [22:06:38.0295] * not `Function.prototype.toString.call` tho (unless you replace that method ofc) [22:06:40.0668] who is parsing function toString [22:06:47.0525] angular 1 did [22:06:49.0866] The above produces a class that can have three completely different shapes at runtime, which causes a host of issues with inline caching [22:06:50.0822] nobody else tho, hopefully [22:07:33.0472] @snek I have to for AOP with JavaScript :) [22:08:10.0250] what is AOP [22:08:25.0102] snek: Aspect-oriented programming. [22:08:25.0377] i had to google it too [22:08:26.0895] ... I kind of think we should a `Class` built-in, from which all `class` objects inherit (the classes themselves, not the instances) [22:08:33.0239] Isn't that the signal that we miss the reflection ? I think public fields have the similar issue~ [22:08:36.0772] Kind of what decorators are for. And the Angular 1 toString debacle is why Angular 2 heavily relied on decorator syntax [22:08:40.0813] and then we could have `Class.prototype.getFields` or whatever [22:08:56.0955] rbuckton: But not in functions. [22:09:10.0908] not yet at least [22:09:34.0935] not yet, though I already have two stage 1 proposal for this [22:09:42.0561] _real_ ā„¢ AOP is also about preconditions etc. at runtime, what else? šŸ˜€ [22:10:32.0582] real real AOP also works on any kind of function anywhere in your source / function. [22:11:16.0517] * not yet, though I already have two stage 1 proposal for this (function decorators and parameter decorators) [22:13:44.0887] real real real AOP would create those dynamically. An AI could do that! Dynamic tracing of production code due to potentially identified threats without explicit instrumentation, why not? Of course the proper reaction would be, self-modifying code to alleviate problems! [22:17:07.0916] šŸ‘® [22:21:21.0660] Do protocols support inheritance? like ``` protocol P1 { ... } protocol P2 extends P1 { ... } ``` [22:21:44.0501] i assume they'd support `implements` at least [22:22:03.0425] but yeah `extends` probably makes sense too, so you can still have required user fields [22:22:36.0568] yes https://github.com/tc39/proposal-first-class-protocols/blob/603c9ec53f134007d975654bbbec2a363aeae1e5/examples/monad-hierarchy.js#L11 [22:22:41.0654] If they do, then they have the same problem as mixins due to the diamond dependency problem. [22:23:05.0625] ... how so? [22:23:06.0537] * If they do, then they may have the same problem as mixins due to the diamond dependency problem. [22:24:39.0672] I may have misspoke? I need to consider it more. [22:29:34.0056] @rbuckton:matrix.org the example there is literally a diamond inheritance and it's not a problem for protocols because the names are always qualified by the protocol that defines them [22:30:08.0424] Can you override a default method implementation from a protocol? [22:30:46.0912] seems like it might be nice to temp check "who would block if it were / were not visible in the else" [22:30:59.0002] @rbuckton:matrix.org yes, and again, it's still qualified so still fine [22:31:02.0182] And what happens if you do this: ``` protocol P1 { foo() { ... } } class C1 { implements P1; [P1.foo]() { ... } } class C2 extends C1 { implements P1; } ``` [22:31:26.0476] works [22:31:42.0186] What does "works" mean? Which implementation is on C2? [22:31:50.0129] snek: I guess it doesn't matter but I'm surprised by the var comment. I thought your issue was that if the check fails the binding shouldn't exist? [22:32:14.0359] yeah i just don't care what var does. no code i have touched in the last 10 years uses var. [22:32:26.0904] ok thank you [22:32:29.0094] so i mentioned that since it presents one (of many) paths to advancement [22:32:51.0729] let's take this to DMs [22:32:58.0348] * so i mentioned that since since i have a hard stance and it presents one (of many) paths to advancement [22:35:11.0243] Justin Ridgewell: my bad, you're right about eslint [22:35:12.0534] bottom-left will not be picked up by a linter today. I'll bet a Sapporo on that. However, I think making a rule for that, should not be difficult. [22:35:14.0735] I actually don't know if it's that much of a pain? ``` if (let x = someResource; ...) { using _x = x; // ensure dispose } ``` [22:35:29.0129] * I actually don't know if it's that much of a pain? ``` if (let x = someResource; ...) { using _x = x; // ensure dispose } else { // ... } ``` [22:35:45.0715] The `...` leaves a gap between acquisition and registration [22:36:14.0988] ``` let data = "outer"; if (true) { let data = 'if'; } ``` will definitely error on https://eslint.org/docs/latest/rules/no-shadow [22:36:25.0688] * ``` let data = "outer"; if (true) { let data = 'if'; } ``` will definitely error on https://eslint.org/docs/latest/rules/no-shadow, which all the popular configs have enabled [22:36:56.0363] we gotta be making features that enforce correctness by default rather than saying the person writing the code has to enforce the correctness. there is a mountain of objective evidence that patterns like this cause bugs and security issues. [22:37:13.0007] ljharb: Yes, but only because you re-declared it. [22:37:14.0202] * we gotta be making features that enforce correctness by default rather than saying the person writing the code has to enforce the correctness. there is a mountain of quantitative evidence that patterns like this cause bugs and security issues. [22:37:25.0564] the bottom left is redeclaring it [22:37:34.0544] there's two `let data =`'s [22:37:53.0204] yes but in the condition. I doubt there will be support for that, already. [22:38:04.0664] oh. well sure, in that case every linter would syntax error on it [22:38:08.0514] how you gonna negate a declaration [22:38:09.0284] so either way i'll take my beer later :-p [22:40:01.0879] this is to be decided. I'd go for no syntax error and use an updated eslint rule :) [22:40:13.0910] I actually am okay with Stephen's solution here - restrict `else` when `if (using )` [22:40:29.0213] lol well yeah, obviously if the feature landed the rule would update to complain about the bottom left [22:40:57.0482] excellent, Jake's question is exactly where we should focus [22:41:12.0930] What was Jake’s question? [22:41:15.0249] oh wait what [22:41:24.0091] sadness [22:41:26.0751] ok so how am I supposed to write this in that case? ``` if (using resource = getResource(); resource.needsUpdate) { resource.update(); } else { await postMessage('no updates required'); } ``` [22:41:27.0741] did something get cleared? [22:41:30.0547] "is there still anyone who wants it visible in the `else`" [22:41:34.0155] * "is there still anyone who wants it visible in the `else`" was jake's question iirc [22:41:44.0362] I'll be honest, I really disliked using declarations in conditionals in Go, but I'll admit a lot of that ire comes from the lack of ternaries in Go. [22:41:50.0955] * I'll be honest, I really disliked declarations in conditionals in Go, but I'll admit a lot of that ire comes from the lack of ternaries in Go. [22:42:37.0631] maybe i shouldve done a temperature check lol [22:42:49.0441] cause yeah getting an idea of how many are on each "side" would be great [22:42:51.0711] Is the else problem also going to be essentially a blocker for pattern matching? [22:42:59.0169] i do think the idea of disallowing `else` is really clever! [22:43:10.0433] It seems like if we can't solve it here are we going to be able to solve it later? [22:43:32.0499] i don't think so [22:43:35.0903] how could you not know how many people are on each side at this point? [22:43:52.0882] There's a bit of a difference though. Pattern matching doesn't currently treat `if` specially. It declares the bindings in the containing scope. [22:44:02.0267] you can't use pattern matching with `using` so my opinions are less strong [22:44:05.0002] I thought temp check was super important there; I would be willing to extend the meeting 2 minutes to get one in [22:44:09.0318] i have a rough idea of who's who, but it would be nice to have confirmation [22:44:16.0778] * I thought temp check was super important there; I would be willing to let the meeting go an extra 2 minutes to get one in [22:44:20.0431] and frankly it was quite rapid at a few points [22:44:24.0969] we could make that usable but obv we'd have to make the usage of it work as you expect [22:45:52.0709] Example of `else` visibility in C#: ```cs if (ar is [var x, var y]) { Console.WriteLine(x); // ok } else { Console.WriteLine(x); // static error } // vs if (ar is not [var x, var y]) { Console.WriteLine(x); // static error } else { Console.WriteLine(x); // ok } ``` [22:46:20.0554] * Example of `else` visibility in C#: ```cs int[] ar = [1, 2]; if (ar is [var x, var y]) { Console.WriteLine(x); // ok } else { Console.WriteLine(x); // static error } // vs if (ar is not [var x, var y]) { Console.WriteLine(x); // static error } else { Console.WriteLine(x); // ok } ``` [22:47:04.0957] it's overwhelmingly disallow in the `else` because, well, duh [22:47:11.0151] I have no idea what that program means [22:47:27.0934] But that's really a pattern matching thing. [22:47:34.0102] yeah that's what i feel as well, but it also seems like there are a few who _very strongly_ want it in the `else` [22:47:37.0554] yes but data is better than vibes [22:47:49.0495] then do the temp check to confirm [22:48:49.0469] I still maintain that, aside from `using`, decls in conditionals is otherwise fully covered by pattern matching. [22:49:58.0253] (Side note: I didn't get temp-checked despite having TCQ open.... Despite my implementation concerns, I was leaning towards interning) [22:50:18.0179] it's perfectly fine to have two ways to do a thing tho. using pattern matching to get decls in conditionals is gross, and it'd be better to also have proper decls [22:51:06.0738] To be clear, decls in conditionals in a language like Rust *is* pattern matching. [22:51:33.0241] it wouldn't be here because of the condition part [22:51:39.0644] i think we should have pattern matching in if statement heads [22:52:19.0710] IMO, these are certainly not gross: ``` if (opt is Option.Some(let x)) { ... } while (iter.next() is { let value, done: false }) { ... } ``` [22:52:22.0344] I'd love to see pattern matching land - is there a reasonable path forward for it? [22:52:27.0319] its also an even better argument for else not binding, because there is no possible value to bind the variable to in the failure case [22:52:58.0167] i agree! but neither of those is *just* a declaration [22:53:10.0336] I believe so, we just haven't had the opportunity to work on the proposal in a while. [22:53:25.0326] can you get on the queue? sometimes if you haven't interacted in a long time, you have to re-auth for things to start working again [22:53:39.0851] Neither is `if (let x = ...; ...) {}` [22:53:52.0312] Seems to be working. [22:54:16.0784] true. but that one isn't pattern matching :-) [22:55:21.0607] I guess strings are technically garbage collectable [22:55:42.0565] `if let truthy(x) = ...` [22:55:49.0602] * `if (let truthy(x) = ...) {}` [22:55:58.0494] Consider the extractor case. `if (opt is Option.some(let x))` actually checks the extractor matches, but what would `if (let Option.some(let x) = opt) { ... }` do? [22:56:11.0571] ^^ vote 1 [22:56:29.0655] i mean i would've expected the syntax to be `if (let Option.some(x) = opt)` [22:56:37.0729] but in all 3 of these its just syntactic choices [22:56:42.0511] ``` if (opt is Option.Some(let x)) { ... } ``` if we're going to let you write ``` let Some(x) = opt ``` then I want to write the above as ``` if (let Some(x) = opt) { // ... } ``` not your pattern matching thing [22:57:10.0937] The temp checks were useful [22:57:14.0278] The first is pattern matching, which follows left to right evaluation. The second is assignment, which follows right to left evaluation. [22:57:23.0229] Don't forget to write your summaries and conclusions!!! [22:57:40.0522] this would be a useful three minutes for a temp check 😭 [22:58:08.0013] * Consider the extractor case. `if (opt is Option.some(let x))` actually checks the extractor matches, but what would `if (let Option.some(x) = opt) { ... }` do? [22:58:21.0553] Ah, extra `let` in the second example, fixed. [22:58:41.0572] my point was that i don't draw any behavioral information from any 3 of these [22:58:46.0195] to me they are 3 ways to write the same thing [22:58:56.0465] rust literally has exactly this [22:59:12.0022] the `if (let Some(x) = opt) {` syntax [22:59:13.0001] I have a thought, but I think you will hate it. [22:59:18.0560] * my point was that i don't intuit any behavioral difference between these [22:59:35.0089] this committee is an exercise in hearing hateful things; hit me [23:00:16.0149] `let Some(x) = opt` is exhaustive. If it doesn't match its an error. Just as `let [x] = opt` throws if `opt` isn't iterable. [23:00:36.0861] my point is that if you put it in an `if` then you would get the `else`, not an error [23:00:53.0442] this is very obviously how it should work, and is how it works in other languages with analogous features [23:00:55.0424] There are a lot of issues with trying to extend destructuring syntax to pattern matching. [23:01:13.0013] i think we are conflating two different things here [23:01:46.0374] Those languages can use pattern matching in declarations. JS can't because of decisions we made for how assignment and binding patterns work that preclude other pattern matching uses. [23:02:01.0199] but we can make extractors work like this [23:02:04.0392] can, and should [23:02:09.0167] I don't want extractors if we don't have this [23:02:29.0684] Basically a restriction where you can always write an `else`, but it's a `ReferenceError` to refer to a `if (using)` variable in an `else` block [23:02:33.0922] I'm actually trying to very clearly delineate the two. Declarations can't be actual pattern matching. [23:02:44.0081] Agreed. Is it the case that different options make sense depending on if your `if` is doing pattern matching? I.e. Rust is pattern matching and doesn't expose the binding in the `else`, Golang does _not_ pattern match and does. [23:02:57.0388] seems fine as long as it's also a ReferenceError for the other kinds of declarations! [23:03:35.0494] I investigated this several years ago: https://gist.github.com/rbuckton/df6ade207eecad4fc94cedc3aae79ceb [23:03:55.0508] I mean I'm fine with that too, it at least tells people "this can't be expressed, you're probably making a mistake" [23:04:03.0426] * I mean I'm fine with that too, it at least tells people "this can't be expressed this way, you're probably making a mistake" [23:04:10.0517] Specifically: https://gist.github.com/rbuckton/df6ade207eecad4fc94cedc3aae79ceb#extending-if [23:04:12.0333] * I mean I'm fine with that too, it at least tells people "this can't be expressed this way, or you're probably making a mistake" [23:04:58.0235] The pattern matching champions group were overwhelmingly opposed to extending existing syntax [23:08:40.0659] but seriously I would at least prefer that to the state where you can't write `else` at all. I do think it would be a very strange inconsistency, though, and would much prefer it to be an error for the other kinds of declaration as well. [23:08:42.0383] IMO, if `if (let Option.some(x) = opt)` actually checks the extractor matches, then `if (let [x, y] = z)` also need to check and not throw, and that means to any level of depth within the binding pattern. [23:08:44.0504] I don't see much reason to want any declarations to be visible in the `else` when you can so easily just move them up a line. `using` is the only reason you need to be extremely careful with when bindings are and are not in scope. [23:09:12.0218] move them up a line and surround the whole statement in `{}` [23:09:23.0010] if you want to be that careful with scope, sure [23:09:31.0580] but if you're not using `using` you don't actually need to be that careful [23:09:36.0851] Isn't that the point of the proposal? [23:10:24.0000] IMO the point of the proposal is basically `using`, and the other declarations are just nice-to-haves which would not be adequate motivation for the proposal on its own [23:12:03.0280] The proposal was originally written before `using` existed, so that's definitely an opinion. [23:12:04.0054] I can maybe get on board with a narrowly focused `if (using x = ...; ...) {}` proposal *without* supporting `var/let/const` as it also short circuits the whole destructuring and extractor concerns as well, since neither are allowed in `using`. [23:12:18.0370] yeah I said the same thing when it was originally presented [23:12:50.0659] I think it would be very weird to leave out `let` and `const` at that point [23:13:04.0163] like, as a user, that would make no sense [23:13:19.0065] Would that be open to abuse by just writing `using` for ordinary non-disposable variables? [23:13:32.0913] No, because that's an error. [23:13:34.0714] * Would that be open to abuse by just writing `using` for ordinary non-disposable objects? [23:13:45.0113] `using x = 1` throws [23:14:07.0393] it only allows `null`, `undefined`, and an object with `[Symbol.dispose]` [23:14:15.0992] At that point it's basically just try-with-resources [23:14:20.0024] * it only allows `null`, `undefined`, and an object with `[Symbol.dispose]()` [23:14:34.0642] No, try-with-resources doesn't support conditions [23:14:35.0384] nnnnot really? it's still a conditional [23:14:46.0559] And `using` started as a try-with-resources variant [23:15:37.0857] (false -> throw and catch, maybe? but point taken) [23:18:03.0286] I think we need to knuckle down and get the pattern matching proposal up to date and present soon. We've lost some momentum over the last year and at least one of the champions has had to step back. [23:18:13.0340] * I think we need to knuckle down and get the pattern matching proposal up to date and present it soon. We've lost some momentum over the last year and at least one of the champions has had to step back. 2025-11-21 [17:42:49.0837] ljharb (or whoever owns the tc39 namespace on github) can I be made admin of https://github.com/tc39/proposal-iterator-join? and/or just fix the url in the sidebar [17:43:25.0752] Fixed, lmk if there’s anything else