2023-06-01 [07:32:52.0124] Is _Object Type_ supposed to be _Object type_? [07:33:28.0859] Also, Undefined type and Null type are not in italics? [08:22:42.0022] annevk: the italics are because it's a definition [08:23:17.0139] the capital letter is probably a mistake; it was until yesterday in a header, where it was capitalized for that reason [08:25:11.0531] https://github.com/tc39/ecma262/pull/3086 [08:25:17.0162] bakkot: okay, so why are Undefined and Null type not defined? [08:26:06.0681] probably because we don't actually use them as terms [08:26:15.0622] but they could be [08:27:46.0066] I don't have a need per se, just seemed inconsistent [08:28:35.0750] Though maybe if we do more reconciliation across JS/Infra/IDL it could help, TBD [08:50:44.0786] There are a few uses of Undefined and Null, generally where the context forces the use of a type name rather than just referring to `*undefined*` or `*null*`. [09:06:08.0249] since they're single-inhabitant types, there's no need for us to refer to the type when we can just list all the inhabitants, which our syntax for describing types in the spec makes trivial 2023-06-02 [07:31:07.0718] What is the reasoning behind both the original regex unicode properties proposal (https://github.com/tc39/proposal-regexp-unicode-property-escapes) and the recent one adding the unicode string properties (https://github.com/tc39/proposal-regexp-v-flag) both passively refusing to add non-binary unicode properties (minus the 3 exceptions already supported)? The syntax for them is already in place, and implementers already use ICU for all of the binary properties, so it doesn't save on dependencies or anything either, so why are all the remaining String and Enumerated properties being left out? I can't find any reasoning or justification for it whatsoever in the discussions of the proposals, except some unclear indirect references to them like explaining why `Name` specifically isn't supported. 2023-06-03 [08:37:12.0856] has anyone successfully used the new eslint config system? (`eslint.config.js`) [13:08:44.0183] flat config? no, not yet. shared configs and plugins tend to need updates for that 2023-06-04 [21:43:24.0385] yes. I have no problem while migrating. [21:43:48.0201] > <@ljharb:matrix.org> flat config? no, not yet. shared configs and plugins tend to need updates for that plugin's don't need to update [23:04:24.0383] they do if they export shared configs, which is basically all of them [23:04:54.0073] I maintain the 3 most used ones, and I’ve only released one so far that’s compatible 2023-06-05 [05:04:21.0588] If anyone might find it useful, I just made https://test262.fyi which publishes results of test262 in most engines daily (like wpt.fyi or test262.report) (please give feedback/wants, sorry if not for this room) [05:06:09.0246] * If anyone might find it useful, I just made https://test262.fyi which publishes results of test262 in most engines daily (like wpt.fyi or test262.report but up to date with more engines) (please give feedback/wants, sorry if not for this room) [05:52:43.0407] @canadahonk: engine262 is checked in the repo's README, but doesn't appear on the website. [06:51:23.0426] > <@jmdyck:matrix.org> @canadahonk: engine262 is checked in the repo's README, but doesn't appear on the website. it's still running as I triggered a build not that long ago, it should show up in an hour or so [06:51:57.0486] * it's still running as I triggered a build not that long ago, it should show up in an hour or so (no caching/past data yet) [07:36:46.0950] > <@canada_goose:mozilla.org> If anyone might find it useful, I just made https://test262.fyi which publishes results of test262 in most engines daily (like wpt.fyi or test262.report but up to date with more engines) > (please give feedback/wants, sorry if not for this room) not very good UI atm, in some cases you cant even click some engines because the hover animations overlap and shift your hover into a different engine, but definitely interesting info to see [07:38:06.0792] > <@voidhedron:matrix.org> not very good UI atm, in some cases you cant even click some engines because the hover animations overlap and shift your hover into a different engine, but definitely interesting info to see I only began it 2 days ago so haha. If you have anything (else) specific to improve please say [07:39:15.0547] yea im aware its new no worries, just giving feedback 👍️ [07:39:52.0449] very welcome to it :) [07:40:10.0429] its also pretty disorienting how if an engine fails a test it completely disappears from the bars list [07:40:25.0467] well actually thats not really related to failing the test [07:40:39.0308] in general how the engines shift each other around unless theyre all 100% [07:41:11.0632] yeah I might change it so each one is in a container for 100% [07:41:18.0059] it'd be cleaner if each engine's % bar column had a fixed start [07:41:27.0477] yeah like that [07:42:45.0752] also if anyone has any (niche/obscure) engines missing I am very open to adding ;) [07:42:58.0208] * also if anyone sees any (niche/obscure) engines missing I am very open to adding ;) [07:44:28.0055] > <@jmdyck:matrix.org> @canadahonk: engine262 is checked in the repo's README, but doesn't appear on the website. it's there now 🎉 (fixing no cache now as well) [07:44:28.0411] it could be interesting to add runs for the versions of engines currently used in the latest versions of backend runtimes [07:45:03.0228] I had that idea too, like V8 nightly (now) and V8 stable (chrome/node/deno/etc) [07:45:20.0029] ie the V8 version of Node LTS and Latest, Deno's current V8 version, Bun's current JSC version, etc, yeah [07:45:35.0140] yeah planning that for sure [07:45:50.0525] also going to do a graph like WPT showing "interop" between chosen maybe [07:47:48.0601] something like compare engines A and B and show tests where they differ so you can see what to avoid/account for between the two could be useful [07:49:08.0348] yeah going to do diffs for sure [07:49:09.0356] a small UI detail too is you could have the test filenames actually link to the files themselves on the tc39/test262 repository (with the exact commit used for the test results on the side at the time of course) [07:49:27.0346] good idea, didn't think of that [07:49:31.0030] canadahonk We currently use test262 to test Babel+core-js, running them in a very old version of Node.js (0.8 iirc). It's not really an engine, but would you be open to also adding that? 👀 [07:49:53.0446] for sure! [07:50:03.0974] Expect a PR at some point then :) [07:50:22.0450] I'm also happy to do if you want btw [07:50:38.0664] code is mostly bash scripts and forks of utils for testing [07:50:48.0321] * code is mostly bash scripts and forks of utils for testing so a bit messy to add a new one [07:51:10.0931] I will open an issue to talk about it, so that I can at least give info regarding our current test262 infra [07:51:23.0747] thanks! [07:52:22.0550] should perhaps code in some way of having static engines that only get tested once and then never again unless manually, so that you can add older engines like that which are unlikely to have their test results change anytime soon but without the extra cost of rerunning them every hour or so [07:53:23.0184] * should perhaps code in some way of having static engines that only get tested once and then never again unless manually, so that you can add older engines like that which are unlikely to have their test results change anytime soon but without the extra cost of rerunning them every day or so [07:53:24.0550] well test262 and Babel/core-js/etc would be updated but yeah I plan on main ones updating daily, some weekly [07:53:41.0275] eg V8 stable weekly, V8 canary daily [07:54:02.0498] (although there isn't that much cost as all engines are tested in parallel) [07:54:31.0274] Btw to save on running time — Babel runs test262 on every commit and we generate tap output, maybe it makes sense to just use that instead of running the tests again [07:54:50.0300] oh neat [07:54:57.0384] pretty much what i was typing out yeah [07:55:26.0272] it would actually be smarter to just listen for updates on engines and test262 to trigger re-runs [07:56:34.0850] I want most engines to use their canary/nightly/CI/etc counterparts so [07:56:41.0917] well some of the engines may not be released on a platform that can be subscribed to like a webhook and might need to be polled on an interval for updates still, but still a lot cheaper than blindly doing re-runs of the same version [07:56:48.0883] (hermes took a lot of effort to get working lol) [07:57:50.0591] > <@canada_goose:mozilla.org> I want most engines to use their canary/nightly/CI/etc counterparts so yeah exactly, for the canary/nightly versions of engines you can just attach their updates to a github commit webhook [07:58:37.0897] well for the engines on github at least [07:58:50.0394] like v8 [08:00:11.0882] unfortunately you need ownership of the repo to make webhooks on other repos so won't be *that* easy probably [08:01:32.0811] > <@nicolo-ribaudo:matrix.org> Btw to save on running time — Babel runs test262 on every commit and we generate tap output, maybe it makes sense to just use that instead of running the tests again your talk was super cool btw ;) 2023-06-06 [03:07:52.0204] if anyone is interested, I updated the site to show proposals (and fix some data/UI stuff) [08:13:46.0430] Is it valid to use "is" to compare different values of different types? i.e. `If _x_ is *""*`, where _x_ might be a string or something else [08:13:56.0787] * Is it valid in spec-language to use "is" to compare different values of different types? i.e. `If _x_ is *""*`, where _x_ might be a string or something else [08:14:08.0232] * Is it valid in spec-language to use "is" to compare different values of different types? e.g. `If _x_ is *""*`, where _x_ might be a string or something else [08:20:42.0662] > <@nicolo-ribaudo:matrix.org> Is it valid in spec-language to use "is" to compare different values of different types? e.g. `If _x_ is *""*`, where _x_ might be a string or something else IMO it is fine and means SameValue [08:21:48.0805] I'm specifically wondering if the first step of https://tc39.es/ecma262/#sec-number.isnan is necessary [08:33:59.0982] it is not [09:58:27.0650] littledan: nicolo-ribaudo: You can read more about how to compare values for equality in https://tc39.es/ecma262/#sec-identity [09:58:39.0739] we have very carefully defined the term "is" [09:59:33.0873] Ah thanks for the correction [10:01:00.0395] Sorry I don’t think I understand the definition. How does this differ from SameValue? [10:01:37.0276] Because it also ranges over specification values? [10:01:47.0304] for one, "is" can be used with any spec value, but SameValue only works for language values [10:02:32.0127] OK, so my answer was correct in that particular context, but insufficiently general [10:04:56.0641] yes, SameValue could be used there because we already know both operands are ES language values [10:07:20.0371] we haven't written down our editorial conventions yet, but I believe the rule we've decided on is that we don't use SameValue when the operands are known to not have identity [10:09:00.0436] writing down those editorial conventions is my next big task as editor, but the 262 PRs and stage 3 proposals keep coming in faster than I can get to them all [10:22:50.0362] also SameValue bottoms out in "is" [10:22:55.0774] so "is" can't bottom out in "SameValue" [10:22:56.0110] but there's something poetic about having the first step of a function whose name literally means "is not a number", be "If _number_ is not a Number, return false" [10:51:09.0653] ptomato: and this is the one with the semantics we actually LIKE! 2023-06-12 [13:56:46.0412] I lost so much time today due to an unhandled rejection from a `promise.finally()` call [13:57:06.0080] The `promise` itself was handled, but the new one doesn't inherit that state. [14:01:33.0008] Is this an isolated example of the problem you observed? `Promise.reject(new Error('Bad from the start')).finally(() => Promise.reject(new Error('Got worse')))`, where the unhandled rejection is `Got worse`? [14:02:42.0679] And you lost time, I presume, because `Bad from the start` was the problem hiding behind the error? [14:04:02.0497] If that’s the case, perhaps the mitigation is for `finally` to produce an `AggregateError`. [14:22:07.0890] Would be great if that was web compat [14:23:44.0070] Maybe there is a way to thread that finally rejection to the unhandled exception handler, while preserving the current finally semantics of .then [14:23:54.0663] If want to be more compat [14:24:06.0598] Or…drumroll… `promise.finalé()` [14:24:39.0580] or just `.fin` 🎥 [14:25:37.0936] Hah. Q predated Doug’s initiative to make keywords valid property names, so I did call it `fin` in the earliest versions, and it’s still there for back-compat. [14:27:58.0601] Shunting the antecedent error out to unhandled rejection handler is a bandaid I can support, but that effectively means deprecating `finally`, since breaking the causal chain is bad in general. [14:28:22.0377] There really needs to be a way for both errors to flow through the output promise. [14:29:51.0431] And as long as we’re talking history, if I’d made Q _after_ Doug won keywordly-named properties, I would have been tempted to name `resolve` and `reject` as `return` and `throw`. [14:30:02.0184] wait Justin Ridgewell was the problem that `finally` swallowed the error from the original `promise`, or that you had an error thrown in your `finally` handler and you didn't handle that error, only errors on the original `promise`? [14:30:28.0158] And then we’d be living in a world where it’s obvious that Promises are just a degenerate AsyncIterators. [14:31:25.0872] ``` const promise = Promise.reject(); promise.catch(() => { /* handled */ }); promise.finally(() => {}) // new promise is unhandled ``` [14:31:51.0892] ah yeah [14:31:54.0966] that one is tricky [14:32:58.0491] It's _not_ equivalent to ``` try { try { await promise } catch { /* handled */ } } finally { } ``` [14:33:15.0555] Which is the behavior I wanted [14:33:50.0080] So, `promise.catch().finally()` would have done the job. [14:34:13.0382] Yup, but my catch and finally aren't in the same file [14:35:52.0785] This is I think a case where promises are working as designed, but we need to promote a culture of not dropping promises, and linting for dropped promises. That’s a bit of a tall order at the moment, since you need something like the TypeScript compiler to find them. [14:37:27.0238] We’ve used an eslint rule for this at Agoric, but because it’s driven by eslint and not tsc, there’s a great deal of duplicative effort in return type inference, so it’s way too slow. [14:44:44.0305] TS doesn't currently have a "must use" annotation [14:44:53.0313] so even TS is not sufficient on its own [14:45:11.0715] also there's a fundamental problem where any promise handler can throw, and then you have to handle that also [14:45:51.0026] like just `asyncFn()` is a bug because you don't handle exceptions, but `asyncFn().catch()` might also be a bug because you don't handle exceptions in the `catch` handler, and so on unto infinity [14:46:52.0585] TypeScript at least knows that `() => {}` will not throw. [14:47:38.0538] But yes, no amount of rigor will eliminate the need for UnhandledRejection reports. [14:48:14.0420] And even TypeScript can’t help you if your handler throws a `RangeError`. [14:50:40.0116] > <@bakkot:matrix.org> TS doesn't currently have a "must use" annotation To be clear, TypeScript + ESlint are able to check for dropped promises, but in this form, it’s just too slow. https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-floating-promises.md [14:52:12.0615] And that is quite good at halting at a handler that has done everything in its power to ensure no exceptions go unhandled. 2023-06-13 [18:16:43.0827] tbh i'd say that if the catch is in a separate file from the finally, then the finally file probably shouldn't be assuming the promise is handled [18:17:01.0358] * tbh i'd say that if the catch is in a separate file from the finally, then the finally file probably shouldn't be assuming the promise is handled - iow, the author of one file shouldn't assume knowledge of the code in another one [04:05:33.0149] Hey! I have a random question: was the idea of `Array.prototype.clear()` ever struck down in TC39? I've had repeated experiences of `array.length = 0` not being trusted by developers, despite being the best way to do clear an array, so I was thinking if a `.clear()` proposal would have a future [04:06:33.0169] Just coming from Python, Java, C#, Rust, or almost any language, you expect `.clear()` [04:07:12.0328] Why would `.clear` be trusted more? Btw, you can also use `arr.splice(0, arr.length)` [04:08:33.0163] It _seems_ sketchy, despite being valid, which is just an odd developer experience [04:11:06.0160] It felt much more like regular JS in 2014, but JS has improved so much in terms of the developer experience since ES6, that now it just feels out of place :D [04:14:28.0522] For instance, of course `.indexOf() > -1` was and still is completely valid – nonetheless `.includes()` is _the_ clear way of doing the same since it was added ES2016 [04:16:32.0960] Not to mention the edge-case where you have non-array-index extra properties in an array instance, which will not be cleared by `array.length = 0;` [04:16:58.0001] would those be cleared by a `.clear()` method though? [04:17:11.0113] Imo they should [04:17:22.0114] I can think of arguments in either direction\ [04:17:25.0595] * I can think of arguments in either direction [04:18:02.0058] Well argument in favor of it is, if you *don't* want the behavior of clearing non-indexes, you can just resort back to the original length method [04:19:13.0440] Thinking about it further, we could also take this further and invert it [04:20:13.0528] `Map.prototype.clear` doesn't clear properties on the map object -- is array different because the indices are actual properties in the object? [04:20:19.0918] * `Map.prototype.clear` doesn't remove properties on the map object -- is array different because the indices are actual properties in the object? [04:20:21.0208] While to Array there is the distinction between indexes and properties, from an Object perspective, both are just properties, so what if instead clear() was added as an Object method? [04:20:38.0826] and it would just generically work on arrays [04:21:15.0440] > <@abotella:igalia.com> `Map.prototype.clear` doesn't remove properties on the map object -- is array different because the indices are actual properties in the object? That was my thinking at first there yes [04:26:18.0596] Hmm, non-index properties on arrays seems like a niche use case outside of well-defined bounds of behavior [04:26:57.0359] I would stick to Map-like semantics of just emptying the collection [04:28:02.0733] That's up for further discussion though I suppose [04:28:13.0664] Well, do y'all know if the method sense as a proposal, or is there a reason why the idea is dead in the water? [04:28:18.0434] * Well, do y'all know if the method makes sense as a proposal, or is there a reason why the idea is dead in the water? [04:28:59.0960] My idea now is that, since arrays don't need a special method to access their internal values due to being just regular object properties, we should just make a generic *object* clear() method, which just works generically on arrays by extension [04:30:09.0395] So it is less niche and actually implements a new ability (clearing objects without manual looping of deletions) that was not previously possible unlike just clearing arrays with `.length = 0` [04:31:37.0017] Well, if it clears non-indexes, then why wouldn't it also delete `.length`? 😅 That's a tricky bit [04:32:40.0621] It can be defined like so: `Object.prototype.clear()` = Delete all **own**, **enumerable** properties of `this` `.length` is non-enumerable, so it would be preserved. [04:32:50.0136] I think the semantics would be clearer language-wide if `.clear()` always meant – clear collection. And `Object` is not necessarily the way of implementing a _collection_, given it's the building block for everything (e.g. if you want a mapping, well, `Map` is often the best option) [04:34:16.0995] `Map` is often too verbose and unnecessary for quick mapping needs [04:35:42.0004] In terms of data structures Map and Object are essentially the same, so saying Objects aren't collections is a bit illogical imo [04:36:21.0744] Map is just Object with fancier methods to manage it, no reason Object couldn't get some for itself [04:37:00.0763] Although I did just realize .clear() in Object prototype would indeed be prone to a lot of conflicts and confusion so it'd be probably best as a static method [04:37:15.0436] `Object.clear(arr)` [04:37:31.0800] you'd also have to figure out what to do for own vs inherited properties [04:37:45.0939] are you deleting non-enumerable properties as well? [04:37:53.0626] > <@voidhedron:matrix.org> It can be defined like so: > `Object.prototype.clear()` = Delete all **own**, **enumerable** properties of `this` > > `.length` is non-enumerable, so it would be preserved. ^ [04:38:19.0419] Just own enumerable props, anything else would break prototypes and other things [04:39:23.0530] it'd be a shallow clear, which follows suit with pretty much every other iterative operation in JS with the notable recent exception of the long awaited `structuredClone` [04:39:41.0482] so JS devs are already used to these kinds of operations being shallow I'd say [04:40:41.0198] * It can be defined like so: `Object.clear(obj)` = Delete all **own**, **enumerable** properties of `obj` `.length` is non-enumerable, so it would be preserved. [07:54:20.0056] `arr.splice(0)` [07:55:44.0617] so you're adding `arr.clear()` to accomplish `arr.splice(0)`. does that seem worthwhile? [08:40:16.0157] I would say the answer is exactly the same as with adding `.includes()` [09:27:14.0561] point taken. there were some additional considerations for includes that don't apply here. in any case, I'm not against convenience methods, though I'm not convinced in this particular case that splice or length leave much to be desired [09:27:49.0801] it's worth noting that additional methods on `Array.prototype` will face resistance in committee [09:27:59.0161] (I haven't read the full thread, lots of messages since I last checked) A few delegates said in the last meeting they're reluctant to add new methods to `Array.prototype` due to web compatibility issues we always have [09:29:00.0131] `Array.prototype.group` was changed in the last meeting to use static methods on Map and Object instead [09:29:48.0959] https://github.com/tc39/notes/blob/main/meetings/2023-05/may-16.md#arrayprototypegroup-rename-for-web-compatibility [09:29:53.0105] ref 1: https://github.com/tc39/notes/blob/d2a0097ec28f18d221118577086e20f78c33b504/meetings/2023-05/may-16.md#speakers-summary-of-key-points-4 ref 2: https://github.com/tc39/notes/blob/d2a0097ec28f18d221118577086e20f78c33b504/meetings/2023-05/may-18.md#speakers-summary-of-key-points-3 [09:37:20.0793] generally speaking, I think "some developers feel that the syntax for doing a thing is sketchy" is not a good enough reason to add a new stdlib method [09:38:27.0252] `.length = 0` is not obscure or difficult to understand for readers, so I don't see much reason to add a `.clear` to arrays [09:53:01.0065] matlokam: i wouldn't want to add any new mutating methods to Array, personally. [09:53:31.0915] * matlokam: i wouldn't want to add any new mutating methods to Array, personally. if you want an empty array, `[]` is right there :-) [10:05:30.0084] I think assigning to `length` is at least somewhat obscure. For most collections `length` doesn't have a setter. Having parity with other collections makes sense to me. [10:07:47.0620] for most collections you can't use syntax to read from it either [10:20:39.0479] generally not prohibitive, but this won't work with `const`, so not always an option [10:53:39.0013] Right, there was a conscious decision to not carry that forward. I don't think that disqualifies adopting more modern APIs for the older collection type though. [11:08:04.0782] I generally see APIs as being _worse_ than syntax, though [11:08:33.0309] Like I'd prefer people not write `array.at(5)` even though that's more consistent with what you'd do with a Map [11:08:45.0696] similarly I'd prefer people not write `array.clear()` even though that's more consistent with what you'd do with a Map [11:09:23.0554] I don't think it's really a matter of what's "more modern". Arrays are just a more foundational type and so have somewhat different affordances [14:39:16.0735] I agree that writing to `length` is somewhat obscure and so it wouldn't be bad to have a duplicate API around it. But also I don't understand why this method would be important/useful enough to be worth the high cost of adding Array methods. [14:48:28.0733] Another reason I think making it a generic Object static method would be more worthwhile and easier to get going [14:49:18.0041] It wouldn't go anywhere near Array but still be able to serve the task desired at hand, while also having other possible use-cases with non-arrays [14:50:13.0267] idk, I think it's generally not a good idea to encourage folks to treat Arrays like general objects API-wise (I think this doesn't match most JS developers' intuition) [14:53:19.0664] I also don't want to encourage people to clear properties from objects [14:53:28.0560] there are cases where that is the right thing but they are few and far between [14:53:33.0040] > <@littledan:matrix.org> idk, I think it's generally not a good idea to encourage folks to treat Arrays like general objects API-wise (I think this doesn't match most JS developers' intuition) That's a fair point, and I kind of agree I suppose, but on the other hand there is plenty of existing stuff in the language that does that already, so i dunno it would just be 1 more to the pile [14:57:39.0239] > <@bakkot:matrix.org> I also don't want to encourage people to clear properties from objects Well I suppose it could be `Array.clear` (static method) instead then, with a strict isArray check on the argument, I do would like that more as well personally, it just seems that it'd be harder to get it accepted due to being connected to `Array` [14:59:48.0104] Yeah and then my answer is, that is not worth having, vs just writing `arr.length = 0` [15:00:52.0999] Yeah I think, if we decide this kind of manipulation is important to support more intuitively, `Array.clear` is a good place to put it. [15:35:47.0868] is the proposed semantics of clearing actually `delete` [15:35:49.0245] if so please no [16:09:42.0290] Really interesting points around here [16:48:38.0540] So to condense the point, in my view there are a _few_ arguments for adding `Array.prototype.clear()` as stdlib sugar *for `.length = 0`*: 1. The base case for it is just that it would be the "one obvious way" of performing a common operation – emptying an array. Obvious in terms of the developer experience as well as performance, which is not quite the case for any of the solutions JS developers have today (and usually have to learn from StackOverflow): - `= []` for one requires usage of `var`/`let`; not in-place, which can be seen at a glance, so immediately not ideal performance-wise - `.length = 0` is just not the way this works in any mainstream other language, this trips developers up - `.splice(0)` works quite sensibly, but the semantics of splicing are a bit different, so this again isn't the obvious way of doing this 2. Coming from most other mainstream languages (e.g. Java, C#, C++, Python, Rust, Kotlin), you just use `.clear()` to empty an array (aka vector/list). The convention is basic to the core. 3. In terms of the cost of adding Array methods, JS has come a long way since ES2015 and the new annual release process. There's really good precedent: - `Array.prototype.find()` in ES2015 (just sugar over a `for` loop), - `Array.prototype.includes()` in ES2016 (sugar over `.indexOf()`, which itself is sugar over a `for` loop) - or this year: `Array.prototype.toSorted()` (sugar over `.slice().sort()`, again all coming down to iteration). All really good quality-of-life improvements, and rather comparable to `Array.prototype.clear()` both in terms of implementation complexity (low on the scale) and utility (fulfilling a specific but universal use case) 2023-06-14 [17:03:36.0561] if mutation is desired to be avoided, `toEmpty()` could be used, but then its essentially `= []` and falls under the same issues as it, so it becomes worthless [17:07:14.0940] Symmetry with other languages is generally something I'm in favor of when designing new features but is not in itself adequate reason to add a new feature when there is already a fine way of accomplishing the same thing. [17:49:10.0783] tbh I don't understand the reasoning against adding methods to `Array.prototype`, or rather I couldn't even find one [17:49:47.0227] what was linked were *statements* of Mozilla's (and them only) stance against them, with no actual backstory on the reasoning [17:54:25.0316] the reason was that adding methods with reasonable names breaks websites [17:54:44.0019] e.g. we tried to add `groupBy` and that broke stuff, and then we tried `group` instead and that broke other stuff [17:54:50.0282] and the breakage is often quite subtle [17:55:04.0692] this is a bad experience for everyone and Mozilla would like to avoid repeating that experience [17:57:07.0718] Chrome agrees with Mozilla on this btw [18:03:19.0837] how does it breaks websites to add properties that never existed before? [18:06:32.0997] many ways, one particular frustrating way was that there were uses of `Array` instances as hash maps, and `group` was being used as a key [18:06:44.0618] libraries that monkey-patched prototypes with the same method name break if you replace them with a function that does something different [18:07:02.0984] some of these are interesting [18:07:37.0944] for example, that one time I monkey patched Array.prototype.clear such that .clear called .splice such that registered change observers would fire [18:08:32.0123] pretty sure that code is in WRT modems now [18:09:30.0932] ``` function getGroupFromThing(x) { return x.group || x; } let things = [ { group: [42], }, [42], [44, 45], { group: [46], } ]; console.log(things.map(getGroupFromThing)); // good, all arrays Array.prototype.group = function(){/*...*/}; console.log(things.map(getGroupFromThing)); // oh no :( ``` [18:13:41.0959] but people monkeypatch all sorts of things in all sorts of JS builtins, not just Array [18:14:45.0704] if we start catering to those where does it stop? are we just going to forget the idea of adding new methods to anything ever? [18:15:26.0402] what about top level variables? are we going to also stop considering adding new builtins entirely some random person could have a top level variable with the same name? [18:17:08.0175] https://developer.chrome.com/blog/smooshgate/#why-dont-we-just-keep-the-existing-name-and-break-the-web [18:17:33.0736] it seems to me like a terrible and extremely disruptive to the language's progress decision to care for behavior in clear violation of the standard, every monkeypatcher is (or should) be aware that their code is invading a place it should not and it has no safety guarantee to itself [18:17:38.0960] this conversation has been had at length; I'm happy to link you to resources but we're not going to rehash it [18:17:49.0739] also the code I wrote does not do any monkeypatching [18:17:52.0035] if you read it [18:18:13.0310] (not that this really makes a difference to anything) [18:28:47.0129] I've read the SmooshGate link, interesting history that I didn't know happened, but it doesn't really answer my question at all, where is the line drawn between caring or not about monkeypatches for a specific name for some new feature? How is anything able to be added if we constantly worry about this? [18:29:17.0932] if we think the risk is low enough we try it and see [18:29:27.0664] For instance what differs `flatten` or `group` from `at` or `toSorted` [18:29:56.0713] Mozilla no longer considers the risk to be low enough for new array prototype methods with reasonable names [18:30:39.0949] how is that risk factor measured exactly? [18:31:03.0870] we just sort of guess [18:31:12.0249] I mean, what happened with `flatten` is that we tried, and it broke stuff [18:31:34.0663] that is to say, browsers shipped it, that broke a bunch of websites, so they unshipped it [18:31:40.0969] this did not happen for `toSorted` [18:31:57.0596] but whenever this happens it is very bad, even though we can in principle unship and find a new name [18:32:22.0384] this happened multiple times for `group` and Mozilla is not willing to pay that cost for future methods unless we think the risk is very very low [18:32:57.0115] which there is no practical way to objectively measure without shipping and seeing what breaks, and shipping is the thing they want to avoid, so we're just going to have to guess [18:39:00.0355] so just trial and error, I see, I also found out `at` actually apparently went through the same kind of problem being originally to be called `item`, ironically I'm actually a little glad about that one, `at` is much nicer 😂 [19:47:45.0322] > <@twixes3d:matrix.org> So to condense the point, in my view there are a _few_ arguments for adding `Array.prototype.clear()` as stdlib sugar *for `.length = 0`*: > 1. The base case for it is just that it would be the "one obvious way" of performing a common operation – emptying an array. Obvious in terms of the developer experience as well as performance, which is not quite the case for any of the solutions JS developers have today (and usually have to learn from StackOverflow): > - `= []` for one requires usage of `var`/`let`; not in-place, which can be seen at a glance, so immediately not ideal performance-wise > - `.length = 0` is just not the way this works in any mainstream other language, this trips developers up > - `.splice(0)` works quite sensibly, but the semantics of splicing are a bit different, so this again isn't the obvious way of doing this > 2. Coming from most other mainstream languages (e.g. Java, C#, C++, Python, Rust, Kotlin), you just use `.clear()` to empty an array (aka vector/list). The convention is basic to the core. > 3. In terms of the cost of adding Array methods, JS has come a long way since ES2015 and the new annual release process. There's really good precedent: > - `Array.prototype.find()` in ES2015 (just sugar over a `for` loop), > - `Array.prototype.includes()` in ES2016 (sugar over `.indexOf()`, which itself is sugar over a `for` loop) > - or this year: `Array.prototype.toSorted()` (sugar over `.slice().sort()`, again all coming down to iteration). > All really good quality-of-life improvements, and rather comparable to `Array.prototype.clear()` both in terms of implementation complexity (low on the scale) and utility (fulfilling a specific but universal use case) > I’m skeptical it’s actually all that common. [02:36:48.0821] Is there a good way to verify that the web won't break that'd be a step short of shipping an implementation in browser stable channels? Well, MooTools for one does not set `Array.prototype.clear`, so that's a relief. I remember that affair, but I'm not familiar with `group` woes. I'm curious, what was the pain there? [02:39:34.0311] You could do some research with HTTPArchive data and maybe GitHub (and that might make your case stronger if you did it well), but generally actually shipping is the real test. [08:36:20.0766] HTTPArchive wouldn't've caught the `group` ones [08:37:41.0090] regressions included https://bugzilla.mozilla.org/show_bug.cgi?id=1791415 https://bugzilla.mozilla.org/show_bug.cgi?id=1799522 https://github.com/webcompat/web-bugs/issues/112552 [08:38:49.0036] So, no, there is not any way to verify the web won't break short of shipping [09:10:27.0492] It wouldn't have caught those regressions, but maybe there were more. It's been quite a useful tool for evolving HTML. [09:15:10.0169] Yeah, it can confirm presence but not absence of issues [09:39:08.0036] > ECMAScript 2023, the 14th edition, introduced the toSorted, toReversed, with, findLast, and findLastIndex methods on Array.prototype and TypedArray.prototype, as well as the toSpliced method on Array.prototype [09:39:30.0549] sounds like adding methods to Array.prototype actually works out more often than it doesn't 🤔 [09:45:27.0639] Probably multi-word methods are safer [09:45:59.0638] And `with` is a bad keyword so probably people were scared of using it :P [09:47:38.0989] also "this only causes us a huge amount of pain a third of the time we try it" isn't that compelling really [09:50:44.0718] it's way less than a third. but it's such a huge amount of pain that mozilla and google's position here is understandable. [09:57:25.0721] `flatten`, `item`, `groupBy`, and `group` all had in-the-wild webcompat issues. by my count we've attempted to add a total of 14 methods to Array.prototype since 2015 (`flatten`, `item`, `groupBy`, `group`, `flat`, `flatMap`, `at`, `toSorted`, `toReversed`, `toSpliced`, `with`, `findLast`, `findLastIndex`, `includes`). so it's pretty close to a third. [09:58:31.0225] and `includes` was renamed from `contains` after it was found to break mootools IIRC [09:59:38.0588] `at` also had in-the-wild issues, come to think, we just managed to paper over them [10:00:54.0042] yeah `contains` was also an in-the-wild breakage, just that it was prior to 2015 https://bugzilla.mozilla.org/show_bug.cgi?id=1075059 [10:16:04.0611] `Array.prototype.jettison(all)` [10:16:58.0570] `Array.prototype.engroupen` [10:19:28.0789] isn't grouping just a special case of smooshing, if you think about it [10:25:01.0127] fair enough on the stats 2023-06-15 [18:24:25.0668] Remind me. The built-in-modules proposal was never a fix for the name conflicts right? Forcing someone to ```import "@std/Object"; which would patch the Object using side-effects. Was it decided years ago to continue using global changes forever? [18:26:19.0529] I think it would be nicer if instead we started having the prototypes of new builtins that get added to the language be frozen by default [18:26:59.0265] then we can guarantee no issues of that sort in those new builtins [18:29:26.0254] sirisian: I don't believe anyone ever proposed having built-in module imports be side-effecting, no [18:30:05.0876] and the built-in modules proposal was never formally rejected IIRC but has certainly stalled, and we're not blocking stuff on it [18:30:23.0339] voidhedron: that would prevent polyfills of later features, so we're not going to do that [18:31:37.0174] right... I didn't consider that [18:32:49.0072] maybe if there was a more official streamlined way of creating and applying polyfills [18:33:13.0970] and *just* polyfills, no other random stuff [18:34:49.0663] most people have gotten the memo about not adding random stuff now [18:35:08.0202] so anyone doing it anyway would presumably be willing to use whatever "official" mechanism there was [18:42:17.0224] yeah it is way past too late for it to be helpful at this point, but *if* we had made something like: (and frozen prototypes) ```js // in the surface its called basically like a Reflect.set call Polyfill.apply(Array.prototype, "at", function() { /* impl */ }); ``` which validated the inputs given by running it through the relevant test262 tests and if it didnt pass it refused to apply the polyfill [18:42:37.0623] we wouldn't have been in this situation now with web incompat issues [18:43:52.0263] it would also have automatically managed the right property descriptor for each polyfill [20:22:19.0135] Some of the web compat bugs are because the polyfill isn't being applied. They were doing: `if (![].groupBy) addGroupBy()` [20:23:36.0895] it's better if they always unconditionally apply it, that way the sudden appearance of the official implementation doesn't change the behaviour of the site [20:25:18.0250] It was only old versions of sugarJs that were applying it conditionally. Sites using newer versions of sugarJS were unaffected [20:34:15.0013] Yeah, that conditional application of the polyfill would also have been handled by the dedicated Polyfill api, so it would also have prevented that had it existed. [00:46:05.0823] Does anyone know why importing bindings that are not declared by a module throws a SyntaxError and not a ReferenceError? [00:48:27.0275] my guess is that it’s an error that happens before any code is executed [00:52:08.0058] That's what I suspected too — I am asking because some of the modules proposals allow distinguishing parsing errors from linking errors, so it's possible to detect "this is not actually a _syntax_ error" [12:48:14.0701] https://twitter.com/sebmarkbage/status/1669410404001251333 [12:48:25.0633] > `import "https://googletagmanager.com/gtm.js?id=123" with { type: "script" }` [12:48:27.0921] I don't hate this idea [12:48:36.0233] you can import a module for side effects; why not a script? [13:09:53.0424] I don't hate it either :) [13:18:58.0899] why should the type even be needed? [13:19:06.0002] like what's stopping it from Just Working [13:58:57.0575] You need _somehow_ to decide if the loaded file should be evaluated as a script or a module [13:59:12.0644] Someone uses .mjs, others use how the file is imported [14:09:37.0171] sloppy mode :( [14:09:47.0333] also the different parsing for `await` in modules, which is just wack [14:11:29.0804] oh right, duh, ambiguous syntax [14:11:50.0766] it'd work fine in anything with a filesystem since it could use extensions, but not with something URL-based [15:43:37.0146] this is why we invented MIME types [15:45:17.0888] unfortunately html disagrees [15:46:19.0263] anyway you probably wouldn't want a MIME type to affect whether something was loaded as strict or non-strict [15:46:28.0653] that would be incredibly painful to track down 2023-06-16 [00:05:52.0909] HTML disagrees? I thought it was TC39 folks who insisted on using the same MIME type for classic and module scripts? [00:06:14.0444] Anyway, too late now either way. [00:06:15.0812] sorry I meant the HTML spec, not its authors [00:06:22.0194] I do not recall who was responsible for that decision [00:07:59.0841] I think the module champions at the time felt pretty strongly about it. Any kind of additional hurdle was thought to be too much. (The HTML side did end up imposing CORS much to the chagrin of the champions.) [00:08:48.0301] anyway I think it's probably the right thing, given how subtle the difference is [00:10:28.0484] There are some disadvantages in that for certain optimizations you need to pipe through who requested the resource and then if the resource ends up being requested by something else as well that might get invalidated and such. But in practice I don't think anyone has attempted those. [00:12:04.0757] If we did something like type: "script" ("script module script" lol) I guess we would enforce CORS and UTF-8 just like we do for all modules, so might not be completely 1:1. [00:13:02.0130] Ah, "classic JavaScript module script" I guess [05:28:34.0475] We've had a lot of turnover among module champions, maybe Kris Kowal or caridy remembers this discussion. Anyway there was lots of discussion about "use module" or something like that, which was rejected in favor of the idea that you could just change the script tag and that was it for the transition. Using the same mime type follows the same principle [05:48:43.0173] I remember discussing this with dherman at Mozilla [10:26:40.0316] I wasn’t participating at the time these decisions were made, but, this module champion doesn’t think it’s weird that CORS applies to modules. I don’t have strong feelings about the MIME type homo/heterogeneity issue, and though I don’t love the `.mjs` extension, the costs of that choice have been paid already. I also don’t hate “import with type script”. We wouldn’t emulate it in Hardened JavaScript but I don’t think that would meaningfully hurt the portability path. I imagine this being used to incorporate a jquery import or some such in the import graph. [10:27:28.0463] (The reason we wouldn’t emulate it in Hardened JavaScript, and would actively prevent it with Module hooks, is that sloppy mode escapes confinement.) 2023-06-21 [09:01:03.0788] Might of interest to people here: https://github.com/whatwg/html/issues/9450 [11:17:54.0982] A regular reminder that Unicode is crazy and nothing can be trusted http://www.unicode.org/reports/tr55/ [11:18:09.0273] (Probably also relevant for HTML and CSS) 2023-06-22 [23:58:08.0309] I think we have categorized that set of issues as out-of-scope, but I guess it's worth pointing out somewhere once it's no longer a draft. [05:59:19.0354] > <@annevk:matrix.org> I think we have categorized that set of issues as out-of-scope, but I guess it's worth pointing out somewhere once it's no longer a draft. oh interesting, is there discussion of that somewhere? [06:00:03.0759] I think a possible change for JS is to allow more BIDI markers where they might not be allowed today. Maybe they are already allowed in those places in HTML. [06:00:26.0665] Another possible change is to equate certain identifiers with each other (which could be meaningful in JS as well as HTML and CSS) [07:13:34.0564] littledan: I don't recall a place unfortunately; HTML has some restrictions, but they're all within the ASCII range [11:09:27.0558] For CSS we've largely just chosen to avoid all the complexity by relying solely on codepoint comparisons. We do limit a few weird codepoints (matching HTML's restrictions on element names) but that's it. [11:11:58.0561] Yeah, neither really avoids the kind of "source code attacks" this document outlines, but that's really up to tooling to surface those kind of code points [11:13:15.0272] Right, whether we restrict some things or not in identifiers, they'll be allowed in strings, and editors need to be smart about it. (Which is definitely a non-trivial task, granted.) [11:13:39.0729] Would be interesting to pursue some way for CSS to *display* things in a smart way for this, tho. [11:18:00.0265] > <@tabatkins:matrix.org> For CSS we've largely just chosen to avoid all the complexity by relying solely on codepoint comparisons. We do limit a few weird codepoints (matching HTML's restrictions on element names) but that's it. I'm not sure if this is a sufficient mitigation for the risks described in that document, but I haven't fully understood this whole space yet [11:18:14.0913] Oh it's not [11:26:22.0419] > <@annevk:matrix.org> Yeah, neither really avoids the kind of "source code attacks" this document outlines, but that's really up to tooling to surface those kind of code points Oh, interesting, I wonder if this is how other programming languages are looking at this issue [11:27:30.0768] > <@littledan:matrix.org> I think a possible change for JS is to allow more BIDI markers where they might not be allowed today. Maybe they are already allowed in those places in HTML. This then is the remaining issue (of the subset of issues that I understand) [11:30:36.0389] fwiw, the CSS allowed codepoints for all ident-ish things is https://drafts.csswg.org/css-syntax/#non-ascii-ident-code-point [11:31:06.0989] You can put *anything* in a string (tho nulls and surrogates will get censored) tho. [11:31:43.0102] it is, explicitly, a larger list than what JS allows in idents [11:32:00.0196] (there's an explanatory block after the list talking about this) [11:32:48.0431] HTML parser is also very YOLO apart from U+0000 and surrogates, iirc [11:33:25.0427] yeah, our list matches HTML on purpose [11:33:43.0882] well, the html parser is more yolo than this list, but this matches valid html element names [11:34:01.0761] for general parsing css is also extremely yolo [11:35:09.0026] I noticed the other day that apparently WSGL is introducing a different kind of whitespace from JS so I guess they might care more about this as well [11:36:54.0967] Now I wonder how much overlap there is between WSGL, Wasm, and JS people [12:05:23.0444] can you use BIDI markers *outside of strings* in CSS and within an HTML tag, and have them just be ignored? This is one of the recommendations of that document. [12:25:03.0731] Not validly, but the stylesheet will just keep on trucking when it's encountered. It'll just cause something to get ignored (a property, or an entire rule, depending on where it is). [12:25:21.0580] HTML will *really* just keep trucking, it drops *very little* when it finds something weird. [12:55:20.0030] well, causing stuff to be ignored would be contrary to the intentions here [12:55:31.0132] I mean, beyond the BIDI mark itself [12:58:25.0100] littledan: Not really? If you add a LTR override, it doesn't render, it doesn't affect surrounding rendering (assuming it's already LTR), but it changes behaviour by disabling the rule/property/whatever [13:07:44.0581] yeah the idea is to not disable the rule... [13:18:12.0109] Why would you not want to disable the rule? It's violating the grammar. [13:33:21.0558] I think the Unicode folks are proposing, smart editors and tools should be able to add these BIDI marks in various places, so that the RTL display comes out better in simpler situations, but that these shouldn't change semantics (whether causing errors or things to be ignored) [13:33:41.0225] so the idea would be to add this to the grammar [13:35:00.0558] or maybe no one is suggesting that and I just misunderstood [13:45:06.0232] Oh, I haven't fully read the document yet [13:45:42.0225] But I got the vibe from what I did read that the opposite was the case, and they're recommending that editors should display code as logically as possible, *not* affected by bidi marks and the like? [13:54:23.0159] There are multiple conformance classes... Yes, editors should use their new BIDI rules to make things display right ,but also they describe an algorithm for inserting more marks for simpler consumers to be able to get it right 2023-06-26 [02:25:41.0199] Why is it that async constructors are not valid syntax sugar, even though you can manually implement them without any issues? [02:26:48.0384] Why was it decided that we should have to write: ```js class Foo { constructor() { return new Promise(async (resolve, reject) => { this.sync = 123; this.async = await someAsyncCall(); resolve(this); }); } } ``` instead of just ```js class Foo { async constructor() { this.sync = 123; this.async = await someAsyncCall(); } } ``` [02:27:24.0448] `await new Foo()` with the 1st codeblock works perfectly fine [02:28:10.0254] even the syntax itself is already in place for other methods of classes, `async methodName() { ... }` [02:28:42.0163] why was it decided to go out of our way to specifically block the syntax when methodName === constructor [02:30:55.0623] It's not without issues -- it does not work with subclasses [02:36:01.0903] works for me, just needs to be a little different from sync subclassing, which a dedicated syntax sugar could do ```js class Bar extends Foo { constructor() { return new Promise(async (resolve, reject) => { const base = await super(); base.barSync = 123; base.barAsync = await someAsyncCall(); resolve(base); }); } } ``` [02:36:27.0485] But now you cannot define private fields/methods in Bar [02:37:09.0127] A new "async constructor" syntax would solve this, but it's not just syntax sugar on top of what we can already do [02:39:55.0002] hmm I see, you're right on those [02:54:39.0024] so the problem seems to be super() attaches the caller's private properties on its own return value before I get the chance to `await` the Promise, so I get a promise with private methods... rather cursed to see [02:55:18.0091] is there a reason for this behavior of applying privates at a different step than normal properties? [03:03:28.0596] huh... this leads to some interesting things being possible... [03:09:08.0146] It's the same for normal properties: ``` class Bar extends Foo { prop = 2; constructor() { return new Promise(async (resolve, reject) => { const p = super(); console.log(p.prop); // 2 const base = await p; resolve(base); }); } } ``` [03:12:38.0511] well this is weird, since when does Chrome console allow you to directly access private members of classes externally [03:16:01.0737] Oh nice, I didn't know about that [03:16:07.0116] That's useful [03:16:29.0887] > <@nicolo-ribaudo:matrix.org> It's the same for normal properties: > ``` > class Bar extends Foo { > prop = 2; > constructor() { > return new Promise(async (resolve, reject) => { > const p = super(); > console.log(p.prop); // 2 > const base = await p; > resolve(base); > }); > } > } > ``` Oh I see, my "normal" property was actually a getter, and those end up in the promise result for some reason [03:16:38.0219] like `get prop() { return 2 };` [03:17:04.0933] Because it's on the prototype, so it's installed long before creating `this` [03:18:35.0138] oh right that's why it shows shadowed... I don't use Chrome console much I usually test this stuff on Node REPL so I got confused there (like with the .#prop thing above) 😅 [03:19:13.0534] on Node it just wouldn't show on the same level if its on prototype [03:21:06.0007] but in any case, back to the interesting implication I realized... [03:21:49.0677] We aren't normally allowed to have private properties on plain objects, and syntax like `let obj = { #foo: 123 }` is not allowed, but... [03:22:07.0286] ...this works [03:23:39.0322] > <@voidhedron:matrix.org> We aren't normally allowed to have private properties on plain objects, and syntax like `let obj = { #foo: 123 }` is not allowed, but... so at this point my next obvious question has to be, why isn't plain object privates syntax like here allowed? It's clearly not for technical restrictions of JS engines at least... [03:29:43.0048] but wait... it gets deeper, you can *inject* private properties into existing objects with this... [03:30:56.0133] not at all production safe, hell this whole concept is cursed off the tracks, but with some eval tricks you can even make it fully dynamic... [08:27:10.0128] voidhedron: if you return a promise from the constructor, then `new AsyncThing() instanceof AsyncThing` will be false [08:44:27.0072] seems logical enough to me? It will work if you `await` the left side [08:45:45.0487] thats like saying `typeof asyncFunction()` will always be `object` even if the function returns something else... of course, you didn't await it... [08:47:55.0215] I do agree that having a non-awaited lingering promise result from a constructor is weird though, but I just see that as another reason to have the async constructor syntax sugar, it could be made so that when the syntax sugar is used, the constructor *must* be await'ed and not awaiting it would be an error [08:49:17.0344] `async constructor` would be statically analyzable to engines should be able to tell at compile time if `new X` is an async constructor or not, an error or not due to lack of preceding `await` [09:32:18.0994] > <@voidhedron:matrix.org> so at this point my next obvious question has to be, why isn't plain object privates syntax like here allowed? It's clearly not for technical restrictions of JS engines at least... because no one has done the work to write out all the details of how it should work and convince the committee that it should happen [09:32:29.0954] this is also the answer to the `async constructor` question [09:32:58.0416] the work has started but not finished in both cases [09:33:25.0474] see respectively https://github.com/tc39/proposal-private-declarations and https://docs.google.com/presentation/d/1DsjZAzBjn2gCrr4l0uZzCymPIWZTKM8KzcnMBF31HAg/edit [09:34:06.0974] > <@voidhedron:matrix.org> `async constructor` would be statically analyzable to engines should be able to tell at compile time if `new X` is an async constructor or not, an error or not due to lack of preceding `await` but, this is false: `X` can be dynamically rebound and is therefore not at all statically analyzable, in general [09:34:21.0737] something like TS can do that analysis but actual engines generally would not [09:34:25.0972] * something like TypeScript can do that analysis but actual engines generally would not [09:39:02.0715] TIL: ``` new class { "constructor"() { console.log("hi") } // not logged } new class { ["constructor"]() { console.log("hi") } // not logged } ``` Similar to`["__proto__"]` vs `"__proto__"` [09:39:11.0221] * TIL: ``` new class { "constructor"() { console.log("hi") } // logged } new class { ["constructor"]() { console.log("hi") } // not logged } ``` Similar to`["__proto__"]` vs `"__proto__"` [12:59:52.0089] > <@bakkot:matrix.org> see respectively https://github.com/tc39/proposal-private-declarations and https://docs.google.com/presentation/d/1DsjZAzBjn2gCrr4l0uZzCymPIWZTKM8KzcnMBF31HAg/edit oh I see, issue #12 of the private decl's one even specifically talks about all the plain object private tricks I brought up, wonderful information thank you [13:00:11.0776] I will keep an eye on those two proposals from now on I suppose [13:01:07.0112] > <@aclaymore:matrix.org> TIL: > > ``` > new class { > "constructor"() { console.log("hi") } // logged > } > new class { > ["constructor"]() { console.log("hi") } // not logged > } > ``` > > Similar to`["__proto__"]` vs `"__proto__"` what is the technical explanation behind this stuff? [13:03:23.0499] it should be possible to identify when you are defining a prototype/constructor purely syntatically [13:03:35.0982] if you could use computed keys to do those, that would not be possible [13:04:36.0732] e.g. `let key = foo(); return { [key]: null }` - does that specify a prototype or not? the answer is that it does not, no matter what `key` is, because only static `__proto__` keys are special, not dynamic ones [13:43:36.0057] and in terms of spec the syntax-directed-operation for handing the constructor of a class body (https://tc39.es/ecma262/#sec-static-semantics-classelementkind) uses https://tc39.es/ecma262/#sec-static-semantics-propname which returns 'empty' for all computedPropertyNames [15:12:46.0080] I am updating the base64 proposal to support decoding into an existing buffer; would appreciate any feedback https://github.com/tc39/proposal-arraybuffer-base64/pull/26 2023-06-27 [17:28:57.0177] not really related but I don't think you should be using such unusual syntax like `0, { a, b, c }` [17:30:03.0498] it will confuse a lot of people and takes away attention from the actual api in discussion, I just spent a hot minute distracted by it to figure out why its there and what its doing instead of looking at anything else on there [17:30:07.0350] * it will confuse a lot of people and takes away attention from the actual api in discussion, I just spent a hot minute distracted by it to figure out why its there and what its doing instead of looking at anything else on the code [17:31:46.0855] actually, I don't even understand what its for, I thought I did, assuming this wasn't valid because of ambiguity or something, but seems like it is? [17:34:08.0288] `{ a, b, c}` is a block statement and `({ a, b, c })` is a record declaration expression. `0, { a, b, c }` is also an equivalent expression that discards the `0`. [17:35:19.0832] `({ a, b, c } = longExpression())` is pretty hard to scan too. 🤷‍♂️ [17:35:32.0731] `{ x, y } = obj` only works in Node's repl, not in an actual JS environment [17:35:52.0159] you need to write `0, { x, y } = obj` or `({x, y} = obj)` in a real JS environment, and of those, the former is better [17:36:01.0445] * you need to write `0, { x, y } = obj` or `({x, y} = obj)` in a real JS environment, and of those, the former is easier to read IMO [17:36:26.0295] it's the same as the old `(0, arg.method)(thing)` pattern [17:36:38.0477] * it's the same sort of thing as the old `(0, arg.method)(thing)` pattern [17:37:02.0721] Also, `(0, eval)(script)` [17:37:16.0695] (Which protects your scope) [17:38:30.0837] Ah I didn't realize the repl's automatic object literal parens wrapping would extend to impacting this too [03:55:42.0326] in TypeScript I may or may not have written `void 0, { x, y } =` to make it happy