2024-05-03 [01:36:35.0790] Hongbo is suggesting the iterator protocol has a high performance overhead (25x perf loss). Do we know if this is cost is effectively mandated in the spec, or is this just a unfulfilled optimization opportunity in engines? https://www.moonbitlang.com/blog/js-support#benchmark-code-execution-speed-exceeds-javascript-by-25-times [02:35:57.0697] My hope is that engines could optimize Array iteration, but I'm not sure about other cases [02:45:57.0326] With something like iterator helpers, engines could theoretically optimize some parts of iteration knowing the shapes of the inputs and the whole of the graph of iteration operations. It's no small task, though, as it requires verifying that no intermediate steps are observable (proxies, user-defined iterators, patched methods, etc.). [07:59:25.0036] Engines brought up the overhead of the iteration protocol at the most recent TC39 meeting, as a source of hesitation for the pattern matching proposal's semantics [08:00:16.0499] engines *sometimes* can reduce or eliminate the overhead in particular cases (e.g., for-of loops over Arrays, as long as you didn't mess with Array.prototype too much) but these optimizations are fragile and difficult to generalize [08:00:47.0160] I think if we were to do the iteration protocol today, we'd do it differently. But at this point, it'd be expensive to have multiple iteration protocols... [08:01:10.0893] see some discussion earlier: https://matrixlogs.bakkot.com/TC39_Delegates/2024-04-25#L21 [08:02:18.0535] that said there is a lot of room for optimizing iterators, in many cases without much in the way of performance cliffs [08:02:36.0702] it's just a lot of work [08:09:20.0345] (also it is extremely unlikely to ever be as fast as a bare loop, even with a huge amount of work) [08:16:24.0663] if we are interested in making iterator helpers faster, something we _could_ do is make all the `{ next, done }` pairs yielded by a given call to an iterator helper be the same object [08:16:54.0739] * if we are interested in making iterator helpers faster, something we _could_ do is make all the `{ value, done }` pairs yielded by a given call to an iterator helper be the same object [08:18:50.0345] so like ```js function map(fn) { let result = { value, done }; // probably with those properties being non-configurable let underlying = this; return { next() { let { value, done } = underlying.next(); if (!done) value = fn(value); result.value = value; result.done = done; return result; } } } ``` [08:19:06.0588] this would avoid most of the overhead and no one would ever notice [08:19:14.0911] but it is, as littledan indicates, conceptually quite gross [08:46:42.0117] > <@robpalme:matrix.org> Hongbo is suggesting the iterator protocol has a high performance overhead (25x perf loss). Do we know if this is cost is effectively mandated in the spec, or is this just a unfulfilled optimization opportunity in engines? > > https://www.moonbitlang.com/blog/js-support#benchmark-code-execution-speed-exceeds-javascript-by-25-times Both? The iterator protocol imposes a lot of complexity; some of that complexity can be optimized through heroic work in JS engines (and has been!)... but the heroics mean that it's costly to do, particularly in any generalizable fashion. I haven't looked at Iterator Helpers in a long while, but I'll bet they could certainly have more optimization applied over time, but I suspect a similar story applies: Could we make them faster? Sure, but that work displaces other work, and so we need to see it as important enough. [08:56:27.0036] by coincidence I just read an article which touches on performance of array destructuring, which is the same problem https://www.figma.com/blog/figmas-journey-to-typescript-compiling-away-our-custom-programming-language/#performance-issues-with-array-destructuring [10:07:20.0884] down with iteration protocol [10:16:10.0365] if only we said "iterables can't contain undefined", then we would have .next() simply return undefined when it's done. Problem solved! [10:16:33.0963] > <@bakkot:matrix.org> if we are interested in making iterator helpers faster, something we _could_ do is make all the `{ value, done }` pairs yielded by a given call to an iterator helper be the same object i feel like how you react to this is like "inside you are two wolves" [10:30:57.0781] * if we are interested in making iterator helpers faster, something we _could_ do (along the lines of Keith's suggestion I linked above) is make all the `{ value, done }` pairs yielded by a given call to an iterator helper be the same object [10:50:18.0281] is this like, inside you there are two iterator results, one is the object x, and the other is also x, you are x ? [11:21:54.0209] savaged again by copy-by-reference! [11:31:59.0801] JS is always pass by value, though :-) [11:41:33.0411] tfw reference is value 2024-05-04 [17:54:05.0643] this moonbit thing is interesting https://github.com/moonbitlang/moonbit-docs [17:54:13.0252] they really bury their docs though [17:54:29.0112] ""docs"" [11:04:32.0967] anyone have further feedback on https://github.com/tc39/proposal-regex-escaping/pull/77? otherwise I think it's ready to go cc ljharb 2024-05-05 [10:37:49.0245] It could even have just been a `Symbol.done` sentinel value 2024-05-09 [06:17:48.0525] I opened a PR for Notes! And added a basic-ass summary! 2024-05-10 [22:38:06.0428] couple people in this random reddit thread assuming that `x?.y = z` is legal, if anyone wants to pick that proposal up https://old.reddit.com/r/programming/comments/1cmccyh/i_built_an_opensource_library_to_automatically/l30559c/ [00:22:02.0361] Did it get explicitly dropped? [00:23:20.0090] from the original proposal, kinda: https://github.com/tc39/proposal-optional-chaining/issues/18#issuecomment-343926065 [00:23:38.0196] since then I have heard people express interest but I don't think there's anything concrete [00:26:57.0654] Oh that was years ago in the original Optional Chaining. A new effort started about a year ago to do this as a standalone proposal. [00:28:19.0751] https://github.com/tc39/proposal-optional-chaining-assignment Updated 4 months ago. [00:28:44.0483] oh neat [00:28:47.0541] I have no recollection of this [00:29:07.0602] so I guess cc nicolo-ribaudo as champion, evidence from the wild that people expect this to exist ^ [00:39:12.0115] Thanks, it's not the first time I see people assuming that it exists (that's why I brought it up) — I didn't work on the stage 1 feedback because I had higher priority stuff to do, but I'll see if I can find some time [00:39:23.0377] (and I'd be happy to add a co-champion) 2024-05-11 [18:34:17.0498] ljharb: i would appreciate it if you do not speak for browsers' motivations in issues. you can quote things or summarize we say, but please don't present a position, especially on "browsers" as a whole, as matter of fact [18:34:26.0905] * ljharb: i would appreciate it if you do not speak for browsers' motivations in issues. you can quote things or summarize what we say, but please don't present a position, especially on "browsers" as a whole, as matter of fact [19:08:19.0609] fair, I’ll edit my comment [19:08:56.0874] can you link me? It’s not easily findable rn [20:03:11.0710] * k, updated to not speak as absolutely, but if my summary of your position is incorrect a clarification would be helpful. [20:29:28.0898] > <@ljharb:matrix.org> fair, I’ll edit my comment thank you [20:30:09.0894] lmk if you’d like it modified more 2024-05-14 [12:19:41.0637] can we get a Helsinki room created? 2024-05-15 [11:10:48.0749] Of course. The [TC39 in Helsinki room](https://matrix.to/#/!eYtJlOBqHCxsUknCCE:matrix.org?via=matrix.org&via=mozilla.org) for in-person coordination (e.g. "who wants to find a karaeoke bar?", "how do I travel from the airport?") is now created. Ask a chair to invite you if you have not already received an invite. [11:11:07.0390] * Of course. The [TC39 in Helsinki room](https://matrix.to/#/!eYtJlOBqHCxsUknCCE:matrix.org?via=matrix.org&via=mozilla.org) for in-person coordination (e.g. "who wants to find a karaoke bar?", "how do I travel from the airport?") is now created. Ask a chair to invite you if you have not already received an invite. 2024-05-17 [14:31:38.0198] rbuckton: (or anyone else who is a grammar expert): i don't understand the `await using` cover grammar [14:32:28.0479] the stage 3 spec draft has this: [14:33:17.0892] CoverAwaitExpressionAndAwaitUsingDeclarationHead and AwaitExpression are exactly the same. how can you refine a grammar with the same grammar? [14:38:26.0988] the intention must've been that `await using x` in StatementItemList position is parsed in its entire 3 tokens by AwaitUsingDeclaration instead of the first 2 tokens by AwaitExpression, but i don't think you can express that by having a cover grammar for the first two tokens only [14:38:31.0387] i don't know how else to express this though [14:39:01.0242] or wait, is that how cover grammars work? [14:42:31.0272] It works the same way as `CoverCallExpressionAndAsyncArrowHead`, which refines to `CallMemberExpression` (which is identical) [14:46:50.0299] The difference is that you can parse the cover in places you can't parse AwaitExpression on its own, such as `await using x`. `await using` isn't a legal AwaitExpression if an identifier follows it on the same line, but its parse can be reused for AwaitUsingDeclaration [14:48:01.0138] Just like `async(x)` is a valid call expression as long as it's not followed by a `=>` [14:48:12.0114] * Just like `async(x)` is a valid call expression as long as it's not followed by a `=>` (or any other illegal token) [14:48:20.0009] oh huh, i see [14:49:42.0176] The cover is essentially eagerly parsing out the syntax. Some covers allow more tokens than what any single refinement might use, but that isn't always the case. [14:51:15.0002] i'm trying to understand why this can't be expressed as AwaitUsingDeclaration: `await` [ntl] `using` [ntl] BindingList without a cover [14:57:55.0817] it's still the case that there's no valid parse of that sequence of tokens with an AwaitExpression [15:00:16.0196] Given the source text `await using x = y`, you have two potential parses for `await using`: An _ExpressionStatement_ containing an _AwaitExpresion_, or a _LexicalDeclaration_ containing an _AwaitUsingDeclaration_. You have to consider both parses as equally viable until they are not. For _ExpressionStatement_, you descend through _Expression_ to parse `await using`, but _ExpressionStatement_ must end in a `;`. Since `x` is not `;`, it's not a valid _ExpressionStatement_. For _LexicalDeclaration_, you can parse `await using` followed by an identifier and that matches an _AwaitUsingDeclaration_. It's only after both of these potential parses fails that ASI is considered, and a `;` would only be inserted after `await using` if there was a line terminator before the `x`. [15:01:06.0949] Given the source ``` await using x = y ``` The same process occurs, except the NLT restriction means AwaitUsingDeclaration isn't a valid parse in that case [15:04:38.0820] ah, it's ASI [15:04:39.0501] got it [15:04:40.0566] * Given the source text `await using x = y`, you have two potential parses for `await using`: An _ExpressionStatement_ containing an _AwaitExpresion_, or a _LexicalDeclaration_ containing an _AwaitUsingDeclaration_. You have to consider both parses as equally viable until they are not. For _ExpressionStatement_, you descend through _Expression_ to parse `await using`, but _ExpressionStatement_ must end in a `;`. Since `x` is not `;`, it's not a valid _ExpressionStatement_. For _LexicalDeclaration_, you can parse `await using` followed by an identifier and that matches an _AwaitUsingDeclaration_. It's only after both of these potential parses fail that ASI is considered, and a `;` would only be inserted after `await using` if there was a line terminator before the `x`. [15:04:50.0648] well that's also fucking terrible [15:06:27.0285] In TypeScript I just do two token lookahead. If I'm on `await` and the next token is `using`, I check that the token that follows it is not an Identifier on the same line. [15:08:32.0939] We try to say that ECMA262 is LR(1), but we have a single two-token lookahead with `` [ lookahead != `let` `[` ] `` for _ExpressionStatement_ that violates that. [15:10:43.0845] Maybe we could have done the same for AwaitExpression (i.e., `` `await` [lookahead != `using` Identifier] UnaryExpression ``), but I don't think we want _more_ two-token lookahead. [15:11:14.0078] * Maybe we could have done the same for AwaitExpression (i.e., ```await` [lookahead != `using` Identifier] UnaryExpression``), but I don't think we want _more_ two-token lookahead in ECMA262. [15:17:15.0357] well [15:17:29.0759] it seems likely an implementation will use two-token lookahead to implement this cover [15:17:35.0267] why obscure reality? 2024-05-18 [17:08:53.0917] * Maybe we could have done the same for AwaitExpression (i.e., `` `await` [lookahead != `using` Identifier] UnaryExpression `` ), but I don't think we want _more_ two-token lookahead in ECMA262. [17:13:52.0614] The LR(1) goal/requirement predates my involvement at TC39 and has been strongly held by many delegates for well over a decade. I can't speak to their reasoning. [17:21:23.0637] "many" is a strong word