2022-04-01 [17:57:53.0235] ljharb: i apologize for my tone earlier [14:58:47.0336] > <@shuyuguo:matrix.org> ljharb: i apologize for my tone earlier thanks, i apologize for getting worked up. 2022-04-02 [09:56:55.0474] > The Closure type system was originally based on the EcmaScript 4 spec. > — https://github.com/google/closure-compiler/wiki/Types-in-the-Closure-Type-System#javascript-types By chance, would anyone here happen to know where this is specified in the ES4 spec? The link provided is broken, but [here's the Wayback Machine's backup](https://web.archive.org/web/20161006100721/http://wiki.ecmascript.org/doku.php?id=spec:spec) if anyone knows where to look (it's pretty extensive). [10:35:24.0676] 3rd section of the [Core language](https://web.archive.org/web/20160802002701/http://wiki.ecmascript.org/lib/exe/fetch.php?id=spec%3Aspec&cache=cache&media=spec:core-language-d2.html) document seems like what that was referring to so maybe never mind? (much of that notation looks unfamiliar even having used Closure myself for several years) [10:38:35.0267] * 3rd section of the [Core language](https://web.archive.org/web/20160802002701/http://wiki.ecmascript.org/lib/exe/fetch.php?id=spec%3Aspec&cache=cache&media=spec:core-language-d2.html) document seems like what that was referring to so maybe never mind? (much of that notation looks unfamiliar even having used Closure myself for several years) [12:17:04.0117] > Deprecated syntax: adding a dot before the `<` (e.g. `!Array.`) is also accepted. Okay, makes sense now; more modern Closure (and TS) annotations don't look like this due to the syntax for parametric type application using the dot now being deprecated (at least by Closure) 2022-04-06 [07:18:15.0402] for https://github.com/mdn/content/issues/14744, comments in that issue or here would be welcome [08:12:09.0824] Hey sideshowbarker I'll try and add some more info or raise a PR soon. I raised it quickly before I forgot. Context: https://es.discourse.group/t/how-does-super-work-as-an-object/1279/4 [08:13:10.0686] * Hey sideshowbarker I'll try and add some more info or raise a PR soon. I raised it quickly before I forgot. Context: https://es.discourse.group/t/how-does-super-work-as-an-object/1279/4 [10:35:03.0438] > <@aclaymore:matrix.org> Hey sideshowbarker I'll try and add some more info or raise a PR soon. I raised it quickly before I forgot. Context: https://es.discourse.group/t/how-does-super-work-as-an-object/1279/4 ah thanks — I hadn’t realized it was you who raised it 2022-04-08 [20:18:01.0218] I’m confused about why we have an article at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/GeneratorFunction in MDN for a `GeneratorFunction()` constructor and global object when there is no such constructor and object in th spec [20:18:51.0868] but then I look in the spec at https://tc39.es/ecma262/multipage/control-abstraction-objects.html#sec-generatorfunction-constructor and I see a whole section on **The GeneratorFunction Constructor**… [20:19:33.0455] ah I see the spec defines it as an intrinsic [20:23:25.0438] it exists it's just not a property of the global object [20:27:56.0944] bakkot: so in looking at the spec, how can I tell that it’s not a property of the global object? [20:28:31.0320] and does not being a property of the global object mean it’s not callable at all from user JavaScript code? [20:28:37.0814] not even observable? [20:32:13.0244] You can tell it's not a property of the global object because it's not listed as such in section 19. [20:34:27.0346] and also because 27.3.1 "The GeneratorFunction Constructor" doesn't have a bullet saying `is the initial value of the "Foo" property of the global object` [20:36:43.0312] But you can't tell by looking at https://tc39.es/ecma262/multipage/control-abstraction-objects.html#sec-generatorfunction, which is maybe unfortunate. [20:37:00.0540] yeah [21:02:41.0819] for the non-global-property ones we could reasonably add a bullet saying "Is not exposed as a property of the global object", I suppose [21:04:27.0502] https://tc39.es/ecma262/#sec-%typedarray%-intrinsic-object says "does not have a global name or appear as a property of the global object", but it's the only one. [14:25:07.0977] we could also just … start exposing it 2022-04-09 [04:43:27.0656] Wasn't there some reason for not exposing it? 2022-04-11 [14:34:05.0995] if we have a bunch of string options that come off of user-provided options bags, is it preferable to convert them to `~tilde enums~` when used internally? examples of what I'm talking about are the _disambiguation_ and _offsetOption_ parameters of this abstract operation: https://tc39.es/proposal-temporal/#sec-temporal-interpretisodatetimeoffset [14:34:42.0200] (the _offsetBehaviour_ parameter doesn't originate from a user-provided options bag, so that's why it's already got tilde values) [14:35:24.0054] ecma402 uses the string values (e.g. https://tc39.es/ecma402/#sec-initializedatetimeformat) but there isn't much precedent yet for options bags in ecma262 2022-04-12 [06:48:43.0954] so interesting! [06:49:16.0971] https://twitter.com/jackworks_asref/status/1513876593021956103 [07:00:14.0747] Is there any `export function then`? 😛 [07:00:42.0785] * Is there any `export function then`? 😛 [07:47:10.0138] No, because the private field is on the import promise, not on the module object [08:13:10.0150] only using spec features? Or special stuff like node async-hooks? [08:21:43.0703] > <@aclaymore:matrix.org> only using spec features? Or special stuff like node async-hooks? Yeah you got it. It's Node only 😂 2022-04-13 [16:51:05.0997] ptomato: why does Time Duration Record have [[Days]]? [16:59:50.0825] it's for when an operation that uses Time Duration Records overflows 24 hours and needs to indicate to the caller that if they care about days, they need to adjust their day total 2022-04-14 [17:00:03.0346] maybe a more descriptive name would've been [[DeltaDays]] [17:00:54.0383] i don't have anything against [[Days]], just didn't understand why [17:01:53.0689] I can give a more concrete example, maybe [17:05:02.0314] when you take the difference between two PlainDateTimes, you get the difference between the date parts from the calendar, then you need to take the difference between the time parts ([DifferenceTime](https://tc39.es/proposal-temporal/#sec-temporal-differencetime)). the time difference might be negative or wrap around 24h, so the [[Days]] field indicates that you need to adjust your date difference accordingly [17:09:09.0560] I hope that's not gibberish :-) it's hard to know sometimes how much detail to go into [17:16:09.0527] i think so? my confusion is probably because i have a naive understanding of how people do duration math [17:16:52.0703] like, i figured the duration between two times, even if it changes days, would still be represented only as some number of hours [17:18:06.0736] but it also makes sense to represent that the day changed, that seems more useful than just number of hours [09:32:24.0457] for a concrete example, there is a difference between a duration of 1 day vs. 24 hours that is observable from `Temporal.ZonedDateTime.from("2022-03-13T00:00[America/New_York]").add(Temporal.Duration.from({days: 1}))` vs. `Temporal.ZonedDateTime.from("2022-03-13T00:00[America/New_York]").add(Temporal.Duration.from({hours: 24}))` because of the DST transition 2022-04-18 [13:26:25.0197] Does anyone know if the iterator helper proposal has ever discussed parallel/batch features for v1? A lot of my use cases for lazy iterators involve async operations that benefit from parallel requests. Maybe I'm thinking of this wrong, but like for (const item of webpages.map(async url => return await op(url), { batch: 5 })){} where 5 are executed in parallel and are handled out of order first come. (In theory if a break is called then the other 4 pending would be cancelled by the generator's return). The big picture is handling tasks that might look like [500ms, 10ms, 10ms, 10ms, 10ms...] where a random long task blocks the whole pipeline. With more complex pipelines this snowballs into large delays. [13:48:22.0103] sirisian: not for v1, no. I would also like to see such a thing at some point but it doesn't really fit with the simpler v1 helpers; it would be its own thing [13:48:58.0600] As long as it's possible later, that's all that matters. [13:49:50.0531] I haven't thought about it really hard but I expect it should be. and at the very least nothing in this proposal is likely to make it harder. [13:50:54.0884] Ixjs has this with a `concurrent` param for `flatMap` https://github.com/ReactiveX/IxJS/blob/master/src/asynciterable/operators/flatmap.ts [14:02:48.0183] for the particular example you give I think the thing you actually want is a helper to bound how many invocations of an async function can be running simultaneously [14:07:25.0823] ``` function boundAsyncFunctionConcurrency(f, N) { let waiting = []; let available = N; function lock() { if (available > 0) { --available; return; } return new Promise(res => { waiting.push(res); }); } function unlock() { if (waiting.length > 0) { waiting.shift()(); } else { ++available; } } return async function(...args) { try { await lock(); return await f.apply(this, args); } finally { unlock(); } }; } ``` [14:07:29.0425] or something to that effect [14:07:58.0564] so you can do `.map(boundAsyncFunctionConcurrency(async url => await op(url), 5))` [14:08:11.0084] rather than getting the iterator helpers involved directly [14:08:27.0078] but there are probably other cases where you'd want the iterator helpers to be involved [14:55:22.0747] I've used https://www.npmjs.com/package/throat in the past [15:57:51.0586] bakkot: Wouldn't your implementation instantly create N promises consuming the whole input generator? Ideally a lazy iterator implementation wouldn't do that. The map would only call next 5 times to start then again when the first promise returns. Ideally a generator could have infinite items and everything would just work. [15:58:22.0851] * bakkot: Wouldn't your implementation instantly create N promises consuming the whole input generator? Ideally a lazy iterator implementation wouldn't do that. The map would only call next 5 times to start then again when the first promise returns. Ideally a generator could have infinite items and everything would just work. [16:34:26.0363] sirisian: no, it will not consume the whole input [16:34:44.0727] not unless you `toArray` it or something, anyway [16:36:30.0982] iterator helpers are lazy [16:36:40.0471] which, it occurs to me, probably means they're not a good fit for what you're trying to do anyway [16:38:55.0542] you can't really have all three of "works with infinite generators", "provides results in order", and "does not block on inputs which are slow" [16:41:11.0930] because if you _don't_ block on slow inputs, but you still want to get results in order, that means it has to eagerly start doing work for results past the next one, which means it's not going to work for infinite iterators. [16:41:14.0233] Well I said out of order. [16:41:23.0342] ohh, missed that [16:41:50.0510] I don't think we want iterators to ever provide results out of order, so that would just be a different proposal for a different mechanism entirely [16:43:14.0609] I do see what you mean though. In applications where order matters batch means something very different than what I intended in my ad-hoc example. [16:43:22.0401] * I do see what you mean though. In applications where order matters batch means something very different than what I intended in my ad-hoc example. [16:44:40.0413] I think the thing you want is something which works with sync iterators which yield promises? Let me see... 2022-04-19 [17:36:05.0937] Here's an example: ``` // Each item has a few pipelined actions that take time indicated by the number. So the first item does 3 operations each taking 500ms function* gen() { yield* [[500, 500, 500, 'a'], [500, 500, 500, 'b'], [10, 10, 10, 'c'], [10, 10, 10, 'd'], [10, 10, 10, 'e'], [10, 10, 10, 'f']]; } for await (const i of gen.map(async item => { await new Promise(resolve => setTimeout(resolve, item.shift())); return item; }).map(async item => { await new Promise(resolve => setTimeout(resolve, item.shift())); return item; }).map(async item => { await new Promise(resolve => setTimeout(resolve, item.shift())); return item; })) { // This will after summation of all the times in each array. console.log(item.shift()); } ``` [17:39:56.0191] * Here's an example: ``` // Each item has a few pipelined actions that take time indicated by the number. So the first item does 3 operations each taking 500ms function* gen() { yield* [[500, 500, 500, 'a'], [500, 500, 500, 'b'], [10, 10, 10, 'c'], [10, 10, 10, 'd'], [10, 10, 10, 'e'], [10, 10, 10, 'f']]; } for await (const i of gen.map(async item => { await new Promise(resolve => setTimeout(resolve, item.shift())); return item; }).map(async item => { await new Promise(resolve => setTimeout(resolve, item.shift())); return item; }).map(async item => { await new Promise(resolve => setTimeout(resolve, item.shift())); return item; })) { // This will after summation of all the times in each array. console.log(item.shift()); } ``` [17:40:29.0323] * Here's an example: ``` // Each item has a few pipelined actions that take time indicated by the number. So the first item does 3 operations each taking 500ms async function* gen() { yield* [[500, 500, 500, 'a'], [500, 500, 500, 'b'], [10, 10, 10, 'c'], [10, 10, 10, 'd'], [10, 10, 10, 'e'], [10, 10, 10, 'f']]; } for await (const i of gen.map(async item => { await new Promise(resolve => setTimeout(resolve, item.shift())); return item; }).map(async item => { await new Promise(resolve => setTimeout(resolve, item.shift())); return item; }).map(async item => { await new Promise(resolve => setTimeout(resolve, item.shift())); return item; })) { // This will after summation of all the times in each array. console.log(item.shift()); } ``` [17:48:16.0683] * Here's an example: ``` // Each item has a few pipelined actions that take time indicated by the number. So the first item does 3 operations each taking 100ms async function* gen() { yield* [[100, 100, 100, 'a'], [100, 100, 100, 'b'], [10, 10, 10, 'c'], [10, 10, 10, 'd'], [10, 10, 10, 'e'], [10, 10, 10, 'f']]; } for await (const i of gen.map(async item => { await new Promise(resolve => setTimeout(resolve, item.shift())); return item; }).map(async item => { await new Promise(resolve => setTimeout(resolve, item.shift())); return item; }).map(async item => { await new Promise(resolve => setTimeout(resolve, item.shift())); return item; })) { // This will after summation of all the times in each array. console.log(item.shift()); } ``` [17:51:47.0988] Handled in-order one must wait 300ms to see the first result. All the operations are handled sequentially taking a total 300 * 2 + 30 * 4 = 720ms. An out of order first come with a task limit of 5 for each step (assume these are network or single worker thread delays) would take 300ms. Even a task limit of 3 would take 300ms. in that example. [17:53:17.0476] * Handled in-order one must wait 300ms to see the first result. All the operations are handled sequentially taking a total 300 * 2 + 30 * 4 = 720ms. An out of order first come with a task limit of 5 for each step (assume these are network or single worker thread delays) would take 300ms. Even a task limit of 3 would take 300ms. in that example. [19:14:51.0935] sirisian: yeah it looks like you're trying to do things with sync iterables of promises, which isn't a concept the language ever really works with, right now. except in like `Promise.all` I guess. [19:45:26.0633] bakkot: https://jsfiddle.net/9xsyev61/ This isn't cursed at all. [19:48:17.0398] sirisian: lol [19:48:32.0482] looks like it dropped some though? I only see a single `1` in the console [19:48:42.0288] oh, wait, that's just the wrapping, sigh [19:49:24.0453] that still only works with finite iterators though [19:49:30.0128] finite underlying iterators, that is [19:49:48.0943] well... maybe it could be made to work with infinite ones, hmm [19:50:04.0017] yes it should be able to. Just pass in the iterator. [19:50:21.0012] take(5) kind of thing then next to get the next work. [19:54:17.0920] oh, but it doesn't compose, because it produces an async iterator rather than a sync iterator of promises [19:54:30.0117] so you can't do it twice with different mapping functions [20:26:43.0079] bakkot: https://jsfiddle.net/xs1brkL8/ Wait, I don't use these much. Can you detect the break in code like that to print "map done"? [20:27:37.0620] sirisian: i don't understand the question [20:32:01.0814] oh, do you mean, the `break` in the bottom loop? yes: it will cause the `yield` to be a `return`, and you can use a try/finally to do cleanup [20:32:12.0243] oh it throws. I see. [20:32:35.0648] it doesn't throw [20:32:40.0165] it puts a `return` [20:32:55.0645] a `finally` will trigger, but not a `catch` [20:33:01.0004] ``` async function* map(tasks, n) { try { // Start n work const parallel = new Set(); for (let i = 0; !tasks.done && i < n; ++i) { parallel.add(makeWork((await tasks.next()).value)); } // Process the work yielding the first one done in the set of n work while (parallel.length != 0 && !tasks.done) { const task = await Promise.race([...parallel].map(t => t.promise)); parallel.delete(task); yield task; // Add 1 more work parallel.add(makeWork((await tasks.next()).value)); } } finally { console.log('map done'); tasks?.return(); } } ``` [20:33:09.0269] * it doesn't throw [20:34:40.0951] https://jsfiddle.net/xs1brkL8/1/ neat, is this composable? [20:35:59.0871] In the actual helper setup it would need to be on the iterator, but that should be fine. I could rewrite it do that I think. [20:37:42.0881] Oh wait, can you modify all iterators to add functions to them. (I know this would be bad). [20:38:03.0832] that's what the iterator helpers proposal is [20:38:35.0528] i.e. adding functions to all iterators (all iterators which inherit from iterator.prototype, anyway) [20:39:00.0566] I can't quite tell if your thing actually composes properly just from staring at it [20:40:36.0623] oh, `!tasks.done` isn't a thing, though [20:41:01.0335] whoops forgot that one. https://jsfiddle.net/xs1brkL8/2/ [20:41:23.0081] * whoops forgot that one. https://jsfiddle.net/xs1brkL8/2/ [20:41:53.0274] I mean can you edit the iterator prototype right now for testing polyfills? [20:41:59.0238] yes [20:42:21.0921] re^, you have to check the `done` property of the result every time you call `.next()` [20:42:38.0857] you have to check `done` before reading `value` [20:43:01.0615] (to obey the iterator contract, anyway; you don't _have_ to but it's going to behave weirdly if you don't) [20:54:36.0579] * whoops forgot that one. ~~https://jsfiddle.net/xs1brkL8/2/~~ https://jsfiddle.net/xs1brkL8/3/ [20:56:37.0542] Wait, how do you edit the iterator prototype? What is it called? [20:57:17.0151] it's called `[].values().__proto__.__proto__` [20:57:53.0631] That's how I know this is a good idea. [21:06:50.0244] Is the async iterator a different one then? [21:07:02.0315] yes [21:11:17.0898] (it's `(async function*(){})().__proto__.__proto__.__proto__`) [21:11:45.0659] ah, I was off one proto [21:24:52.0358] sirisian: ok I looked again and I am pretty sure this implementation will never start the third phase until at least 5 items from the second phase have finished, which I think is not what you intend [21:25:57.0306] where you have `await tasks.next()` you want to instead have a race with that and the existing work queue items, and if one from the work queue finishes you yield it right away [21:26:06.0233] https://jsfiddle.net/xs1brkL8/4/ My current one for reference. Thinking more. [21:26:46.0968] * https://jsfiddle.net/xs1brkL8/4/ My current one for reference. Thinking more. [21:32:32.0990] ah, I think I see what you mean since the iterator can take a while to yield. I'll put a sleep in my makeALotOfWork just to make it more clear also and handle it. [21:33:21.0496] * ah, I think I see what you mean since the iterator can take a while to yield. I'll put a sleep in my makeALotOfWork just to make it more clear also and handle it. [22:29:22.0725] There's no way to get the Promise from Promise.race along with the value without creating another promise right? [22:30:18.0997] * There's no way to get the Promise from Promise.race along with the value without creating another promise right? Like it returns the value, but if you have say 10 promises you don't know what value that promise corresponds to. [22:31:24.0711] * There's no way to get the Promise from Promise.race along with the value without creating another promise right? Like it returns the value, but if you have say 10 promises you don't know what promise that value corresponds to. [00:40:31.0385] * https://jsfiddle.net/xs1brkL8/4/ My current one for reference. Thinking more. Updated: https://jsfiddle.net/xs1brkL8/9/ [00:41:53.0081] * https://jsfiddle.net/xs1brkL8/4/ My current one for reference. Thinking more. Updated: https://jsfiddle.net/xs1brkL8/10/ [05:19:52.0204] I made a few concurrent async iterable helpers at https://github.com/jridgewell/minx/blob/main/src/async-iterable-concurrent.mjs [05:40:50.0426] Why does tc39.es not host ECMA-404? [05:47:35.0893] That is probably just an oversight.. [06:45:38.0668] yulia: ta, filed https://github.com/tc39/tc39.github.io/issues/283 to track [06:46:01.0823] > <@annevk:mozilla.org> yulia: ta, filed https://github.com/tc39/tc39.github.io/issues/283 to track thanks, we are discussing it in #tc39-website:matrix.org [06:46:24.0717] we don't seem to have an html source anywhere -- i think it predates that [06:46:28.0951] so we likely need to write that up [06:46:36.0924] We will get in touch with Chip [06:47:04.0128] for now we might just host the pdf under the usual url [06:47:09.0788] I figured that might be part of the problem, but PDF could be linked until hosting is sorted in the future [06:47:16.0865] yeah [08:05:47.0044] sirisian: you can get substantially simpler, I think: https://gist.github.com/bakkot/6bee327466c06887d96a65f88f4cf728 [08:14:36.0849] though I notice there's another way this could be configurable, which is, there is both "number of tasks running in the mapping function" and "number of unsettled promises read from the underlying iterator", and those don't actually need to be the same number [08:15:21.0322] in my gist I have it so that the sum of those two numbers is `n`, but they could reasonably be independently configured [08:23:25.0670] Justin Ridgewell: hmm, I wonder if we should make iterator helpers work like your mapper... [08:23:51.0676] probably not I guess? it would maybe be surprising. [08:25:14.0756] though I guess you're only exposed to the difference if you're manually pumping the iterator rather than just using `for await` [08:33:42.0421] It’s really difficult to reason about my way. [08:34:03.0222] You can get a done message before all the previous messages have completed [08:34:55.0479] I had to write the cap iterator to help me reason about the end states when using the map and interleave [08:35:57.0307] Even map, you have to be aware of reentrancy during any async portions, which was difficult [08:37:02.0414] I do not recommend we make standard iterators that behave this way [08:37:22.0289] Backpressure may be slow but it has a very predictable result [08:38:37.0555] Yeah, sounds good. [08:39:19.0367] Staring at this async code above has been making my head hurt also. Which says there's maybe a place for the language to help out, but as a power tool, not one of the simple helpers. [08:41:03.0320] * Backpressure may be slow but it has a very predictable ordering [10:14:09.0391] bakkot: Very nice and compact. Also your idea about separating n above is excellent. These problems are definitely fun little puzzles to think about. Your use of first is nice. I asked a question yesterday, but deleted it, about getting the promise instance from a Promise.race when was thinking about things. [10:14:54.0886] * bakkot: Very nice and compact. Also your idea about separating n above is excellent. These problems are definitely fun little puzzles to think about. Your use of first is nice. I asked a question yesterday, but deleted it, about getting the promise instance from a Promise.race when was thinking about things. [10:24:03.0867] * bakkot: Very nice and compact. Also your idea about separating n above is excellent. These problems are definitely fun little puzzles to think about. Your use of first is nice. I asked a question yesterday, but deleted it, about getting the promise instance from a Promise.race when was thinking about things. ( https://jsfiddle.net/zu261h3s/ Pasted your solution into a polyfill kind of implementation) [11:23:49.0335] * bakkot: Very nice and compact. Also your idea about separating n above is excellent. These problems are definitely fun little puzzles to think about. Your use of first is nice. I asked a question yesterday, but deleted it, about getting the promise instance from a Promise.race when was thinking about things. ( https://jsfiddle.net/yt5n4gLd/ Pasted your solution into a polyfill kind of implementation) 2022-04-21 [20:06:00.0510] Looking at https://github.com/mdn/content/issues/15129 — in general in MDN articles where we’re describing a case where some JavaScript data type gets coerced into another data type, any recommendations on what term we should use? _“an x gets cast to a y_”, or _“an x gets converted to a y”_, or _“an x gets coerced into a y”_? or what? (this particular case is about the _delay_ parameter of `setTimeout()` being coerced into a number) [20:07:06.0624] * Looking at https://github.com/mdn/content/issues/15129 — in general in MDN articles where we’re describing a case where some JavaScript data type gets coerced into another data type, any recommendations on what term should we use? _“an x gets cast to a y_”, or _“an x gets converted to a y”_, or _“an x gets coerced into a y”_? or what? (this particular case is about the _delay_ parameter of `setTimeout()` being coerced into a number) [20:07:34.0726] * Looking at https://github.com/mdn/content/issues/15129 — in general in MDN articles where we’re describing a case where some JavaScript data type gets coerced into another data type, any recommendations on what term we should use? _“an x gets cast to a y_”, or _“an x gets converted to a y”_, or _“an x gets coerced into a y”_? or what? (this particular case is about the _delay_ parameter of `setTimeout()` being coerced into a number) [20:07:36.0587] "coerced" is the term I personally use [20:07:54.0729] The spec doesn't use the verb "cast" at all. [20:08:43.0503] this is also the word used in at least some education materials, looks like [20:08:48.0869] > <@jmdyck:matrix.org> The spec doesn't use the verb "cast" at all. OK yeah then I think we should avoid “cast” in MDN [20:09:04.0674] e.g. https://eloquentjavascript.net/01_values.html > When an operator is applied to the “wrong” type of value, JavaScript will quietly convert that value to the type it needs, using a set of rules that often aren’t what you want or expect. This is called type coercion. [20:09:31.0646] It does use "coerce" some, but it uses "convert/conversion" a lot more. [20:09:31.0666] though that's in a section called "automatic type conversion", not "... coercion", so somewhat inconsistent [20:10:28.0841] also e.g. https://exploringjs.com/impatient-js/ch_values.html#coercion-automatic-conversion-between-types [20:10:31.0931] OK, I see now we actually have https://developer.mozilla.org/en-US/docs/Glossary/Type_coercion in MDN [20:11:05.0667] > Type coercion is the automatic or implicit conversion of values from one data type to another (such as strings to numbers). _{{Glossary("Type conversion")}}_ is similar to _type coercion_ because they both convert values from one data type to another with one key difference — _type coercion_ is implicit whereas _type conversion_ can be either implicit _or_ explicit. [20:12:39.0527] So if a particular case is implicit, how are you supposed to decide if it's coercion or conversion? [20:13:20.0853] dunno… [20:16:17.0279] Hm, some of the spec's uses of "coerce" are not implicit. e.g. "A String object can be coerced to a String value by calling the String constructor as a function" [20:18:18.0012] I *think* the spec is using "coerce" and "convert" interchangeably. [20:57:24.0878] They’re likely used interchangeably in MDN articles as well — I doubt most MDN contributors make the distinction 2022-04-22 [07:25:05.0465] proposal idea: python has `raise Exception from CauseException` syntax. I like this because it would let you set causes even on random error subclasses that don't pass the options through. [07:26:04.0451] might write something up 2022-04-24 [18:25:57.0936] comments on https://github.com/mdn/content/pull/15271 welcome either there or here [01:20:13.0056] looking at https://github.com/mdn/content/issues/15203, should `Symbol` also be included in the list _“`String`, `Array`, `TypedArray`, `Map`, and `Set` are all built-in iterables, because each of their prototype objects implements an `@@iterator` method.“_? (I guess the list is also missing `Intl.Segments`) [02:39:19.0496] `Symbol` doesn’t implement @@iterator. `Symbol.iterator in Symbol.prototype === false` [02:48:55.0250] Though I did make this mistake recently when I wrongly wrote ``` isWellKnownSymbol = v => typeof v === 'symbol' && Reflect.ownKeys(Symbol).includes(v); ``` 🤦🏻‍♂️ [09:48:38.0816] it’d also have to be a frozen property, and you’d want to cache that list as early as possible [10:14:49.0412] yep, I was miles off. Got it in the end: https://gist.github.com/acutmore/0a5bf0f35785edfe3c17e1f6d05e8921 2022-04-25 [12:13:54.0854] Ashley Claymore: nice! yours doesn't handle boxed symbols, and the Intl fallback symbol has a different description in older engines (because the intl spec didn't define the description in the 4th edition), so i went ahead and made https://npmjs.com/is-registered-symbol and https://npmjs.com/is-well-known-symbol and https://npmjs.com/intl-fallback-symbol :-p 2022-04-28 [08:08:19.0217] Is there a reason why the destructuring pattern `{...{}}` is disallowed with an early error, while `[...{}]` is allowed? [08:20:06.0518] `[…{ length }] = [1, 2]`? [08:44:10.0162] Oh it makes sense [08:44:59.0704] The inconsistency annoys me, but I cannot think of a real reason to allow it in object destructuring (maybe "I want to trigger every getter"?) [09:33:20.0992] `({...foo})` ? [09:33:56.0846] But that will get removed by virtually all optimizers [10:11:32.0768] not a correct one [10:12:09.0567] there's a bunch of annoying places parens are required around an object literal, i assume because of the ambiguity with block statements [10:12:15.0635] * there's a bunch of annoying places parens are required around an object literal, i assume because of the ambiguity with block statements [12:56:54.0265] I meant a standalone "assumed no side effect" expression like this will often get removed by minifiers, the same way `foo.bar` will. Basically if the goal is to "trigger getters", minifiers will usually get rid of any such constructs. [13:52:59.0780] I’d still call that a broken minifier [13:53:15.0602] similar incorrect expectations caused rollup to break Airbnb.com on IE for a month, a few years back [13:53:16.0196] they all are ;) [14:26:28.0188] I feel like, if I could get away with breaking IE support for a month without getting angry phone calls, I would do it and then tell management it's clearly not actually important to support [14:26:58.0436] unfortunately we do actually see nontrivial traffic on IE9 and I have in fact gotten angry phone calls for breaking it, sigh [14:27:02.0282] or, well, angry slack messages [14:27:24.0761] * I feel like, if I could get away with breaking IE support for a month without getting angry phone calls, I would do it and then tell management it's clearly not actually important to support [14:41:45.0210] i mean, to be fair this was in like 2018 when IE was still in much, much wider usage [14:42:02.0506] but yeah even now IE needs to be supported far more than trendy devs want to admit 2022-04-29 [04:06:35.0022] https://twitter.com/MSEdgeDev/status/1512091320596246531 perhaps those angry customers need to assess their own house. [12:06:36.0616] i think that actually, platform owners need to reevaluate how much it actually matters that they say they're dropping support for something :-) what matters is what people use; not what's supported (altho that might drive the usage) [12:26:22.0495] afaik ie9 is only ever used under duress [12:26:29.0360] some companies require it on their corporate machines, still [13:07:23.0130] over the years I’ve encountered a number of older folks without computer-savvy descendants that have old computers and old browsers and don’t know how to update, and “evergreen” is a lie even if they start with an alleged evergreen browser. 2022-04-30 [18:56:43.0925] Very lucky our product only supports the latest 3 versions + Firefox 99 + iOS 14 [18:58:07.0229] we still have tacit support for IE11 (we try to keep JavaScript from crashing and do the autoprefixer motions but don’t actually care about the CSS or layout)