diff --git a/meetings/2025-07/july-28.md b/meetings/2025-07/july-28.md index d24cd60..b4dc2dd 100644 --- a/meetings/2025-07/july-28.md +++ b/meetings/2025-07/july-28.md @@ -1111,4 +1111,4 @@ CDA: All right. Nothing else on the queue. This was a short update on what changed on the web integration side since the May plenary. No decisions were made. -[image2]: +[image2]: data:image/png;base64,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 diff --git a/meetings/2025-11/november-18.md b/meetings/2025-11/november-18.md new file mode 100644 index 0000000..ac3ac8c --- /dev/null +++ b/meetings/2025-11/november-18.md @@ -0,0 +1,1928 @@ +# 111th TC39 Meeting + +Day One—18 November 2025 + +**Attendees:** + +| Name | Abbreviation | Organization | +|----------------------|--------------|--------------------| +| Waldemar Horwat | WH | Invited Expert | +| Richard Gibson | RGN | Agoric | +| Josh Goldberg | JKG | Invited Expert | +| Ruben Bridgewater | RBR | Invited Expert | +| Dmitry Makhnev | DJM | JetBrains | +| Frank Yung-Fong Tang | FYT | Google | +| Anthony Fu | AFU | Vercel | +| James M Snell | JSL | Cloudflare | +| Daniel Minor | DLM | Mozilla | +| Jonathan Kuperman | JKP | Bloomberg | +| Christian Ulbrich | CHU | Zalari | +| Marina Aisa | AIS | Apple | +| Martin Alvarez | MAE | Huawei | +| Ashley Claymore | ACE | Bloomberg | +| Andreu Botella | ABO | Igalia | +| Devin Rousso | DRO | Invited Expert | +| Jake Archibald | JAD | Mozilla | +| Lea Verou | LVU | OpenJS | +| Mathieu Hofman | MAH | Agoric | +| Caio Lima | CLA | Igalia | +| Yusuke Suzuki | YSZ | Apple | +| Chip Morningstar | CM | Consensys | +| Aki Rose Braun | AKI | Ecma International | +| Philip Chimento | PFC | Igalia | +| Eemeli Aro | EAO | Mozilla | +| Mikhail Barash | MBH | Univ. of Bergen | +| Keith Miller | KM | Apple | +| Ross Kirsling | RKG | Sony | +| Chris de Almeida | CDA | IBM | +| Nicolò Ribaudo | NRO | Igalia | +| Ron Buckton | RBN | F5 | +| Shane F Carr | SFC | Google | +| Istvan Sebestyen | IS | Ecma | +| Daniel Rosenwasser | DRR | Microsoft | +| Stephen Hicks | SHS | Google | +| Ujjwal Sharma | USA | Igalia | +| Guy Bedford | GB | Cloudflare | +| Chengzhong Wu | CZW | Bloomberg | +| Gus Caplan | GCL | Deno | +| Jordan Harband | JHD | Socket | +| Justin Ridgewell | JRL | Google | +| Kevin Gibbons | KG | F5 | +| Michael Ficarra | MF | F5 | +| Mark S. Miller | MM | Agoric | +| Olivier Flückiger | OFR | Google | +| Rob Palmer | RPR | Bloomberg | + +## Opening & Welcome + +Presenter: Rob Palmer (RPR) + +RPR: All right, we’re about to begin. Logged in on the Zoom. Let me bring up my slides. Okay, let’s see, here we go. All right, welcome, everyone, to the 111th meeting of TC39 here at Bloomberg in Tokyo, yay! So a lot of energy in this room. And in particular, welcome to everyone who has flown here. I think people have come from far away, and in particular, I know we’ve got a number of first-time meeting participants, so special welcome to you all. So yeah, we’re here in Tokyo. It seems a particularly attractive destination, and I’ll say that because we were here two years ago, we had 25 people. This time we’ve had I think 43 sign-ups, so that is great, and being in person is a key part of having that as an element of the committee and is a key part for ensuring good relations and ensuring we all understand each other, so I have some fun facts here about Tokyo. Other than it being the largest metropolitan area on earth, the home of modern sushi, and there’s very good reasons for why the Tokyo tower is painted orange, to be safe. Where is the cat bus? It is—I’m guessing it will be related to the studio jibly park or museum. Chris is messing we many. He told me it was pronounced jibly, and I don’t know if gibly or jibly. It’s the ever ending… Okay, it is jibly, thank you. All right, so to help run these meetings, we have the chair group, so that consists of myself, I’m Rob. We have Chris here, and remotely we have Ujjwal. We’re assisted by our facilitators Justin, Daniel here, Dan Minor, and Daniel remotely. I should also say a few things about our facilities here today in Bloomberg for, if you need the restroom, the men’s is down the hallway and there’s a sign pointing to the left, and the women’s is here just by the meeting room exit there. If you do need to take a call or you’d like some audio privacy, the room over there is not technically reserved for us, but if you see it’s empty, please feel free to use it. And then in case of any kind of emergency, the fire exits you’ll see are lit up with green signs over there and over there. Yeah, I think that’s it. And please do take a look at the views out the window. It’s particularly good. Today everyone here obviously has signed in as registered to be in person, but please make sure you also sign in for the Zoom video feed as well. The reason is that that helps with all of our records. We have a code of conduct, which you can find links from the [TC39.es](http://TC39.es) repo. Please do have a read of it, and also remember it’s—we’re not trying to follow it to the letter. We’re also trying to respect the spirit of the code of conduct as well. Chris sums it up as be excellent to each other, which I think is a good way to live. Our daily schedule means that the meeting begins at 10, now, and will end at 5 p.m. each day, apart from Thursday, when we will end a little bit earlier at 4 p.m. One thing to note about this—our timings this week is that we have a significant amount of agenda overflow. People seem to have been very keen to bring a lot of work to this meeting, so I appreciate that. And the Chairs are going to try and make sure we get through as much of a as possible. Wherever we finish before the time box, that will always be appreciated, and one of the ways that you can help to think, when it comes to the discussion phase, to try and be mindful of how long your contribution to that is taking, and, for example, whether that level of discussion is the appropriate thing to be focusing on at this—at whatever stage a given proposal is. So we’re really going to do our best to keep to time. So that also means that possibility for continuations, as we have done in previous meetings, is unlikely. We shall see. But, yeah, there’s significantly more on the agenda than capacity we have. In terms of events, I guess a number of people have already been to prior events up to this, so we’ve had TPAC and JS con at the weekend and the TG5 meeting in this room yesterday, which was lent. For the coming week, on Wednesday, we have our social dinner. Everyone who has registered for—as an ECMA member, as a regular delegate here, is entitled to come. Invited experts and so on. I’m just making a differentiation between the observers as well. And please let me know if you are not coming, because the restaurant needs to be precise on numbers. So that will be on Wednesday from 6:30. And you can see there on the map it’s not too far away. In terms of meeting participation and how we work, we have various tools to ensure good communications. The main pool here is TCQ, and that tool has been recently refreshed by Christian here. Thank you so much. It’s one of our essential tools that we’re very proud of and helps us keep the discussion on track. So you’ll see once the agenda is running, when we’re participating, this is the view that you’ll see for the current topic. And you’ll see that there are four buttons you can use to participate in the discussion. Try to keep things linear and orderly, so one at a time. If you are speaking, if you are on the queue and it’s your turn, you’ll see this button, I’m done speaking. We—chairs normally ask people not to use the button. This is the button of do not push this. Oh, okay, all right. Well, there is—TCQ has been updated to remove the button, so temptation has been removed. Thank you, Christian. I assume that was you. And when it comes to those buttons, normally you want to prefer the buttons on the left, so new topic is the most natural and orderly way of adding new topics. If you do want to reply, then you can use discuss current topic. Likewise, with slightly more urgency like clarify something, we treat that with higher priority. And the highest priority one, the red, point of order, is for emergency situations such as note taking has broken, such as the internet is down or some kind of other high priority issue that you want to bring to the Chair’s attention. We also have Matrix for asynchronous and realtime chat. Links to this are on the reflector invite, and the main channel you will want to be joining is TC39 delegates. That is the primary place where work gets done. And then the secondary channel is the Temporal dead zone, which is where work does not get done, and you might see some off topic things. As part of ECMA, we have an IPR policy. If you’re part of an ECMA member company or member organization, and you are a delegate, you will have already signed the appropriate materials there. Likewise, people who have completed the invited expert process, you are equally covered by the forms that you will have signed as part of that. For anyone else, we ask that you do not speak. And please let us know if you’re not in that category and have not already signed the RTFG form, please do so. So that normally applies to observers. All right. We take notes of everything that happens in the meeting. This is transcribed live. We have a transcriptionist. I should check, is the transcriptionist on the call? + +>> Yes, I’m here. + +RPR: Excellent. Thank you, Julie. And we also need people to help fix up these notes live. I’ll get to that. And I will also read out our disclaimer that a detailed transcript of the meeting is being prepared and be eventually posted on GitHub. You may include at any time for accuracy, and may also corrections and deletions in the first two weeks after the TC39 meeting or subsequently making a PR in the notes repository or contacting the TC39 chairs. One of the ways you can really help in this meeting, something that everyone will be happy if you do, is to assist us with taking these notes. So this is—this work is really just working on a Google doc that you can get from the invite. And the actual task is only to make small corrections if you see them of what the main transcription is taking. This is what you think will better reflect the content, and another key part of that is the attributions, which is tagging the notes with the three letter acronym of whoever is speaking. You can find everyone’s TLAs, everyone’s designations in the delegates.text, which is part of the notes repository on GitHub, not jit hub, Chris. The next meeting is the 112th meeting. This runs for three days in January. It a remote meeting on UTC -5. The full agenda for the year is published on the reflector as well. So let us begin with one of the most important things, as I’ve said, we look for notetakers to assist us. Please could I get a couple of volunteers to begin that for this session. Straight away, we’ve got Christian and RBR with hands up. Thank you so much. We show our appreciation for the notetakers as much as we can. If there were swag, you would get some. We should also check for the previous meeting. So the minutes have been published and merged, the notes repo. Please can I ask are there any objections to the minutes for the previous meeting? We have silence, so I’ll record that, that the previous minutes are approved. Next up, the—for this meeting and the current agenda that is set out, are there any comments on that? Okay, we have a comment from NRO on the current agenda. + +NRO: There are two topics on the agenda for stage advancement, `Object.propertyCount` and `Object.getNonIndexStringProperties`. Both going for stage advancement. They both have been presented two meetings ago. They both have been rejected two meetings ago, and there’s been no updates to the proposal, so it is impossible to tell what the committee is going to be asked for. We tried reviewing this proposal, and just we also look at the requests, and the issues, and we couldn’t figure it out. I’m happy to discuss the proposal, but it would be difficult to have a position on the stage advancement. + +RPR: Okay, so those items remain on the agenda, but that’s a comment about our regular procedure that we like people—we aim to get all the materials on the agenda, and advertise ahead of time. All right, any objections to the current agenda? No, okay. Then we will adopt that. All right, first up, then, Aki, are you ready with the secretary’s report? + +AKI: Yeah, I’m ready. Can I steal the screen sharing? + +RPR: Please, go ahead. + +## Secretary's Report + +Presenter: Aki Rose Braun (AKI) + +* [slides](https://github.com/tc39/agendas/blob/main/2025/tc39-2025-049-Rev1.pdf) + +AKI: All right, hello, even. I’m Aki, and I’m here representing the Ecma secretariat. Samina sent her regards and wishes she could be here but incidentally she is receiving an award right now and wasn’t able to attend. So she sends her regards and—oh, yeah, and her chocolate. I have two bags of Swiss chocolate that I have been carrying around since I was in Switzerland in October, and I hope you all really enjoy them, because I’m not taking them back. + +AKI: So some notes from the secretariat. The Ecma general assembly is in December, and there are a ton of new standards. There’s a new TC. We also want the kind of talk about some planning stuff ongoing for FOSDEM and JSON schema. There’s going to be a vote today, which I know makes us all itchy, but we’re going to do it, and I hope you all do download these slides and look at them later, because the annexes are something everyone should review, but I’m not going to read them verbatim to you. + +AKI: The 2025 December general assembly has 13 new drafts that we are approving as standards. Ecma is, like, at warp speed right now, and I am pretty excited about it. Ecma standardizes a lot of things around technology, and one of things is how much noise computer equipment is allowed to make. Think hard drives clicking kind of thing, or hard drives whirring I should say. That kind of thing Ecma has long been the standard bearer for how much computers are allowed to make. There’s some new ones. There’s also an update to the CD-ROM standard. But perhaps more relevant to this crowd, ECMA-424 is going to its second edition, CycloneDX v1.7. That’s going to go to ISO-IEC/JTC1 for Fast Track approval and that will be an international standard. And TC54’s PURL package URL, which doesn’t have a number yet, is also going to go to ISO-IEC/JTC1 for fast track submission. And the common life cycle enumeration from TC54, spearheaded by JHD, is also going to be approved at the GA. There’s a whole bunch of new AI natural language interaction standards that—and this is surprising to none of you—I have not really looked into that much, because it’s not really my thing, but I’m sure it’s great. And then the Minimum Common Web API from WinterTC is going to be approved—so WinterTC is going to have its first standard, congrats to ABO (and LCA who is not on the call because it’s a terrible hour right now). So we have a whole bunch. It is more than I’ve ever seen. We have a new TC that’s the HLSL technical committee, high level shared language. Microsoft and I believe Apple were the main impetus, but we also have Meta and Sony and Google participating and UC Santa Cruz. If any of you all have any part of your company who might be interested in this, you should let them know this is happening, because I already think we have the players for it to be successful, and, therefore, everyone should make sure that their voice is heard so it’s not just the biggest players who get to say what this specification looks like. Oh, yeah, and also this is going to be another royalty-free technical committee. So almost every TC that’s been chartered in the last ten years, 11 years, maybe every TC has been royalty-free. Nice influence, TC39. + +AKI: Outreach at FOSDEM 2026 in Brussels, we expect there will be an Ecma session and expect to work with OWASP to have some sort of event regarding software transparency. If anybody is attending FOSDEM, you should let us know. If anybody wants to be involved in anything Ecma- related at FOSDEM, you should let us know. I will be there, Samina will be there. And I think several people from TC54 will be there. + +AKI: We continue to discuss the JSON schema task group for the approved and not yet chartered Schema Language & Structured Data Technical Committee. We’re just making sure that everybody has signed the IPR agreement and everybody feels comfortable with what they’re agreeing to—which is not giving up anything, but rather allowing Ecma to use their copyright and use their license. And we’re also working directly with IETF to make sure that any standardization that happened on this in IETF can also be ongoing without any IPR issues, for which IETF has been super supportive. They’ve been great. + +AKI: And so as I mentioned, make some time to check the annex. We go through the code of conduct, the invited expert policy—I think everyone would benefit from being familiar with it for the next time an invited expert invitation comes up. The annex also includes a list of the latest documents. There’s so much that the GA publishes that it’s valuable to read through the titles and just see if any of this matters to you, especially if you know which TC is which, which I understand if you don’t. + +AKI: Yeah, lots of action going on in ECMA right now. + +AKI: And the chairs have just published the 2026 schedule in the last two weeks. For in-person meetings, the current plan is that Samina will be in New York, we’ll both probably be in Amsterdam. Tokyo next year is not yet decided. + +AKI: Okay, now on to the vote thing. The last two versions of ECMA-262 and ECMA-402 did not have the alternative copyright notice and copyright license, which is what we have in those documents to allow people to fork. We hope nobody wants to fork it, but we don’t want to stop anybody from doing so. What we need to do as a committee is vote to approve a corrigenda for each of these standards. We will publish an update that’s just a cover sheet and the one page we are changing with the old copyright and the new copyright. I think we should—yeah, okay, I’ll go through it quickly + +AKI: I know we all get itchy when it comes time to vote. I will try to make this as painless as possible. Every member gets one vote. That means that all the delegates of a company share one vote. Observers don’t get to vote. Invited experts don’t get to vote but they can certainly lobby the members as much as they want. And it’s a simple majority. So I’m not concerned about it passing overall, but if anybody wants to get their disagreement on the record, they can certainly do so. If for some reason we can’t agree to vote, we’ll do a postal ballot. I don’t think that’s going to be a problem. We need to vote on all four, but if there isn’t any dissent, we can vote on them all at once. So, chairs, if you would be so kind as to formally call a vote on approving the corrigenda. + +RPR: With a clarifying question from Eemeli about whether—please. + +EAO: Could we just, like, not and just ask for consensus, which counts effectively as everyone consenting and unanimously voting. + +AKI: That’s why we start by asking for dissent. + +EAO: If we don’t dissent, we don’t have to do all the complicated stuff? Cool. + +RPR: I think we’re all on the same page, yes. + +ACE: I want to do a postal ballot + +AKI: All right, Ashley, you can write us a letter. + +RPR: All right, well, would you like to display—you have a slide with all four items. + +AKI: There we go. Here is what we’re voting on. + +RPR: Okay. So the first call here is do we have any objections to approving all four items on this slide? Okay, we have explicit support from Chris. No objections, so I will say that this is approved. + +AKI: Great. Vote complete. I really wish I had a sound board and one of those “that was easy” buttons. + +RPR: Yeah, thank you, Aki. + +AKI: Thanks for your time, everyone. + +RPR: There’s also a question from NRO. + +NRO: Yeah, 426 already has everything correctly done? There is nothing to change there? + +AKI: Correct \[editor’s note: AKI was wrong.] + +RPR: Aki, is that everything from your section? Perfect. Thank you so much. + +### Speaker's Summary of Key Points + +* Ecma has had a busy year, and intends to publish 13 standards at next month’s GA + * Including standards with contributions from TC39 delegates JHD, ABO, and LCA +* TC57 HLSL is getting off the ground, make sure your employers know +* FOSDEM 2026 is coming up, Ecma will be participating and wants to collaborate with anyone on the committee who may be present +* Chairs have published 2026 TC39 meeting schedule +* ECMA-262 & ECMA-402 corrigenda need voting + +### Conclusion + +* Committee voted unanimously to accept all four corrigenda on 2024 and 2025 copyright notices. + +## ECMA262 Status Updates + +Presenter: Kevin Gibbons (KG) + +* [slides](https://docs.google.com/presentation/d/1OEO7E_2LAUA7EzH4v0JfTbq9-ro_05GEH_4lhserhGs/edit) + +KG: Excellent. I’m somewhat sick, so forgive me if I’m difficult to understand. Updates since last time, not a very long list. We’ve landed a number of normative changes, but they’ve all been bug fixes and similar. I’ll go through them just for the sake of going through all of them + +KG: So we had a bug fix in `String.prototype.lastIndexOf` that was introduced during an earlier refactoring. + +KG: There’s this change to copyWithin where RGN has noted the specification did not match reality, and we landed that change per consensus at the last meeting. + +KG: We also landed this change which was arguably editorial, where previously it was implied to the global object was required to be exotic, which was just a weird thing to do, because the only thing that exotic implies is that the doesn’t use all and only the ordinary object MOP specifications, but there’s no reason to require that of hosts and there’s a loophole later that would allow you to have an ordinary object anyway. We landed this thinking it to be something that wouldn’t require consensus, even though it is arguably normative, which is why I’m calling it out here. + +KG: [PR 3700](https://github.com/tc39/ecma262/pull/3700), MF I believe noticed that when we landed BigInts in the spec and introduced the BigInt type, we introduced the `[[IsLockFree8]]` attribute, which is consistent with `[[IsLockFree2]]` and `[[IsLockFree4]]`. And the other pre-existing ones were required to be consistent within an agent, for the lifetime of the agent, and that was not true for `[[IsLockFree8]]`, which, A, was never ever going to happen—no one is running an architecture which is only sometimes lock free for 8 byte types—and, B, was 100% just an accident. So we landed that without asking for any consensus on the assumption that this was always the intent and of course is web reality. + +KG: And then this last one is that there was a bug in the module handling machinery, which I believe Nicolo noticed, that was just a failed assert that was now corrected. + +KG: And a handful of notable editorial changes. The first one, thanks again for RGN, a number of improvements to the `TypedArray` machinery in various places. Which hopefully will just clarify or make more consistent a bunch of that stuff. And then this last one is something that we have been working towards for a very long time, although only incrementally, which is that you may be familiar with the `!` and `?` macros in the spec which are used for asserting that a potentially abrupt operation is not abrupt, and unwrapping a potentially abrupt operation or propagating the abruptness to the caller, respectively. You may not know that question mark was defined in terms of this ReturnIfAbrupt macro, that macro had been used in a number of places historically, but through a series of refactorings made for other reasons, we did ultimately remove all uses of ReturnIfAbrupt, which has allowed us to specify `!` and `?` directly. This also allowed us to fix a thing which has caused a number of people confusion over the years, which is that the specification of ReturnIfAbrupt was bad and wrong. It didn’t actually correspond to how it was used in the spec. And now ? and ! are specified directly and hopefully that will be clearer for readers in the future. It shouldn’t actually affect anyone, because no one was going to read return if abrupt. + +KG: Also a couple of meta points of business. First I wanted to call out that Aki has been on a quest to make the spec more standards compliant, as it were, and as part of that, she's added the correct copyright metadata. Previously the spec had the wrong copyright, a copyright not approved for use in ECMA documents, and now has been updated to match the ECMA copyright. + +KG: And also PR previews are working again. They were broken for a while. They should be working. CI now posts a link to a preview. However, to get a preview for a pull request, you immediate need to either be a member of TC39 on get must be or manually add the "request preview" label, if you have permissions, or otherwise ask anybody to do it for you. + +KG: Okay, last thing is that I wanted to call for interest in editorship, because SYG is going to have less time going forward, MF potentially has less time going forward, and I may or may not continue as editor depending on my employment status. Anybody who is interested in being an editor, now is a particularly good time. And if you think you might be interested, the editor calls are open. You can find them on the calendar. There are currently 2 p.m. Pacific on Mondays or feel free to talk to any of the editors, either in person, if you happen to be there in person—I believe Michael is the only one in person,so talk to Michael if you happen to be in person. Or we're on Matrix, happy to chat about editorship. + +KG: And very briefly, I want good call out a little bit of upcoming work. We are probably going to soon introduce a CI warning for when you are introducing a phrasing which ESmeta does not know how to parse. It shouldn’t block a pull request from landing, but if you see that warning and wonder what it’s about, it’s just that you’re using a new phrasing and possibly means there’s some other standard phrasing you should use instead. Possibly you chose the best way to say it and you should ignore that warning. + +KG: And finally we would like to do some work to make the spec more linkable in general. And I believe someone, NRO maybe, was pointing out the concrete methods could use better linking, so we’ll hopefully have something to do with that soon. + +KG: That was a lot of talking very quickly. Any questions or anything? + +RPR: Nicolo? + +NRO: Yeah, when do you want the interest to be expressed by? Is there, like, some deadline you need? + +KG: Chris, do you know the answer to that question? I believe it’s January. + +RPR: Ideally some time this year in order for us to do elections the next meeting, which is the 20th of January. We will put out formal requests—sorry, reflector posts on both the editors and the chairs group. Okay, I think that’s all—anything else, Kevin? + +KG: That’s all I had. Thanks very much. + +RPR: Okay, thank you. Please, can you review the notes to make sure that the summary and conclusion are correct. + +### Speaker's Summary of Key Points + +* Normative changes are all bugfixes +* Copyright on the living spec has been changed from something bespoke to an actual ECMA copyright +* Anyone interested in editorship for next year should express interest by the end of the year, and anyone even potentially interested should feel free to attend editor calls before then + +## ECMA402 Status Updates + +Presenter: Ujjwal Sharma (USA) + +* [link](https://github.com/tc39/ecma402) +* [slides](https://github.com/tc39/ecma402/pulls?q=is%3Aopen+is%3Apr) + +USA: Hi, yeah. For 402, there’s two new normative pull requests. One of them we’re going to see later today. That’s 1032. But the other one, 1035, it’s a routine change that will probably hold off on until 2026, so, yeah, not much new. + +RPR: Sorry, what was, that Ujjwal? + +USA: That was the update. + +RPR: You are complete. + +USA: Yeah. + +RPR: Okay. Are there any questions for Ujjwal? Nothing in the queue or in the room. Okay. Then we are done. Chip? + +## ECMA404 Status Updates + +Presenter: Chip Morningstar (CM) + +CM: So 100 plus years ago when Einstein published the theory of relativity, it spawned an entire cottage industry in bad sophomoric philosophy about how everything was relative, but in spite of that, this is really a theory of invariance that says the speed of light is the same regardless of the observer. And so it is with JSON. Which is unchanged with respect to time or location. And so even though we are all in Tokyo, nothing in ECMA404 has changed. + +RPR: Thank you, chip. I think that deserves a round of applause. Mark has something else to say about this. + +MM: So invariant you stated is the invariant that sort of drove things, but calling it the theory of invariance, the invariant he had in mind was space time distance, X squared plus Y squared plus Z squared minus T squared. + +RPR: Thank you for that clarification. I’ll also say, Mark, your audio is quite low quality. I think we still got it, but if there’s anything you can do to improve that for the rest of the meeting, that would be appreciated. Okay. ECMA404 rests. Thank you, Chip. Onwards to test262 status update with Philip Chimento. Philip, you are there? + +## Test262 Status Updates + +Presenter: Philip Chimento (PFC) + +PFC: We had compiled a list of bullet points in the last maintainers meeting, and then RGN just helpfully sent me a couple more with what’s happened since then, so thanks very much, RGN. I appreciate that. + +PFC: One update is that we are welcoming back Mike Pennisi who is working on publishing test manifests for web features in the WebDX world. There’s some stuff that you can read about on the issue tracker if you’re interested in that, but otherwise it’s just a notice that this is happening. We’ve landed some tests around async module loading, immutable ArrayBuffer, and Intl era month code. And there’s something I’m also going to highlight in the Temporal item later, where we added a lot of coverage for edge cases using a new snapshot testing technique, so more about that later on. + +PFC: And as usual, we'd like to ask, anything that you can do to help would be greatly appreciated. Right now we have a couple of tests for explicit resource management (`using` and `await using`), and RBN wrote these quite a while ago, and they’ve been mostly reviewed at various times, but there are still a couple things that need some eyes on them. They’re fairly large pull requests, so anything that implementers might be able to do to help us out by, say, making sure that the tests align with your implementation, and flagging things that don’t, would be very helpful. Shout-out to Tooru Fujisawa who did this for Firefox, but, yeah, we could use some help for that on the—well, particularly the `using` and `await using` PRs, but also anything that’s been waiting for a while, we do really appreciate that kind of help. It does really move the needle on getting things merged, because it means that we as the maintainers don’t have to do a deep dive as much into the proposal. + +### Speaker's summary of key points + +* Integrating test262 into web-features (https://web-platform-dx.github.io/web-features/web-features/) (More info: https://github.com/tc39/test262/issues/4602) +* We have landed a bunch of tests for async module loading, immutable ArrayBuffer, Intl Era Monthcode +* Added many tests for Temporal edge cases using a snapshot testing technique, more about this in the Temporal item +* We appreciate help from implementors on checking that open PRs with tests are correct for their implementation of a proposal, and flagging when that is not the case. Help is particularly appreciated on the remaining Explicit Resource Management PRs right now. + +## TG3: Security + +Presenter: Chris de Almeida (CDA) + +Next up, we have the TG3 update. Chris, are you ready for this? + +CDA: Sure. The threat actors of TG3 continue to meet weekly to craft malicious payloads and discuss the security implications of proposals. If you are interested in either of those things, please join us weekly on Wednesdays. Thank you. + +RPR: Thank you, Chris. After TG3 comes TG4. Nicolo, will you be giving us on update on source maps? + +## TG4: Source Maps + +Presenter: Nicolo Ribaudo (NRO) + +NRO: Yes, no slides. Just two quick things. One is that we have spec text for the range mappings proposal. It’s linked in the range mappings, and explained there in the ECMA 426 if you want to look at. And second thing, we had service maps session with the work group, and there was interest from multiple people there to work with us, so we’re going to figure out how to make that happen. And that’s it. + +## TG5: Experiments in Programming Language Standardization + +Presenter: Mikhail Barash (MBH) + +* [slides](https://docs.google.com/presentation/d/1GZSXUH0pZX_DiK__s-rbeNpVZreS_yRB7oH_4zhjw7M/edit?usp=sharing) + +RPR: Okay. Thank you, Nicolo. And then Mikel, you are ready with TG5 programming language and experimentation? + +MBH: Yes, with continue with monthly meetings where we discuss various topics that range from sort of statistical analysis of proposals to mechanisation of proposals in proof assistants and we also arrange workshops. The most recent was arranged yesterday. And we had two presentations from two persons from local universities here in Tokyo, and one presentation by a TC39 delegate. So it was a quite nice event. I think we’ve had 19 participants, which was one of the largest workshops. And we would like to make an announcement for one of the workshops that will be held next year co-located with plenary in Amsterdam. It’s 22nd of May at University of Delph in Netherlands. That’s it. + +## Updates from the CoC Committee + +Presenter: Chris de Almeida (CDA) + +RPR: Thank you, MBH. Over—sorry. Yes, we did. So, CDA, over to you for the code of conduct committee updates. + +CDA: Yes. There are no updates from the code of conduct committee. No news is good news. + +RPR: And are you looking for new members? + +CDA: The one time I forget. Yes, if anyone is interested in joining the code of conduct committee, please reach out to one of us. Thank you. + +## Normative: In PluralRules, set compactDisplay only if notation is "compact" + +Presenter: Frank Yung-Fong Tang (FYT) + +* [PR](https://github.com/tc39/ecma402/pull/1032) +* [slides](https://docs.google.com/presentation/d/1qKRDsbRbEw9zKfmCAwqTXdDbTAdyc4IArr2C0-v4vIc) + +RPR: Thank you, Chris. Next up is FYT. FYT, are you there? This is to discuss normative in plural rules set compact display only if notation is compact. Does anyone from Google know if FYT is on the line? There we go, so, sorry, you’re on Zoom, FYT. We see you now. + +FYT: Is it my turn? + +RPR: Yeah, your turn now. + +FYT: Sorry, I just have some problem. Zoom asked me to quit. Let me bring up the agenda. First time using new computer. Sorry. + +RPR: We can see your desk top, yes. + +FYT: Okay, let me bring up the slides. It forced me to—somehow it forced me to out, so let me show. So can you see my presentation now? + +RPR: That looks good. It’s full screen, yes. + +FYT: Great. So I’m talking about PR1032 for MR402. It’s a small normative PR. Basically what, give you some background, currently `Intl.NumberFormat` for very long time have option called compactDisplay. It’s read unconditionally, but it’s set into the internal slot conditionally, only if notation is compact. And that is by design, because the compactDisplay mean nothing when ever the notation is not compact. Okay? So the consequences later on, the particular slot actually have three possible value, one is undefined, one is short or long. But on the other hand, we have Intl PluralRules, which recently added this thing, and we somehow, again, do the right thing, unconditional read that compact display. And we actually unconditionally set into the internal slot, so what happened really is that we have some inconsistency here. We added the notation in PR89 not long ago and also added a compactDisplay in PR1019. The problem really is that whenever we later on called resolve option of compactDisplay, in the NumberFormat, it may return three different value, undefined, short or long, but for the plurals, they can only return short or long without an undefined, but it doesn’t really make sense whenever other notation is not compact. So this is really the problem, and the real problem is really whenever we find this out when we dry try to implement this in V8, but essentially for efficient Ron, question actually utilize some of the internal structure to implement the result option value for that. So if we want to return to maintain the thing whenever the notation is not compact, we have to have some extra memory to do that, and also it doesn’t make sense for some useless method. So we—and also it have the problem to be inconsistent with NumberFormat. So our PR is really just change it to align with what the NumberFormat do, is we still read it unconditionally, but we also do the same thing as when the NumberFormat did, is we conditionally set it into the internal slot only if the notation is compact. So that’s basically this PR is very small PR. We change the setting under the condition if condition. Any questions? + +RPR: There are no questions, but Dan is on is on the queue. + +DLM: Yes, thank you. And I’d just like to say we support this normative change. + +FYT: Can I ask from the consensus for this? Is there any objection? + +RPR: Shane? + +SFC: You can hear me? Okay, great, yeah. This was discussed and approved in the November TG2 meeting. And, yeah, we approved it there. It’s the third change—it’s the third pull request in the area for about six months, so hopefully the last, but because three makes a nice round number, so I hope that it will be the last time you’re seeing a pull request in this area, and also that now—and I hope you’re not back again in a few more months with another pull request here. And yes, thanks, FYT for identifying this in specification and fixing it. + +RPR: Okay, we haven’t heard any objections. And so in the last few seconds, yeah, I’ll say Congratulations, you have consensus. + +FYT: Thank you. + +### Speaker's Summary of Key Points + +* Need to change the spec for `Intl.PluralRules` to set compactDisplay only if notation is "compact" in order to align with Intl.NumberFormat + +### Conclusion + +* TG1 approve the PR + +## Normative: make re-exporting a namespace object in 2 steps behave like 1 step + +Presenter: Nicolò Ribaudo (NRO) + +* [PR](https://github.com/tc39/ecma262/pull/3715) +* [slides](https://docs.google.com/presentation/d/1Ozx51idOUlBzJz8nPgvB8U5HypIN7o0w7mfEaL0xBSs/edit?usp=drivesdk) + +RPR: All right. Let’s move on. So, yeah, thank you, FYT. And then we move to Nicolo with normative change of make re-exporting and namespace object in two steps behave like one step. Oh, okay. Don’t put it on the Matrix. We do not—yeah, all right. I’ll get the Zoom link. All right, Nicolo logs into Zoom. No problem. Is it going all right or shall I fill time with—no, it’s not needed. + +NRO: Yes, okay. This normative pull request is about inconsistency in the spec as we notice where the spec is just—does two different things in two very similar cases, and sometimes that happens and it’s fine. But the reason I’m presenting this is because also browsers, in that case, do not match the spec. So just a bit of context how expert star works. Expert star, just like re-exports all the bindings from some other module, and in example here, in the library file, we don’t really know looking at that file what bindings are being exported from it too. So in this case, it’s kind of exporting foo twice, because it’s exporting foo from left and right. The way we deal with this when I try to import foo from library, so in the file at the top, that’s a linking error because it’s ambiguous to which of the two foo we’re referring. And the same happens—so notice here, just the change in the file right, the same happens even if the variables have the same value, because we’re not checking if these two food have the same value. We’re checking are they the same value. And even if they have the same value, it’s still an error. Now, if left and right are not declaring valuable foo and instead exporting variable foo from the same place, there’s no ambiguity in which foo our entry point is importing. Yes, sure it can go through two different paths, but they both result in the same underline binding. And the same happens if we split the export from the declaration in two. So if left and right do import 2350 and export foo in, is still not creating a local foo variable in left and right. So from entry point, we pierce through and go all the way from both sides of variable and end up. The same happens when left and right use export as their namespace, so when we are importing an S, like, in entry point, again, it could go through two different paths and it’s clear we’re getting to the namespace of the dep module, so there’s no error here. However, if we split the export star as the declaration into import and export, we start errorring. And the reason we start errorring, is technically now left and right are declaring a local variable called NS whose value happens to be the namespace object. They’re not, like, pointing directly to the namespace object as a binding. And the proposed change is to actually make this not an error anymore so that we—so that import star as a namespace acts the same as an NS. And getting the same equivalence and we have for named exports. This what this spec text looks like. You can see at the bottom of the screen shot, that’s how we’re—this like in a loop that goes through, like, all the things exported by module, and what’s happening at the bottom of the screen shot is when we have an import foo by an export, we are creating like a VR12 record to report represent an export, and the same is for when we have an import star, import dub. And this is how browsers currently behave. So SpiderMonkey and JavaScript core actually do match the spec. So allow export star and then for import star followed by export, and V8 export and engine 6 do not match the spec, as in they both making error and the proposed change would be to actually make both okay. If we do not get consensus on making both okay, my personal preference here would be to then do what V8 and XS are doing, preserve the give length, which is useful for tools like mini fires, and all tools right now just assume that those to things are equivalent in all cases. And, yeah, I see Jordan raising a hand. You have some people on the queue. + +JHD: So this is clearly something I—like, an area I don’t fully understand. My—I saw your PR, like, a week or two ago, and I thought it was doing something totally different. So export star as NS, you’re proposing that that do what exactly? + +NRO: I’m proposing that—the only behavior it changes is whether in this case here, we detect that the 2NS exported by left and right are actually the same. + +JHD: Okay. So just to—let me try a different tack. What I think is happening here is both left and right have a named export called NS that is a Moose Jaw equal namespace object that comes from dep, and you’re saying that—you’re talking about the caching behavior or something? + +NRO: No, I’m talking about—so this convert now, it’s equivalent as having—okay, so let me first go back to the previous slide. In this case here, the variable that contains the NS object is actually not stored, the binding is not defined either in left to right. The binding here is defined on dep. It’s as if dep had like a hidden variable declaration that contains namespace. + +JHD: You’re saying this is currently an error because you’re trying to combine the two NS. + +NRO: Is not on error, because imagine there’s a hidden variable inside the file dep that’s const NS and the name pace object and left and right are exporting that same variable. However, what’s happening here is that in left and right, we’re declaring a new local variable whose variable is the namespace. And here we have two namespace variables, one in left and right, and they point to the same value, and the to proposal is we don’t throw and if we’re not doing const NS from the file, we’re just actually re-exporting NS from that file. + +JHD: Okay. + +JHD: So the thing you’re making okay, that currently throws, is just an alternate form of the previous one, which is just saying— + +NRO: Yes. + +JHD: It shouldn’t matter that these are both the same objects, just merge them. + +NRO: Yes, and to clarify even more, in this case here on screen now, here left and right are not declaring a local foo. They’re just re-exporting it. If left and right had const foo equal from foo dep, both them, this would be an error because they’re two foo variables that happen to have the same variable. + +JHD: But if I console log foo in left and right. + +NRO: They have the same value, but they’re two variables that have the same value. + +???: That statement doesn’t matter. + +NRO: The only way you can observe whether two variables are the same or not, you can see Whether they throw. + +MAH: We support making this consistent, it should all work whether it’s a namespace export or just a regular exported binding. My question was how much test coverage do we have especially around— + +NRO: We have test coverage. + +MAH: Yeah. In particular we need coverage around aliasing, in one path alias to one name, and then in another path to another name, and further rename both to the same name. + +NRO: Yeah. I’m working to make sure we have testing for those things + +MAH: Thanks + +GCL: Hello. Yes. I also support this change. As with many things in the modules, part of the specification, the history for why they are are sometimes muddy, but it’s clear this is not an intentional divergence in behavior and it’s good we are fixing it. + +RPR: Dan? + +DLM: Yes. We also support this change. I wanted to also thank you for going out the slides and a clear explanation of the issue. + +NRO: Thank you. + +NRO: And the two—I don’t know V8, but two that match the spec. I checked two lines changed to implement this. + +NRO: The queue is empty. I heard no concerns. So I think I have consensus on this. Is there anybody who still wants to say anything? + +RPR: Congratulations, you have consensus. + +NRO: Thank you. And thanks, KG for working on the actual pull request for this when I was not able to do it. + +RPR: Thank you, Nicolo. + +### Speaker's Summary of Key Points + +* Currently, there is a difference in how `export * as ns from "foo"` and `import * as ns from "foo"; export { ns }` are handled when checking for ambiguous bindings in `export * from` statements. +* The discussion proposes to change the latter to behave like `export * as ns from "foo"`, effectively removing some "ambiguous binding" errors + +### Conclusion + +* The normative PR has consensus. + +## Normative: Extend `JSON.parse` and `JSON.stringify` for interaction with the source text of primitive values + +Presenter: Richard Gibson (RGN) + +* [proposal](https://github.com/tc39/ecma262/pull/3714) +* no slides presented + +RGN: Let’s see. So… As mentioned, this is a request for Stage 4 advancement. It’s actually been quite a while since I presented `JSON.parse` with source. And in the meantime, we have implementation support in—checking now… V8 and SpiderMonkey and JavaScriptCore. We also have the tests that have merged a while back, which are mostly good, there’s still a few gaps with respect to the test plan which I am working on shoring up this week. And we have a pull request against ECMA262 proper, to implement it. There are no remaining issues on the proposal repository, as of about a week ago. And as far as I know, this is looking good. Everything I have just covered should include the requirements of the process document. So hopefully, this is pro forma. But as always, the queue is open. + +RPR: Dan Minor (DLM) Has support for Stage 4. End of message. Chip with a strong + 1. So we have heard support. + +RPR: Are there any objections to Stage 4 for `JSON.parse` text access? There are no objections. Therefore, congratulations, RGN, you have Stage 4! Yay. + +### Speaker's Summary of Key Points + +* `JSON.parse` source text access is shipping in JavaScriptCore, SpiderMonkey, and V8 +* tests have merged and will be improved imminently +* there are no open issues + +### Conclusion + +`JSON.parse` source text access is at Stage 4. + +## Temporal status report and normative PR (slides) (30m, Philip Chimento) + +Presenter: Philip Chimento (PFC) + +* [proposal](https://tc39.es/proposal-temporal) +* [slides](https://ptomato.name/talks/tc39-2025-11) + +PFC: I am Philip Chimento, I work at Igalia and we are doing this work in partnership with Bloomberg. As promised, a progress update. There are now two implementations that pass 99% of the Test262 tests. At least, there was 2 weeks ago when I measured this. We've merged a lot of tests and the numbers I'm showing are current as of two weeks ago. + +PFC: I want to talk about how we hunted down implementation divergences using a snapshot testing technique, because other proposals might find that useful. And then, to close out, we have one normative change to propose, which I found using snapshot testing. + +PFC: So here’s the fun little graphs. As usual, the disclaimer that 99% conforming to the tests does not equal the same thing as 99% of the work done. This is just a rough indicator. Sometimes it goes down in between meetings because we add new tests for edge cases and found out implementations have been susceptible to the edge cases. Sometimes it goes up because we add more tests for edge cases that the existing implementations already handled correctly. Sometimes it goes up because engines fix bugs, of course. You can see we have two at very close to full conformance and a few more hovering around the high 90s. + +PFC: I am going to talk a little bit about our plans for moving the proposal to Stage 4. The V8 implementation is now unflagged in trunk which is scheduled for a beta release on December 3 and a release to production in mid-January. So at that point, we will have two implementations shipping without a flag, which hopefully by then we’ll conform to the acceptance tests as the process document requires. + +PFC: We still have some tests in Test262 in staging. By the time we request Stage 4, we move those to the main Test262 tree and expand as needed. We have a couple of issues open with identified gaps in test coverage which need to be filled. When that’s done, we will plan to request Stage 4, going together with the Time Zone Canonicalization and Intl Era Monthcode proposals—that’s a good opportunity to move them all at once. + +PFC: Right. So the testing technique I said I would talk about. If you’ve been following the proposal repo, there have been a number of files added that introduce this snapshot testing technique. It’s based on taking a list of so-called 'interesting' inputs and just basically testing all the combinations of them, which works out to, you know, hundreds of thousands or in some cases of millions of combinations. For example, we have one test that takes the difference between every pair of dates in a four-year period in the Gregorian calendar. It’s impossible for a person to go through all of those and figure out what the answer should be. So for this technique, we don’t actually have to care what the answer should be. We just care if the answer changes between implementations or changes after you merge a pull request. So these are not correctness tests; they’re more intended to raise a flag if something is wrong: flag it when the results are different between implementations or before asking after a pull request. Flag it when an assumed invariant does not hold for one of the millions of combinations of inputs. Or flag when a combination of inputs causes an assertion to fail, which is how I found the bug that we’re requesting a normative change for later in this presentation. + +PFC: If you are interested, you can check it out. You can follow the link here in the slides. And I made a script that makes it easy to run it on your implementation, as long as it supports JSON imports. If it doesn’t, you can probably still run it, but you are on your own to get it to work with the loader or write your own loader using your own I/O facilities. + +PFC: I wanted to highlight this in the presentation because I think it was incredibly useful for Temporal and will probably be useful for other proposals as well. So just to show you how much worth it, it was, this is a list of the bugs that we found. So we found a spec bug, more on this later in the presentation. Here’s all the bug reports we opened in implementations. Very sorry, I haven’t opened issues yet in GraalJS, but I plan to do when I have a moment. And just to re-enforce that the snapshot tests are not intended to be part of the correctness suite, but just a flag for when something is going wrong: we also added specific test coverage for all the bugs to Test262 now they are part of the actual test suite and any new implementations will have to pass those tests. + +PFC: I am planning to continue to do more of the snapshot tests, around non-ISO calendars with respect to the Intl Era Monthcode proposal. You may find this interesting if you are working on a different proposal. If you would like to talk more about it, feel free to drop me a line and I can walk you through how I did it for Temporal. + +PFC: So on to the bug in the normative change. I found an assertion failure in duration rounding. So this bug pops up when you have a duration with a date component (for example, 1 year here) and the time component (for example, one hour here.) You do rounding to a calendar unit. You have a date relative to which you round, which is an end-of-month date. Just without going into too much detail, the duration rounding uses a bounding algorithm where construct two bounds that are multiples of the rounding increment. In this case, the rounding increment is one year. And you make sure that one is shorter and one is longer than the given duration. And then you round based on which one is closer. + +PFC: So with this particular combination of inputs, that didn’t work. The algorithm generated bounds where the given duration wasn’t in between them. And, of course, as you can probably guess, that leads to an assertion failure and also, you know, even if you have a release build where you disable assertions, that leads to wrong answers. So there is a normative pull request here to fix this. Thanks to Tim Chevalier for fixing it. We also had a bunch of help from Adam Shaw. + +PFC: Usually we say, in fact, I think it explicitly says in the spec, that if an assertion doesn’t hold that’s an editorial error in the specification. But in this case, you know, the fix is actually quite involved. It’s not just like a typo in the spec text. And, you know, code has shipped to the web that gives an incorrect result in release builds of Firefox. So I think this warrants a normative PR. + +PFC: Hopefully that went quicker than the timebox. I would like to ask questions now. + +RPR: Are there any questions? The queue is empty. + +RPR: All right. Then if there are no other questions, nobody puts one on the queue at the last moment. I would like to request consensus on the normative PR that I just presented. + +DLM: I am supporting the normative change. And thank you. + +RPR: Chris also supports. + +RPR: So we have heard support. Are there any objections? No objections. So congratulations, Philip. You have consensus for the normative PR. + +PFC: All right. Thank you very much, everybody. We will go on to merge it and onward with the tests. + +### Speaker's summary of key points + +* There are two almost completely conformant implementations, one still flagged. We outlined a path to stage 4 for the proposal and listed the blockers. +* We presented a testing technique which has been successfully used to find and fix differences between implementations. +* We presented a spec bug found with the above technique and a normative change to fix it. + +### Conclusion + +* A normative change to address an edge case in `Temporal.Duration` rounding (https://github.com/tc39/proposal-temporal/pull/3172) reached consensus. + +## `Error.captureStackTrace` for Stage 2 + +Presenter: Daniel Minor (DLM) + +* [proposal](https://github.com/tc39/proposal-error-capturestacktrace) +* [slides](https://docs.google.com/presentation/d/1c3vpsgkUSD2qWCl_6RICnykWLYm2Tc7Dk_uusBKNvc8) + +DLM: And the slides are up + +DLM: I am sorry about that. I was not entirely prepared. Here we go. Sorry about the delay. Yeah. I would like to talk about `Error.captureStackTrace` again. So a quick reminder of the motivation. So here is some stuff from the NPM page. But basically the `Error.captureStackTrace` static method, and stack trace information, it’s not normally Error objects but things that are created to look like your objects and would like to have a stack. + +DLM: A quick reminder of history. In the depths of time, Chrome shipped this. There’s evidence as early as 2015. More recently, JSC shipped this and SpiderMonkey did as well. In that case because we started to see web compatibility problems. So unfortunately in a situation where we have three engines shipping two different things, and no standard, so this proposal reached Stage 1 in February. I presented in the July 2025 plenary we discussed in redeal number 8, which causes observable changes to prepare a stack trace. So this is another Chrome API that we are not planning to standardize. But it is a web reality. My initial intent to attempt the specifying was to a DataProperty we heard feedback from the V8 team that is not acceptable. Because of the behavior of preparing a stack trace. I also did a little bit of work with one of the suggestions that came out of the July plenaries, using closures and feedback from other members of the committee that they refer to getter and setter to be identical across all. So my latest attempt and getting feedback on today is a version that dynamically adds an internal slot. + +DLM: So the proposed behavior here is that `Error.captureStacktrace` would… then used by the getter to value that slot if it’s present or otherwise undefined. I would like to point out this is the only place in the specification we daytimely add an internal slot. This is allowed if expressly said. And so yes. The getter—the setter does something different. What it does is override the stack property with the object provided as argument. What this does, replace the getter-setter pair. The accessors with a DataProperty. And this is in response to other feedback we like to avoid any kind of internal communications channel. One thing that is part of the proposed specification there is… part of the reason for this is that with the proposed specification, the error stack setter overrides with a DataProperty anyways. And also, this matches what JS assessment and SpiderMonkey have already shipped and V8 shipped this for a number of years as well before they used the DataProperty as well. Both of these are web compatible. I have a quick—not quick. Here’s the proposed specification text. I wouldn’t say this is necessarily complete or corrupt. I am trying to Stage 2 here. Things to be improved are acceptable. So briefly, what I am trying to do here is first make sure things are an object. If there’s a limit to specify, this is part of the existing API, what that does is, partially censor the stack. This isn’t a security mechanism, but a convenience for users. In this case, either way we end up with a string. Then we will have the choice of strategy beginning on whether we are using DataProperty or accessor. The DataProperty version installs the DataProperty. If it’s an accessor, then what we do is install a getter and a setter as I mentioned before. So I have a version of the proposed getter and setter as well. Getter will return the value internal slot if present. Otherwise, undefined. And the setter as I mentioned would override itself with a simple DataProperty. + +RPR: On the queue, Mark has a clarifying question. + +DLM: Yes, please. Go ahead, Mark. + +MM: Yeah. It’s actually just a clarification. You said that the only operation that adds a property—internal slot, adds an internal slot + +DLM: I had a hard time finding something else in the spec + +MM: This is not the thing that has the property. It’s the thing that—subclassing that adds a property. + +MM: It’s the constructor change. + +DLM: Okay. Thank you. It’s good to know there’s some precedent for this proposed behavior. + +DLM: So I don’t have the queue invisible, but I am happy to hear any questions or comments + +MM: What about non-extensible objects? This would fail; correct + +DLM: That’s correct. + +MM: Okay. Great. + +RPR: Please use the queue in future Mark. Thanks + +JHD: Yes. So I would prefer no choice in strategy here. The only shipping—shipping this as spec is better than the current reality for sure. Locking down, you know as many semantics as possible. Both approaches a web compatible, the only benefit to shipping this is that to allow the choice rather is that web browsers don’t have to do anything. All the browsers are just like cool. We are already good. More or less. I think it’s reasonable to ask browsers to make a change to have—to avoid implementation-defined choices. I don’t have a strong preference as to which option is selected. But I would really prefer to see us just pick one unless there’s a compelling reason not to + +DLM: No. That’ fair feedback. We are more or less limited to accessor because of the accessor approach because there’s substantial use of the V8 APIs. In terms of allowing both here, do you think there—or not allowing both. I guess, yeah, do you see an advantage to like users of the web or developers by only specifying one here or is this an argument around just kind of keeping the specification nice is tidy + +JHD: I would say both. I think anything that is not fully locked down in the spec is something that library authors and just generally people in the ecosystem have to deal with permutations. Like, if it’s—saying that V8 can’t change away from accessor, like another alternative I suppose could be that step 7 is marked as legacy, meaning like nobody new should do this. But we acknowledge that somebody will do it. Right. Because then that says all future implementations will pick step 6. That would be fine too. Or that would be better for me than this current strategy. This says you can build new implementations with either approach and that is like not stopping the bleeding. Whereas, you know, either picking one or at least putting big frowny faces on one of the two is a I think a better approach. + +DLM: Yeah. Okay. That’s fair enough. I think I mean, I guess I would like to hear what you—how do you feel about the argument since calling the setter installs a DataProperty, people will have to expect the DataProperty there. Anyways… + +JHD: That is true. Yeah. I mean, I guess—I said I don’t have any strong opinions. I do have some much weaker opinions that like I don’t like the accessor approach at all. I prefer it DataProperty. It’s simpler and straightforward. But I am not going to argue with V8 about it. + +DLM: Yeah. I mean, yeah. Obviously, we prefer not to have to rewrite our DataProperty to be accessors. I assume JSE is in the boat. It would be nice to hear from the other implementers about this. + +RPR: Mathieu + +MAH: I’m not an implementer but I do have concerns for them, I wouldn’t want to force accessors on engines that don’t want an accessor. + +KM: Okay. Yeah, I think similarly, yeah. It’s not the end of the world to change it. But I think it would be preferred to not have it be. It’s sort of unclear—it doesn’t matter, in effect what happens under the hood it’s the DataProperty that acts as an accessor, so practically, it doesn’t matter that much. It slightly feels like a better API to not to be an accessor. Not a thing that can change over time. But I am not married to it per se. + +KM: Yeah. So we are willing to change as well. Obviously. I don’t know. Someone from the V8 team? Also interested in hearing any feedback on the idea of marking the accessor approach as being, you know, not particularly nice or deprecated or something like that. + +OFR: Yeah. Maybe I can also—that’s my next topic anyway. There is a consistency thing with the error arc caesar, like that we want to put on the prototype for normal Error objects. What I would find nice if—so why I don’t think it’s a terrible idea to have an accessor, it’s consistent with normal Error objects. So we use the name implementation for both of them. + +JHD: I can speak to that from the perspective of the stack accessor proposal which is that the big difference is that it’s an owned property and not an inherited one. And so I think that is much higher, like,… on the list of people will notice, that’s much higher than whether it’s a DataProperty or an accessor. And also, this whole API, like, is legacy. This whole API is only proposed because of web compatibility. From my perspective, it should never have existed. It shouldn’t exist. But it’s because JSE and SpiderMonkey shipped it, it’s too late to get rid of it. And probably V8 shipped it for so long. I am not as worried about consistency because people shouldn’t use it. They use it in libraries to hacky, fancy things and that’s cool. A regular developer doesn’t use this function. Like a standard application developer, in my opinion. I am comfortable with it being inconsistent. As Keith mentioned internally, it’s the same implementation regardless. Whether it’s exposed as an accessor or DataProperty. It won’t matter which one it is in terms of implementation difficulty. Obviously that could be wrong. But… yeah. + +RPR: Mathieu? + +MAH: Yeah. I am all for consistency, which is why an accessor doesn’t shock me. However, I want to be clear that in TG3 we discussed potentially sharing the accessors themselves between `Error.captureStackTrace` and `Error.prototype.stack` and we believe that’s not a good idea but we don’t have to discuss that now. + +RPR: Back to Jordan. + +JHD: So yeah. Particularly, from V8’s perspective, is that okay that we can just mark steps 7. Legacy is the spec at that time we have for this thing is smelly. Don’t use it. So can we mark step 7 as legacy and that makes implicitly normative optional. And we can add a non-normative note that, you know, it gives context, perhaps. Is that okay? Does anyone have a problem with that? We can bikeshed the wording later. + +DLM: It seems like a reasonable approach to me. + +OFR: What does it mean exactly? Because it also doesn’t make a lot of sense to put that on. Well, maybe it does. We are not planning to change it. + +JHD: There’s lots— + +OFR: There’s an interaction with—so maybe this was not entirely clear from the presentation so far. But there is a prepared stack trace API? And that prepared stack trace API in V8 allows you to install your own JavaScript hook to format a stack trace. And that basically means when you call this accessor, it can call JavaScript code in V8 if you use this other unspecced API. And this other unspecced API is widely used that shows that this is used quite a lot, so this captureStacktrace is used on 1% of page loads and prepared stack trace is used on 0.1% of page loads. This is widely used. It would be like a multi-year project to get rid it of. So I don’t expect this to go away. As long as we have to prepareStackTrace API + +JHD: That’s fine. There’s lots of things in the spec that are legacy that are never going away. Like dot subcentre and things like the prototype, accessor, stuff like that. It’s totally fine. The value there is a signal that developers should avoid using in new code if they can and new engines should add it. They have web compatibility reasons. But it’s still very useful I think to classify them as such. Even with the very explicit understanding it’s not going away in V8. + +OFR: Okay. Yeah. I mean, I guess under this—yeah. Understanding of legacy, we don’t have a problem with it being marked this way. + +DLM: Yeah. Okay. Great. Thank you. Is there anyone else in the queue + +RPR: Justin + +JRL: Another clarification. PrepareStackTrace only used in 0.1 on Web pages, but 100% on node app. The fact it’s an accessor allows performance because we don’t need to perform the actual prepare step until the user tries to access it. We can get the current stack frames that can be done internally in the engine, skipping all the user code and when they need it while calling Error stack, that is when it runs. This is for the entire node ecosystem. + +RPR: Thank you, Justin. + +DLM: Thank you, everyone for your feedback. I guess I would like to formally ask for Stage 2. With spec text that I showed. It needs to be fixed up a little bit and the legacy note that Jordan suggested + +RPR: James has support for Stage 2. Mathieu? + +MAH: Support Stage 2 as well. Especially, if we go for accessors, thanks for specifying the private slot route. + +RPR: All right. I am hearing support. Also Dmitri and Chip has support. + +RPR: Thanks everyone. Congratulations, you have Stage 2. + +DLM: Thank you. + +RPR: There was support from Jordan. All right. + +\[LATER] + +JHD: We forget to do Stage 2 reviewers for captureStacktrace + +RPR: Quickly, yeah. For captureStacktrace we are looking for Stage 3 or Stage 2.7 reviewers. One reviewer is Jordan. Thank you. Any other volunteers? And Michael Ficarra. Excellent. Thank you. + +### Speaker's Summary of Key Points + +* Presented approach involving an implementation-defined choice of installing data property or using accessors. The accessor version will dynamically add an internal slot. The getter returns the value of this slot, the setter overrides it with a data property. +* Continued use of accessors is important for V8, in particular for Node.js +* Preference to only use the data property version in new implementations + +### Conclusion + +* Support for Stage 2 with text about the accessor based approach being not recommended for new implementations. +* JHD, MF are Stage 2.7 reviewers + +## Intl Locale Info API for Stage 4 + +Presenter: Frank Yung-Fong Tang (FYT) + +* [slides](https://docs.google.com/presentation/d/17FKrRkWCfNdYui9uRQDRYzv2c3cOCp6ZM7Rly9MwGHM) +* [proposal](https://github.com/tc39/proposal-intl-locale-info) + +FYT: All right. Okay. Let me see. + +FYT: Can you see my screen + +RPR: Full screen. You are good. + +FYT: This is proposed for `Intl.Locale` for Stage 4. We will go through the motivation history and we do have one request that blocking this consensus for normative PR, and then also, I want to tell you the current things if the—to have a second request for advancement. Basically this has been put on the TC39 for a long time. TA proposal to expose locale information like the week data. The firstDayOfWeek, in our cycle. We actually advanced to Stage 1 in 2020. And Stage 2 in 3 and 2021. And then we have a lot of updates. There’s some functioning changes, et cetera, for a couple years. And incremented. So currently, we have issue 75, sorry. 76, I think. And it is basically saying, we should define the fall back behavior, one of the—AO. So basically, the idea is that when we write a proposal, we kind of leave those falling back behavior, say, implementations dependent is not—is very vague language. And Mozilla and JS actually suggest we make it more clarified. How does that really fall back? So we have some issues and get a fix. Currently, we change a little bit of the PR because of some other thing and now we review that in PR 92 and this is the proposal by Mozilla and JS for the normative. And basically make it more explicit. It’s not changing behavior. Make some behavior that is not specified to be clearly specified. In TG2, 2025, October 9. So in—for this particular issue, there’s another reason that is blocking Mozilla, so I think what currently V8 and Safari ship it, but Mozilla is blocking this one. I want this address to be that—it can ship things. So only one issue is that Mozilla is not shipping it. So there are no other known issues on this. So we are currently requesting the committee consensus for the normative PR 92. And then I can show the PR. It’s a little bit big. But mainly the—can you see the PR here or? + +RPR: You are showing the PR. There’s quite a lot of text and it’s a little bit small. But… + +FYT: Right. + +RPR: Shane is on the queue if you would like to go to that, FYT. + +FYT: Yes, please + +SFC: We discussed it at the TG2 meeting in October, and everyone was quite happy with this change. + +FYT: Let me see. And we have—so this is a proposal by JS and I review it and I think Daniel Minor has reviewed that and we have—let me see. TG2. We have some discussion. And Apple is looking at this. I think—and several other people are looking at it. Yeah. Any other questions? + +DLM: I am on the queue. I wanted to say we support the normative change and to thank you for working on Andre to get this resolved. + +FYT: Anyone else? + +RPR: Are there any objections to this normative change? No objections. Congratulations, FYT. You have consensus. + +FYT: Okay. So once we have this consensus, because that’s really just specified what is the current behavior; I want you to report what implementation stages we are in now. Chrome and V8 have implemented the proposal in M99. There’s some changes made the changes. Safari and V18, 2023. September. Mozilla is pending on. And also, there’s a polyfill. So we do think with all—all the implementation there are two browser implemented thing and the Mozilla only blocking by the issue once this got merged we should be able to advance to Stage 4. So I think in the TG2, on October 9, we agree we need to first resolve this issue which we just resolved and also have the review—the Stage 4 PR. The Stage 4 PR definitely still failed to change a little bit based on the merge of whatever we approved. The other thing, we have a PR for PR there, a Stage 4 PR for that. And the reason is that for Stage 4 requirements, we need to have two compatible implementations. Chrome and Safari. We have experienced that and we have a PR ready, except we need to merge whatever we just approve. And the editor—I forgot the change. The editor looked at the PR, that I think they should have some approval. RGN I think looked at it. And there may still be some minor issue we need to address. + +RGN: Yeah, my review turned up nothing severe. + +FYT: mostly editorial stuff. Right? Yeah. So I would like to ask for a consensus for advance to Stage 4. + +RPR: All right. Do we have any folk in support or objections to Stage 4? Chris has support. + +FYT: Thank you. + +RPR: Shane? + +SFC: Yeah. I am really excited to see this come all the way through. I know FYT has stuck with the proposal for several years. It was supposed to be a small proposal and we found a lot of issues with it throughout—on the way and FYT has stuck with us to the end and resolving the issues and I think that what we end up with here is a really, really good `Intl.Locale` info API that develops developers built out applications including custom calendar Guis and other key use cases. And thank you, FYT, to sticking through it to the end + +RPR: We also have support from James. Daniel Minor. And Christian. + +FYT: Thank you. + +RPR: I am not hearing— + +RPR: Is consensus reached? Yes. Congratulations, FYT. + +FYT: Thank you + +RPR: You have Stage 4. + +FYT: I appreciate it, everybody. + +### Speaker's Summary of Key Points + +* Anba from Mozilla proposes PR92 and TG2 agrees. Need TG1 approval to merge. +* With the merging of PR92 there are no outstanding issue and like to request for Stage 4 + +### Conclusion + +* TG1 agree to merge PR92 +* TG1 agree for Stage 4 + +## Iterator Sequencing for Stage 4 + +Presenter: Michael Ficarra (MF) + +* [proposal](https://github.com/tc39/proposal-iterator-sequencing) +* [slides](https://docs.google.com/presentation/d/1rOgJ2LY5IF4M6zXo_Cbn0HkTFlFceBrmEkvwKw-u3go) + +MF: I will try to do it 2 minutes faster than I planned. + +RPR: Thank you + +MF: So this is iterator sequencing. Remember that it adds the `iterator.concat` function, which produces a new iterator. And that iterator yields all of the values that would have been yielded by all of the passed iterables. + +MF: This is what the spec text looks like. It has review and approval from KG. We have implementations from JSC, who originally implemented it in October of last year. And it has been available behind a flag since November of last year. SpiderMonkey also implemented it, in November of last year. And it has been available in various forms behind a flag until just a few days ago, I think, actually. Where it was unflagged in nightly releases. No signals from V8 yet about their plans to implement. + +MF: But that is two. I am looking for Stage 4. + +RPR: Daniel Minor? + +DLM: Yes. We support Stage 4 and yes, you are correct, this will ship in Firefox 147. + +OFR: Yeah. It’s planned to be implemented. So all good. + +RPR: All right. So this is the formal call for Stage 4. We have had— + +MF: Yes + +RPR: Two for support and Jordan. Are there any objections? I hear no objections. So, congratulations, Michael. You have Stage 4. + +### Speaker's Summary of Key Points + +* Iterator Sequencing has had two implementations for approximately one year. + +### Conclusion + +* Stage 4 + +## Keep trailing zeros in `Intl.NumberFormat` and `Intl.PluralRules` update + +Presenter: Eemeli Aro (EAO) + +* [proposal](https://github.com/tc39/proposal-intl-keep-trailing-zeros) +* [slides](https://docs.google.com/presentation/d/1_xv96P0GaV2GZx4eevGd5GH9gvEBPbu9In6JA1WOOPg/edit?usp=sharing) + +EAO: This is going to be a bit of a two-parter. First an explanation of a PR I’d like to merge fixing some small stuff, and then an issue and a possible solution for that if we want to opt into it. And the latter part is why this is 60 minutes, because this is about rounding and it’s about precision, and these topics seem to take up committee time often quite a bit. So I didn’t know if we were going to fill up the whole of it. But I guess we’re going to find out. + +EAO: The first set of fixes here that I’d like to fix are related to the treatment of this slightly peculiar thing where we need to count string digits as a concept that’s entirely internal to `Intl.NumberFormat` and this proposal’s changes in how we deal with string values. + +EAO: And the first part of that is that when we are parsing a string, we accept leading zeros, so something like `0012.3` is a numeric string that we support in `Intl.NumberFormats.format` and `Intl.PluralRules.select`, and there we need to trim those leading zeros so they don’t belong to the count of how many digits we consider that value to contain. And that—because we’re doing this inside a syntax directed operation, we need to do also the zero trimming as a syntax directed operation. It all turns out fine. It added a little bit of complexity to the spec language. I don’t think it impacts on engines much, it just needs to trim leading zeros and then deal with it as before. + +EAO: The second part of leading zeros is sometimes we don’t require them at all. So a value like `.45` needs to be handled as if it’s got a leading zero before it. And because we’re counting these string digits, rather than fraction digits or significant digits or integer digits, we end up needing to count three as the proper count for `.45`. + +EAO: And then there’s the changes that we need to apply when we’re changing the base of the value that we’re formatting. So specifically, for example, when we’re formatting a value like `0.06` and we’re formatting that a percentage, we multiply the input by 100, so we should format that as 6%. Effectively, this can be thought of ensuring that when we’re moving from `0.06` to `6`, we don’t add more precision than the six that we’ve got there, so we don’t end up with `6.00%`, but it’s more like `006%`, and then we do the same leading zero trimming thing that we presented earlier. One slightly tricky part of this is that because we in `Intl.NumberFormat` can do both style: ‘percent’ and notation: ‘engineering’ and/or notation: ‘scientific’, we might need to do this thing twice, so it’s a bit, not complicated, just need to be careful about doing it. I discovered these things when I was writing the tests for this. To see more examples of how stuff works with this, there’s a test262 PR link later in the slides, and it should be included in the agenda. + +EAO: So with this being presented, given that this is 2.7, I understand that I ought to be asking whether it’s cool to merge this. JMN has given this an approval. I don’t actually know, do I technically need my Stage 2.7 reviewers to also approve every PR or how does it go? But my question here, before we get to the next more complicated thing is to ask is this cool? Does anyone have any questions? Is there anyone on the queue? + +CDA: RGN is on the queue with an empty topic. + +RGN: Yeah, I just jumped in real quickly to say that I haven’t looked over the pull request yet. I do intend to. But I am in favor of it in spirit. I think that fixing those edge cases came up pretty early on. I don’t think you need approval at this point to merge it because all the text is going to be subject to further review anyway. So if your preference is to push the button, I support that. + +EAO: My preference is for you to say I press the button and then I press the button. + +RGN: You might have to wait a little bit, then. + +EAO: I’m not in a particular hurry about this. Please review this when you get to it and that will be fine for this. + +RGN: Okay. + +SFC: Yeah, I’ve also reviewed the pull request in spirit, and I basically am in the exact same situation as RGN, where this is a sufficiently, like, complex part of the specification that I want to make sure that, you know—that I review it thoroughly, but I’m definitely in favor of what it’s trying to do. + +CDA: That’s it for the queue. + +EAO: Cool. I think I’ve got enough on this that I need, and then to the thing that I don’t know how big or—how long we’re going to spend on it. Basically, what we ended up discovering relatively late about this proposal is that it’s impacting maybe a little bit more than what has been presented before in terms of what values it impacts. And this needs to be acknowledged and we need to figure out are we cool with working with it as it’s currently spec’d, which I think is the right thing to do, but for which we ought to make a committee decision. + +EAO: So specifically, what I’m talking about here is that what we’ve been talking about so far as a change to the behavior is that when we have a NumberFormater with which we are formatting a string value that has trailing zeros like the first line example there, `2.00`, that has a clear precision of three digits of precision effectively, that we retain as much of that in the output is requested by the specs and that this, then, yes differs from how the same value as a number or as a BigInt get treated. So this as before. But what has not been explicitly noted before this is that we also get this behavior, that when the number that we are formatting is rounded so that it starts with a precision that is greater than the precision to which we are formatting, so in the example here, we’re using maximum fraction digits 1, the default value for maximum fraction digits is 3, but this can vary up to 100, I think. Or you can use significant digits for the precision, then you opt into that. + +EAO: In any case, if you’re formatting a numeric string value that contains more digits of precision than you can account for directly in the output, and, therefore, you need to do rounding, if the result of that rounding is such that it would have trailing zeros, those trailing zeros are retained. So specifically because 2.03 with maximum fraction digits 1 rounds to “2.0”, we would format it as “2,0” Rounding up works the same as well, and 1.96 rounds to 2.0 and therefore we format this as “2,0”. This is a slightly greater change to the behavior than previously presented. But, again, because of the very, very limited scope of what this actually affects, we still think that this is fine to do and it’s not going to break the web. But it is a little bit more than previously. And as a, therefore, slightly mitigating factor, we propose that we could do what was originally proposed in the discussion of issue #1 of the proposal, that we have this existing option in NumberFormat, trailingZeroDisplay, which is currently only used to trim the zeros if we end up with an integer value. We could add a new value ‘stripToMinimum’ to that option and using that, you could get the current behavior, whereas we are still proposing that going forward, the default behavior changes to keep trailing zeros, but that you could opt in with trailingZeroDisplay: ‘stripToMinimum’ to getting the behavior that currently happens, which means that you end up not retaining trailing zeros in these cases. So the question here is should we merge this PR and/or are there other concerns or questions about the behavior identified in issue #11? + +NRO: Just a question. You said that we could do that. Is it just we can preserve the behavior or is there actually a need for preserve, for having a way to get the previous behavior? Like, is there some way to say, oh, I actually need the behave, please give me an option for it, or is it just that it’s possible for us to provide an option? + +EAO: It is possible for us to provide an option. We still have not had anyone come up explicitly stating that they want or need the current behavior. + +NRO: Okay, then I would prefer to not do the option unless somebody says we need this. + +SFC: Yeah, I—yeah, I’m—initially when I first saw this, this behavior, I was—I found it a little bit surprising, like, a little bit greater of scope. But I know that I’ve spent more time investigating some of the cases here, I think that the proposed behavior is quite a bit better, because it’s—it is introduces a very odd amount of inconsistency with, for example, if you’re formatting the difference between `2.00` and `2.01`, it doesn’t make a lot of sense that one of them retains the trailing zero and the other doesn’t contain the—retain the trailing zero, because that’s not the use case that’s intended here. So I think that it makes more sense to adopt the behavior that’s in the specification already that we just recently sort of realized when writing test cases and things that this is also in the specification. + +SFC: So I like the specification as proposed, as we had approved it for Stage 2.7. And about the option, I tend to agree with Nicolo that, like, we have a very clear path for adding such an option. And I think that I would like to see a little bit more data on the demand for that. + +JAD: Potentially a dumb question. On the previous slide, it totally made sense to me because if you called `toString` on `2.00`, you get `2` back, so it—yeah, that adds up. On the next slide, it’s introducing differences now if you—if you take `2.03` and call `toString` on that, you’re going to get different value on the other end. It seems weird. + +EAO: That is what happens, yes, it is maybe a little weird. But it’s maybe the least weird thing we can do around this. Because I think other behavior than that gets quite complicated honestly. For example, if we were instead of formatting—so, like, because it’s not simple to establish a rule when not to apply the rounding behavior and not—so, for instance, if we were instead of formatting the string `2.03`, if we were formatting the string `2.0300`, which clearly has trailing zeros, and, therefore, we would still end up with `2.0` as the formatted, or should we then also go to just 2, or it’s—yeah. + +CDA: Stephen? + +SHS: Yeah, I just wanted to point out that initially I thought it was little bit weird, but when I think about it further, converting between string and number is inherently either fabricating or losing that precision data, and I think it’s actually quite natural that this a different result. + +CDA: WH. + +WH: Rounding works differently between numeric and string modes. Let’s say you have a Number, and you want to print it with a maximum fraction digits of, let’s say, 2. In order to actually do it correctly, you must turn it into a string and then round it. If you try to round it directly from a Number, half the time you’ll get the wrong results when the first dropped digit is a 5. + +EAO: Just clarifying that, `Intl.NumberFormat` does support explicitly selecting a rounding mode, defining the behavior of rounding for concerns around this, not just specific to the changes proposed in this proposal, but overall behavior for the formatting—for the rounding of values for formatting. + +WH: Yes, and that is the crux of the problem. Let me give two Number values which you want to round to nearest breaking ties to even. Try the Number .755, round it to two digits and then try the Number .855 and round it to two digits and see what happens. + +EAO: I’m sorry, could you clarify whether this is a weakness in the current implementation of `Intl.NumberFormat` that you’re pointing out or a something being introduced here? + +WH: No, what I’m pointing out in order to do rounding correctly, you must convert doubles to strings and round those. + +SFC: I’ll just go ahead and do my item, which is that the `Intl.NumberFormat` has worked on doing rounding on string decimals in string decimal space for a long time, and that was very much explicitly specified in `Intl.NumberFormat` fee 3 proposal. + +WH: Okay. + +SFC: It’s not the case—and it’s not the case in `Intl.NumberFormat` that 0.755 and 0.855 round differently. In fact, they will round according to the rounding mode, and we specified that in the `Intl.NumberFormat` V3 proposal. And the proposal that EAO has here is not changing that behavior. It’s orthogonal. + +WH: So you do convert those to strings before you’re doing the rounding, is that right? + +EAO: Yes. + +WH: Okay. + +CDA: That’s it for the queue. + +EAO: I’m waiting for an uncomfortable silence to stretch a little longer to see if anything else pops up there. CHU? + +CHU: So I think this does make sense. I would support it. But the thing is I’m—I wouldn’t say I would object to it, but I think keeping the option is—keeping a possibility to retain the old behavior is worthwhile, because in the end, what you’re proposing is breaking change, and this—you said it won’t be breaking the web, but it can have—I assume the usage of this, because it’s about formatting a string, so if you change that, from an engineer’s perspective, there might be layout changes, and I can see use cases where this is a fast fix—it would be to keep the old behavior. And therefore, we would need that option. I mean, Shane was referring to seeing any data for that, but I think it would be worthwhile keeping a possibility to retain the old behavior. As meaningless as it might be. + +EAO: Just to clarify, by “keeping the option”, you mean merging [PR #12](https://github.com/tc39/proposal-intl-keep-trailing-zeros/pull/12) and adding the stripToMinimum option value to trailingZeroDisplay? + +CHU: Yeah. So that—there’s the possibility to have the old behavior opt in, as opposed to not have the possibility. + +CDA: Shane? + +SFC: Yeah, that’s the position that CHU just expressed, I think is a perfectly valid position to hold x when we discussed this in TG2, the comments that we got were along the lines of, well, like, we either believe this is a web compatible change or we don’t I believe this is a web compatible change. And if we believe this is a web compatible change, then we don’t need an option to get the old behavior. And if we believe in is not a web compatible change, why are we proposing in change? We should instead make in an option itself or something like this, right? And I think EAO has presented a fairly compelling case that I agree with, that this is a web compatible change. And, like, if we want—like, if we go sign up for adding an extra option here, it’s more for, like—we have to be clear that we’re not adding it because of any question that it’s motivated. We’re adding it because we want to, in the case that, like, the layout changes on a website like Christian said have a quick fix, they have a quick fix available. And if we think that’s high enough probability, which given the scale of the web, maybe is a high enough probability, to justify adding in option that otherwise may or may not be motivated by itself. + +SFC: I do think that the option is somewhat motivated. I don’t know if it’s—it wouldn’t—I don’t know if it’s strongly motivated, but the one thing that you would—that this option allows you to do that you can’t currently do is passing in a decimal string that has more than 15 significant digits. For example, if you want to format a string with 20 or 30 significant digits in the Tess mall string and you want to get the shortest representation and you don’t want to trailing zeros, you would need this option in order to get that. It’s a little bit of an edge behavior, but maybe if you’re building, for example, an online calculator and you want to show the shortest version of the value at all times, that would be a use case for this option. + +SFC: So I do think the option could be motivated, but I think that the main reason we would be adding it if we did was basically as this insurance policy. But we still need to be clear as a committee that we believe is a web compatible change. + +CDA: WH. + +WH: I agree with Christian here. It came up just last week in the development I’m doing. I have a use case for doing exactly what the current behavior does and what this option would let me do—there are situations where I want to display numbers without extraneous trailing zeroes, but I don’t want to round them too much. + +EAO: Cool. So I think that is leading to the question of do we have agreement in principle that we ought to merge [PR #12](https://github.com/tc39/proposal-intl-keep-trailing-zeros/pull/12), which adds this option value? The change to the spec, if you care to look at it, that this adds is really very minimal. Most of the change for this PR is adding the framework for that option being able to take a new value, but it’s only used to set the string digit count to zero, rather than the value that we generate by actually counting the digits from the string. So, yeah. Anyone opposed to merging this PR? + +CDA: Shane? + +SFC: Yeah, I think the feedback that I think is most important today from the plenary is whether we move forward with the principle that we want to have an option to get the old behavior back. And the exact nature of that, it could be an option with this name. We’ve—I think we briefly discussed this name of the TG2, and the name of this option has not really been thoroughly investigated. So I would expect that, like, we—we approve in principle, but then when we come back for Stage 3 at a future meeting, then we come back with, like, the finalized name that TG2 has agreed on for the option. + +CDA: I’m curious, strip over, like, trim or something? Like, what else was— + +SFC: So the name—there’s another option in the same enum called if strip integer, and That's where we got the name strip from. Trim may have been another name that could have been chosen for that. + +EAO: Just checking, if nobody opposes adding this option value, could we first add the option value and then if bikeshedding results in a different name, then we go with that rather than blocking this on the bikeshedding. + +SFC: That’s what I would intend—I had intended to suggest, yes. + +EAO: Cool. So what I’m taking out of this is that I’ve not heard any opposition to merging [PR #12](https://github.com/tc39/proposal-intl-keep-trailing-zeros/pull/12). And we’ll do so once RGN and/or SFC give it a review or somebody else. + +SFC: [PR #10](https://github.com/tc39/proposal-intl-keep-trailing-zeros/pull/10) is the one waiting for SFC and RGN review. + +EAO: Somebody should look at this one too, you know? + +SFC: Yeah, also [PR #12](https://github.com/tc39/proposal-intl-keep-trailing-zeros/pull/12). + +EAO: Yeah, yeah. So, yeah, this proposal is currently at Stage 2.7. Not asking for Stage 3 because obviously we’ve got still a couple of changes coming to it. But expecting Stage 3 request to be coming quite soon, possibly in January. As we have a new TG2 process of getting W3C internationalization working groups proposal like this, this is the example case that’s gone through that process and has the review and approval from there. There’s also the A test262 PR that’s going to need some iteration because it doesn’t include tests for [PR #12](https://github.com/tc39/proposal-intl-keep-trailing-zeros/pull/12) changes yet. That’s going to need to be updated. And there’s a polyfill. I forked the format JS library, and it’s implementation of NumberFormat in order to assert how the proposed spec changes actually work in practice. Have a look at them if you’re interested, or don’t if you’re not. That’s it for me. Happy to continue on this maybe in a month or two. Well, two months, I think. + +CDA: Good. Thank you, EAO. + +### Speaker's Summary of Key Points + +* [PR #10](https://github.com/tc39/proposal-intl-keep-trailing-zeros/pull/10) was presented, and got support in principle for merging (pending review). +* [Issue #11](https://github.com/tc39/proposal-intl-keep-trailing-zeros/issues/11) was presented and discussed. The proposal's current behaviour was accepted as reasonable. +* [PR #12](https://github.com/tc39/proposal-intl-keep-trailing-zeros/pull/12) was presented, and got support in principle for merging (pending review). + +## Joint Iteration for Stage 3 + +Presenter: Michael Ficarra (MF) + +* [proposal](https://github.com/tc39/proposal-joint-iteration) +* [slides](https://docs.google.com/presentation/d/1ZB0Gf74zj_5ezC_iLfTlICDp862dLRdGdexHmekhJmg) + +MF: Okay, so I don’t know, some number of months back, KG and I put together a testing plan for the joint iteration proposal with the hopes that someone would just write the tests for us. And someone did. So ABL from Mozilla followed our plan and wrote the tests, including some additional tests that were not included in the testing plan. And feedback from test262 maintainers was that they wanted a couple changes, which KG did take up that pull request in this follow-up one, adding on a commit there. And then I reviewed the entire thing. There were a lot of tests to go through. I made various changes, and I approved it, so it looked good for me. We also—KG wrote a spec compliant polyfill, which we ran against it, and they all pass. + +MF: I want to have a quick aside here that the entrance criterion for Stage 3 is just that the feature has sufficient testing and appropriate pre-implementation experience. Given what I just said, I think that it meets that criterion. + +MF: So—but in addition, you know, the pull request is not yet merged and we have heard from test262 maintainers that they are okay with merging it in its current state. That was, like, some time last week, I’m not sure when that’s going to happen, but, again, I don’t think that’s necessary for Stage 3. At some point, we should have a longer conversation about that, but not today. So for joint iteration, I would like Stage 3. + +NRO: Yeah, I would encourage also the other test262 maintainers to please merge pull request, even if you might want to keep reviewing those tests. Just because if the proposal goes to Stage 3 now, browsers are going to start implementing it hopefully, and we’ve seen it happening multiple times that there is a pull request with tests, but it just doesn’t run in browser’s CI, the example with request and so they don’t catch back. And I’m personally fine with saying there is sufficient testing. It’s been reviewed by people who are competent about this, but still I would like somebody to press the merge button. It doesn’t need to happen before Stage 3, but it needs to happen very soon before browsers start implementing this. + +DLM: I fully support Stage 3. We’ve had it in implementation for a while, and I’m looking forward to being able to ship that. + +RGN: I agree with MF and NRO. There’s a little bit more to do, but it’s basically just paperwork and rubber stamping on the test262 side. No substantial changes are expected from this point, and it looks good for Stage 3. + +JHD: I’m happy with Stage 3, but for the reasons mentioned, I do think it’s very important that the test PR be merged, like, either before advancement or as close to after as possible, but I also think that there’s no need to block advancement on it as long as we’re planning to merge it shortly. + +CDA: All right, that’s it for the queue. + +MF: Okay, then I’d like to formally call for advancement to Stage 3 for joint iteration. + +CDA: You’ve already got a few voices of support for Stage 3. Are there any more? I saw thumbs up from Chip. Do we have any objections or dissenting views? Hearing nothing, seeing nothing, you have Stage 3. + +MF: Thank you. We are going very fast through this agenda. + +### Speaker's Summary of Key Points + +* Tests have been written and reviewed. +* A spec-compliant polyfill passes the tests. + +### Conclusion + +* Stage 3. + +## export defer for Stage 2.7 + +Presenter: Nicolò Ribaudo (NRO) + +* [proposal](https://github.com/tc39/proposal-deferred-reexports) +* [slides](https://docs.google.com/presentation/d/1xB3qWhOX26dV3stpZ0bViVtMo711mtyCbBKUOLm3NW0/) + +NRO: Okay. So the export for Stage 2.7 or export defer. Very quick, what the proposal I think I presented this in the last few plenaries, so I only included this slide. It’s basically you have some levering on the right that exports a bunch of stuff, and then you have your application left that imports one of those things from that library, and this example is only loading the code needed to run button and not loading, for example, the importing from input and check box, causes loading and executing. And when you pair these with, like, namespace imports for `import defer`, you get the, like, execute and access behavior. Motivation, my apologies for those that already looked at the slides before one hour ago. I just recently added this slide, with you it’s exactly a copy from the slides I already presented, that it’s common in the JavaScript ecosystem to produce provide libraries that export a bunch of stuff. And the reason for this is that it’s just better DX for users of that library to import a bunch of things in one place rather than one function from a module and another function from somewhere else. And the way to support it is by—to have internal listing multiple files and adjust export from that. These examples were from, like lodash would do it. It’s an extreme case and it would have 100 export statements. What happens more commonly is that you have some export from statements, I don’t know, maybe 10. And maybe you have some main code in your fail and it’s exporting some additional utilities that are defined in some other file. And this example here is a file that’s a bunch of export from statements and, again, that’s the extreme case. + +NRO: And this is considered to be a bad practice. Even though it’s common because it’s problems, and so people in the community tell other people, please do not do this. The reasons are that you’re just loading and executing code that you do not actually need. But, again, the act of having just single export frequently wins over these concerns, and then we need tools that go around and strip code as needed and different tools have different ways of doing that. They might strip different things. + +NRO: So the goal of this proposal is to allow developers to keep choosing that pattern that they’re already choosing, but without that causing a problem for the end users, because having code from a website because my website is going to take longer to load or starting interactive. + +NRO: Also, this is new based on discussion over the weekend. I apologize for that. Somebody asked how do the import and export you’re proposing, how do you know which one I should use? So they—the proposals have some differences and are similar in some aspects. If you remember, we had maybe six months to one year ago a discussion on whether we wanted to use the same keyword for the two proposals. And we wanted to do two key words for this exact reason. And import defer lets you—you preload a whole subgraph from a module, and then it lets you defer its execution. Export defer when used in a similar way gives you granular control over that, so you can say it doesn’t execute this whole thing, and I just need this part. And when you’re not importing a whole module, and just some specific function from that module, it can statically tell, oh, they’re never going to execute this because they don’t have access to execute a, so I can just skip loading that whole subpart. + +NRO: And so we’re trying to use in? And you should use export defer one day, and export something that the consumer might not need. So that whether that thing exported by the library is actually loaded and executed, they’re basically deferring the responsibility of triggering that to the library consumer. The—I would say the only time libraries should use `export from` without `defer` is when either it doesn’t make sense to use library without importing that specific pining or they have a set of facts that they’re—binding or never a set of facts they’re relying on. And consumers of libraries should use `import defer` when they’re loading the whole library and see, actually, the execution of this piece of code is low. It’s like a heavy library, so even if I’ve loaded it, like, JavaScript is running and it takes multiple seconds before those are happening, and I do not need those things to happen at start-up, and you can use import defer there to delay that execution. + +NRO: It’s not something that you should just blindly use. You should use it once you have a performance problem due to that library. Since last plenaries, we had a couple discussions. We had—there was an open question about implicit propagation of defer. So in this example here, we have at the bottom the internal module that does export defer and foo and bar, and then line exports foo and bar. And, yes, 2015 way, and so we add the defer can keyword, and entry point import only foo. And the question here is library is importing and exporting bar without using defer, and then foo is not really using it, so can we, like, have the defer marker bubble up and not have library first the execution of the Moose Jaw a particular contains bar. And we tried doing that, and it’s a lot of complexity, and it noons when the user does import foo from library, they cannot just open library to see what they’re actually loading is and it will trail down into all of its importing until they see whether or not there’s a defer keyword or not. So we decided to not do this, and instead if library wants to propagate the defer redness of these things, then it’s explicit every foo bar. As consequence of that, we had another idea. Maybe we should just make it a never to use export from for something that was deferred. Because ideally you would want to put defer there to, like, propagate the optionality of the import. The—so the advantage of this is that you don’t accidentally load something where you—maybe you were not expecting to be loaded. The disadvantage of this is that adopting defer becomes a breaking change for libraries because now, well, your consumer is not using defer, that stops working. I have a slight preference for not doing this, for leaving it to lenders, but I did—I’m very much curious here to see how the committee feels about this. And then, well, this was do we have cob consensus of 2.7, if we don’t make changes, and otherwise I have to make changes, and I have 2 of 3 of the Stage 2.7 reviewers in the past few pay days. There’s a few changes, and there’s one form where we’re explaining step by step how it’s working, and the suggested changes are all editorial. Let’s go to the queue. I see Jake. + +JAD: Yeah, how does this work with dynamic import? Like, how does it know what to—what to load and execute for the target module? + +NRO: Yeah, so dynamic import behaves the same as namespace imports, like, if you do imports there’s a, it gives you the whole namespace, which means it actually loads everything, because from there you are able to access everything. There was—there was actually an idea that was first discussed—well, I don’t know fit was discussed. I had the import defer time when we decided to import defer only works in namespaces, it was to do, like, something like this (`import { foo, bar } as ns`)), where you get a namespace, but specify what you want to have access to. But before suggesting anything like this, I would actually like to see how people use the proposals in practice. So it’s possible to retrofit something here that makes you say I’m getting whole namespace, but please to not load evening. And I think we need to wait for that to see how things go. + +JAD: And my next question was on the web we’ve got linker, module and preload, and what would that do, and I imagine it’s let’s see what develops for dynamic import and copy the same thing. + +NRO: And maybe to link pre-model load, you might want to specify a list of identifiers to load. And know it will import foo in bar with the static import. I still need to—thanks for bringing this up. I was expecting here to have, like, no consequences on HTML, but this is a very good point. + +GB: Yeah, I just wanted to say, you know, overall it has my approval. I read through the proposal. The semantics are very well defined and clear. But as I was going through it again I did have some late stage reservations, which doesn’t affect my Stage 2.7 approval. But does affect, I think, a Stage 3 approval, and I want to go through some of those now, and there’s a few. There’s like three or four different things. We’ll see how it goes for time. Please feel free to interrupt me. So I guess the first thing is that the module system is already very complex. And import defer adds new complexity, and then this adds extra complexity. The other thing is that this is actually kind of two separate features. These partial namespaces is a little bit of a distinct feature from these actual explicit named imports, because the way that the names are collected on the namespace and partially execute is another kind of mechanic. And from a purely mechanic point of view, that’s where the confusion for end users is something that I brought up, and I think that is something you touched on in your slides. But we’re telling users that we want them to use `import defer` right now, so that whenever you import something, you should use the import defer namespace for—to avoid unnecessary execution until you need features. With this, if you do that, you lose out on all the network benefits of this proposal where it can actually avoid load things over the network, because if you import defer one of these namespaces, you still—you actually have to the network work up front, so import defer, for an expert defer, is effectively an expert defer anti pattern, and that’s a little bit confusing in terms of how we communicate that. And that’s the one discussion that I think is important to have. + +GB: And the other discussion is about whether we really want to be encouraging the barrel file pattern. And NRO, you mentioned that all re-exports should be ideally using this syntax. But I think, you know, re-exports are a really useful thing at development time for constructing modules and then you build out your chunks and you have reexports from chunks where you probably have a directly export to the chunk, and I think in both of those scenarios, you don’t necessarily need export defer. So is the only use case barrel files, or are there other use cases here as well with these partial namespaces where he apply to things that aren’t quite barrel files but maybe are slightly barrel files? I think I pretty much got through it, but thanks for listening to me on all this. + +NRO: So, yeah, about import defer and export defer working together in, like, maybe it is true that if you are getting the loading benefits from export defer and then you move to namespace import, you’re losing on that. Unfortunately, the guidance for whether it’s worth losing the loading benefit to get the execute benefit is going to vary a lot on the environment you’re running. For example in, the browser, not loading one file, it’s probably going to be much better than loading a useless file and then skipping some code execution. But then there are environments where the file loading is much cheaper, maybe, for example, they’re already preloaded in memory, like, pre-cached and compiled by code. And so the loading cost is basically nothing. + +NRO: This proposal actually—this export defer thing was originally part of the import defer proposal and it was just in the execution thing. And, like, when we split out, it’s because we realized actually, we can do even better. We can do loader. Give loading benefits. And, like, going pack to not doing the loading means that the feature work are more complete with each other. And saying that import defer works exactly like export defer, it’s the execution of something, but we’re missing out on, like, some potential there. Like, personally, even if it started like this, I find this keep loading part much more exciting than the defer excuse part here. + +NRO: About the barrel file thing, so, yeah, the example I had here was just a bunch of free exports. I’m thinking of cases like, I don’t know, for example, I like react where you have the core react and it has a bunch of hooks, and normally users might need some of those hooks. So it’s not just something like lodash that exports something, it has core logic and a bunch of satellites that are around that. And, like, those kind of libraries would also benefit from saying, oh, all of these additional features are actually skippable. + +NRO: Sorry, you can tell me, I don’t remember what the other points were. + +CDA: Well, Jordan has got a reply in the queue. + +JHD: Yeah, I just wanted to talk for a minute about barrel files. So this is my opinion informed by many years of experience. If you want to argue with me, please feel free to do so outside of plenary time. Barrel files are at best an attractive nuance and most commonly actively harmful. In every cone bit code base I have experienced, if you convert all your barrel files into deep imports where you only pull in the things you need instead of trying to use tree shaking to do a half as attempt at cleaning up the stuff you brought in that you don’t need, your memory usage, your performance, all of these things will improve dramatically. When I was at Coinbase, the react native app got 71% smaller when we made code conversion overnight. And we definitely shouldn’t be doing anything to encourage barrel files or make them more ergonomic. We should be, you know—that said, Lots of people do use them, so making them more performing is a great thing. And I don’t object to the proposal. I I just wanted to share the perspective. + +CDA: You can quickly define "barrel files". + +JHD: Yeah, that’s a community manifested term that loosely refers to the unfortunately common pattern of having a bunch of small things in a library, and oh, yeah, just like this. And then collecting them all together so you have a single entry point. This predates the exports field on node packages. Which allows you to limit your entry points without needing a packet, something like this or like roll-up. So nowadays, there’s just no need for this. You can just tell people to import from slash add, slash divide, et cetera, and you can make sure they can’t get it all over your other internal files. + +NRO: So it, just to respond to this, is it true that—is not true that the reason barrel files are bad because you need one thing to import all of them? + +JHD: Yes, and that is why this proposal may help. That however, there’s a lot of code that would have to be updated in order to take advantage of those limitations, and it would be bet for all of the—like, rather than trying to hope your files are this clean, because Many barrel files aren’t just re-exports, they also have some other stuff in there. But in general, like, from a philosophy point of view, I would say pulling many just the things you need is always a cleaner approach than doing fancy stuff to optimize away the stuff you don’t need. And I think that as an ecosystem, we should be moving as fast as we can away from that pattern that’s on the screen, regardless of what performance improvement we still want to provide to help that pattern. + +NRO: Thank you. And and this is aiming to do the thing, well, don’t just import exactly what you need. It’s probably just doing it a different way than the way you would like. You find it beautiful. + +CDA: Just noting we have about ten minutes left for this topic, and five items on the queue. RBR? + +RBR: About the argument that barrel files should be prevented from being used by making them non-ergonomic, I don’t believe that’s a actually a real argument, because people don’t know about this pretty much. They like it, and no matter what, it will be used. In this case, it’s more about, like, we have to face the reality of how they are used. I don’t believe slow or fast will change that at all. + +JHD: Just to clarify, I’m more focused on the messaging than on a deluded belief that we can actually change user behavior by making their favorite thing suck. If that were true, like, a lot of things on the web would be better. + +CDA: All right. Ashley? + +ACE: I think—I was on the notes, so maybe I misheard GB, but I think GB said that the advice is that all imports should be import defer, even if that’s not what you said, I’ll still say what I said or I’m going to say. So we have import defer already inside Bloomberg using a horrific in line comment instead of the syntax. The—our advice is not the add import defer everywhere. There are easy places where this is hopefully offence to the author, like, if you’re immediately going to use that thing right under the import, definitely don’t defer it because you’re immediately going to trigger the execution, so you’re only adding overhead in that case. Our advice is, like, if you are trying to really defer something, maybe dynamic import is, like, the best thing to use. If the thing is something you’re waiting until a user clicks a button and it’s okay that there might be a delay to do the full thing, if you can go full lazy and that works for the case, go full lazy. If it’s something you’re going to use immediately, use full import and then start considering import defer, and definitely measure—we’re very fortunate we have a lot of very good tooling inside Bloomberg to measure, like, kind of what’s happening during application load and time the first paint and highlighting which modules—I think similar things in browsers with you spend a lot of time evaluating this module, and then you didn’t execute half of it. So I think, yeah, the advice would be slap this on everything like most performance things. And it’s measure first and add it because it’s—you’re seeing that this would be a win. + +GB: Thanks for explaining that so clearly. I just wanted to briefly summarize. I think it was a few things and I kind of rushed through them a bit, and maybe it helps to just go over those points again, because to be clear, while I say this isn’t blocking Stage 2.7, this is a very serious consideration for Stage 3, and I’m very seriously considering blocking Stage 3 on it. And so to very clearly explain what the individual issues are. So firstly, you know, it’s—it provides ergonomics for barrel files, and if that is the use case that we are pushing, we just need to be very, very clear that we are all in agreement that barrel files are a good thing. + +GB: The current message in the he can—like the refactor JHD mentioned he had a Coinbase in general we’re sort of moving away and if we’re now going to be providing optimizations for the ecosystem that are going to it create best practices, that are going to attract people back to these patterns, we need to be very, very clear about this. About this ecosystem, in fact. Sorry, JHD, did you want to speak? + +JHD: Yeah. Just so we’ve established in the past that the only thing that is a valid Stage 3 blocker is something that came from implementation experience essentially. And so all the concerns you have described, I think, if you want to use them to object to advancement, you have to do it now. And not after 2.7. Just to be clear. + +GB: Okay. + +NRO: I think the motivation is to agree now that these goals are something we will do. I don’t think we should go to 2.7 and say we don’t agree with the goal. There is something that some people said here, GB, that maybe you didn’t fully absorb. It’s not necessary necessarily, but whether we think the barrel files are good or bad, it’s that barrel files have been used and there are clearly a lot of people that like them, even though there is some other group of people that is trying to say not introduce them because then you want to use them with everything. It’s not necessarily about expressing whether everybody should use barrel files; it’s recognizing that there are widely used patterns. + +GB: I think it’s really important we go into that with our eyes open up. And the second point, with that new sort of endorsed barrel file work flow, using import defer becomes a footgun because if you import defer something that is using this barely file technique, you showed the example of lodash, but lots of folks here will remember lodash has hundreds of these. When you import the barrel files, there’s lots of questions. + +NRO: Should we have a presentation about that in context? That sounds like if we do import defer and not these, like import—sorry. That sounds like a problem of import defer. Export defer + +GB: Problem with barrel files and if they are something we will endorse as a best practice in the ecosystem we need to think about that from a use-case and usability in the ecosystem perspective. + +NRO: Okay. + +GB: My apologies for making the late feedback on that. Let me know if you want to propose Stage 2.7 or if we can maybe continue this discussion. + +NRO: It sounds like… at least Jordan said we should not go to 2.7 + +GB: All I said based on what GB is saying, if you want the absence to retain the blockability, you have to do it before 2.7. I don’t think we should block the propose, but it’s important that nobody is encouraged to have more use arrange of barely files + +NRO: Let’s go to the queue and I want to come back to this. To the consensus question. Do we think this is actually asking the committee to have consensus? + +CDA: We only have a couple of minutes. We don’t have time to go through the queue + +NRO: SHS says standardize barrel file. And ACE can you be quick + +ACE: Just one—Barrels are the extreme case of only exporting something from like that people export things from other modules that have a bunch of stuff on. So please—like, if this is not all about barrel files. We can come back and present other cases and patterns where people are exporting things from a module that isn’t a barrel file. + +NRO: Okay. Can I have like five minutes? No? + +CDA: No. We have a packed agenda. We could try to schedule a continuation. + +NRO: Let’s fit this in five minutes. Before consensus there was this topic and I see there's things in the queue for it. But… I cannot do it in 30 seconds. And like I have another module discussion and willing to take that off the agenda if we—if it helps fitting this in. But I think we are done for now. + +NRO: Okay. Going to this question, I see Guy in the queue. Would you mind, do you want to— + +GCL: Yeah. Hi. I agree with the champions here. I think if you are introducing this sort of refactoring hazard here, it kind of makes it impossible as a consumer to, like, structure anything. And as a library author, you can never migrate to using these. So I think, yeah, you have to leave this to the linters. + +NRO: Does… okay. Thank you. Okay. Okay. So without doing the change of requiring of linters do we have consensus 2.7 as a committee knowing this means that we are agreeing with the—with the goal of making it better to have files, have a bunch of free exports? + +GB: Yeah. I’m sorry. Nicolo to do this, at the last minute and it wasn’t my plan, but as I was going through the review, it was a serious concern. So yeah. I do have to raise that concern at this stage + +NRO: We will get back to this at another time, then. + +### Speaker's Summary of Key Points + +* the proposal was presented for stage 2.7, with no changes since last time. +* we discussed at length about whether files with multiple re-exports are good or not, whether this proposal risks encouraging them, and whether it removes the bad parts from it. The committee didn't have a shared value judgement. +* we discussed how "export defer" doesn't play well with other features that require you to use namespace imports ("import defer" and dynamic import), since the tree-shaking logic doesn't apply in those cases. +* the champion presented one remaining open question: whether it should be allowed or not to have non-deferred re-exports of deferred re-exports. There was one some "no" answer to it. + +### Conclusion + +* We didn't reach consensus on advancement to 2.7 + +## `Error.prototype.stack` accessor for stage 2.7 + +Presenter: Jordan Harband (JHD) + +* [proposal](https://github.com/tc39/proposal-error-stack-accessor/) +* No slides presented + +JHD: Okay. So I initially put first Stage 2.7 because I am overly optimistic to think what I could get done in the next couple of weeks. You won’t ask for that today. What I want to do, though, is leave the meeting with direction clear, so as long as I get the spec reviewer sign offer and the HTML integration PR approved there are no decisions to be made. + +JHD: As a reminder, this is the current spec. It just, you know, is pretty basic. It throws if the receiver is not an object. Returns undefined if it’s a true error. And otherwise, hand waviness gives me a stack string. And then the setter which is behavior shared with one or both of capture and prepareStackTrace. I forgot the details. The throw in the receiver is not an object. We will talk about this in a second. And then it installs a own DataProperty on the receiver, which of course will fail if it’s non-extensible for the property is non-configurable and returns undefined as setters do. So that is the spec text So this part, I intentionally put this in here because with normal usage a setter only gets precisely one argument. And if—we have stuff like this. That is only possible to hit if you borrow the method in dot call it on something in the same usage pattern. I want to do it here and add another defensive check that says; make sure you use this right. Some for degree of right. + +JHD: MF has a PR up that basically takes away that check. And uses is present which means that it implicitly assumes if you have 0 arguments that the first argument is undefined. Which is certainly how JavaScript function would operate. You can use `arguments.link` most don’t. It’s not worth derailing in another direction. The existing setters we have, MF enumerated them here, the—we don’t have—add for web compatibility reasons and I don’t think we should look for precedent. And the object appropriate value of setter is it one of the legacy web only things from before. Not a huge deal but it seems nice to me to have things throw errors more often when people are doing the wrong thing. So please put your thoughts on the queues. Before we—let’s dip into that before I go to the next item. + +MF: You said that the present check is like defaulting to undefined. That isn’t what this is doing here. This is—it is still checking that `arguments.length` is one, but no-oping instead of throwing. That’s the proposed change. + +JHD: Thank you for clarifying that. + +MF: It skips that step’s action. + +JHD: Right. So this—so I hear you. But that’s what it’s doing. Thank you for the correction. The—without the two steps here, it would just write undefined. I don’t see any reason why a no op is better here and that’s the phrasing before. You should get an exception because it’s exceptional + +MF: In a vacuum, I would agree. As I put it in the conversation there, we only have three built-in setters, and they all are consistently behaving in this way and I just would follow that pattern because it’s not an important corner to catch. + +JHD: I agree. I would love to hear thoughts from anyone else + +MM: I put myself on the queue. So a slight from accessors, for which there’s, you know, which you covered, just among standard spec standard functions, is there any precedent for a function that errors on too few arguments and does not argue if the arguments are provided, but the value is undefined? + +JHD: The only—offer the top of my head, the only function I know that counts its arguments is maybe object array and the date constructor. And the date constructor—all three do it over overloads. I think that’s all of them. No, there’s no precedent for it. + +MM: Okay. + +JHD: I am not adding a check here to if you pass more than one argument, you should throw because that is definitely not something functions do + +MM: I agree with the hair you’re trying to shed there. KG did this a whole bunch of design roles for future JavaScript proposals going forward that don’t have to follow existing precedents such that we end up gradually moving into a better language without breaking compatibility. Is there anything in Kevin’s set of recommendations that covers this argument counting issue? + +JHD: No. I think it’s just—it’s spiritually similar in the sense of Kevin’s premise was let’s—even though we did something gross before, let’s do something better moving forward, whenever we can. And I think that—on a much tinier degree, that’s this change I am making here + +MM: Okay. I am going to—I am on the fence on this change. I really like having bugs be errors, but I am on the fence. And I am done. + +JHD: I am not sure if the child agreed or not, but RBR? + +RBR: So looking at what we have, as a spec, things are already inconsistent in many, many spots and we will never be able to always keep everything consistent. It’s my belief at least and what is a sentiment I hear is because we didn’t do best before, we cannot do better today about providing users feedback when you make a mistake. That is something I have seen and like well, I worked as a consultant in many, many bases where people were messing up because they weren’t given any feedback about them using an API in a way that is wrong. This happens in not only the language, but also in libraries and so on. But like at least from a language perspective, I would really hope that in the future we can provide a user with the best feedback about something that is not as they anticipated. + +MM: Yeah. Other things being equal, I completely agree with you. It’s just the least surprise, if there’s no precedent then we introduce a first-case. But like I said, I am on the fence. + +JHD: Yeah. In terms of—I would suggest considering it that the surprising thing is how rarely JavaScript errors occur when you do something bonkers. And any time we can change that ratio, I think it’s a good thing. + +KG: Yes. You asked if there's a convention that covers this? There’s not exactly a convention that covers this. But we do have a convention that says, when required arguments are missing, we should throw. + +MM: Oh. That seems like it covers this + +JHD: Yes. + +KG: So the intention was that it should cover functions. And this is not really a function. I mean, it is like formally speaking a function because it’s possible to rip it off of the accessor with getOwn PropertyDescriptor. But certainly when I was writing the convention I didn’t consider that case + +MM: Okay. In that case, I am completely in favour. I think if it’s a recognized design role that in general we want to move to errors and to too few arguments, there’s no reason not to do it for the setter as just the first example. + +JHD: Notably this is only in the usage pattern where this kicks in because the syntax for setters are always called within a single argument, even if it’s undefined. + +KG: Yeah. And I guess since I am now engaging in this conversation, I do actually want to express my agreement with MF. I do think that as a language, it is great to move into a direction of providing information to users. Which is why we have the convention. But this is adding complexity to engines that I don’t think has any benefit because no one is actually going to do this. Like, no one is ever, ever going to— + +JHD: I— + +KG: No one not named JHD is going to do this. + +JHD: Fair. + +KG: I don’t think we should be adding this additional complexity to provide more useful feedback in a case which is that obscure. Better errors in general, good. Additional complexity for cases that aren't going to come up in practice, not good. + +JHD: Then I guess my response as to that, why then do we check the receiver is an object? Everywhere, instead of no oping? We throw. You would have to branch. + +KG: My preference is to treat this as if it was called with `undefined` actually. Not to no op. But… + +DLM: I am just following up on KG’s point. I collected telemetry in the summer and we saw 15,000 calls on the setter on 55 billion documents. No one is using this anyways. That being said, I have a preference for what Michael is suggesting. We are treating this as basically something that is new, whereas error stack has existed for a long time. I thought about possibly tightening things up to be modern. For things like that, existed for a long time, it’s safer not to do that. + +JHD: And just to add one of the possibilities, based on that telemetry. Maybe we don’t need a setter at all. But the non-zero risk of breakage didn’t seem worth it so I kept in the proposal + +JRL: Okay. There are two points I need to make quickly following up on Daniel’s point. This is a really popular node, particularly because it allows you to implement captureStacktrace on older node versions. That’s what it was commonly used for. It is not used on a bunch of Web pages unless they are test pages. So I don’t expect it to be common in usage. But I don’t know why we are even—I don’t think this is useful. This error message. It’s not going to be a common case we are not preventing a user from doing accidentally. They have ripped off an accessor and invoked it. We don’t need to add any error checking or presence checking here. If you do this one case, we toString and it runs and that’s it + +JHD: We don’t `toString` it. KG's coercion says we wouldn’t do that. The next question, should we make the setter throw for non-strings? You know,finish the position, you would say, no, stamp whatever value in the slot + +JRL: This isn’t a common case + +JHD: It’s certainly not common + +JRL: Yeah + +JHD: As I wrote the spec text for it, I am going to leave it cleaner than I found it. As long as we agree on a path, that’s what I will do. I am fine with that + +JRL: My preference is not to do anything here. + +JHD: So the—the preference Justin describes and maybe someone else was, just delete the check—the two steps here? Which means that not providing an argument is just setting undefined into the value. + +JRL: Exactly. + +JHD: And the no op is the PR Michael has up and as it would be the throw. + +JRL: Thank you. + +RGN: I think JRL and KG have made every point that I was going to, so I will keep this brief. I am in favour of a simple algorithm. Omit the steps entirely. Let an absent argument be the same as a present `undefined`. There is no need to go out of your way to provide feedback for users who have gone out of their way to use an API in an unusual manner. + +JHD: Okay. So before I, like, summarize and suggest a conclusion, I am going to jump over to this other issue for mark, should the setter three for non-strings? Is there—if you have expressed an opinion that you want me to make a change to this spec text, I am going to assume that it should not throw for non-strings. Is there anyone who didn’t express that position that has a strong opinion one way or the other? Or anyone who expressed that position and differs from my assumptions? + +RGN: I am not sure what you are asking, but I will provide an answer that I think is responsive: I am in favour of throwing on any non-string input if that is compatible. + +JHD: Given the low usage from Dan’s telemetry, it’s compatible to do almost whatever we want here. + +MF: So this is a place where I don’t think we have to follow any kind of precedent. And our normative conventions suggest we should throw on non-strings here. We are expecting it to be a string. It’s not useful to put something that’s not a string, especially confusing to people who get it and expecting it to be a string. We should throw for non-string. + +JHD: At the same time we are then throwing for zero arguments because undefined is not a string. Just making that clear. + +RGN: I am explicitly in favour of that. + +JHD: Since the queue is empty then, I am going to move forward unless someone jumps on and objects with the assumption that I will replace these two highlighted steps with if—you know, if V is not a String, throw a TypeError exception effectively. The vys and the HTML PR, which I don’t think the issue discusses like a pretty straightforward plan, Kevin very enumerated the things I need to fix, but I don’t expect any controversy over those changes as long as they are complete. Assuming I get that work completed, then I will come back seeking 2.7 with those changes. And fingers crossed hopefully anticipate no friction. So thank you. + +### Speaker's Summary of Key Points + +* Not seeking advancement yet +* Plan to return in a future meeting once spec reviews and HTML PR are ready +* Achieved clarity/direction from plenary about setter behavior + +### Conclusion + +* setter throws for non-strings + +## Declarations in Conditionals for Stage 2 + +Presenter: Devin Rousso (DRO) + +* [proposal](https://github.com/tc39/proposal-Declarations-in-Conditionals) +* [slides](https://www.dropbox.com/scl/fi/0x3r4l7y29ubac2iv2b0s/Declarations-in-Conditionals-Stage-2.key?rlkey=35qe0g6od4uyyd93duuxgdrd6\&dl=0) + +DRO: Hello. I am Devin. So yeah. This is a declaration in conditionals for Stage 2. Just to give a little bit of background this was first presented in 2019. And then I got busy and am now trying Stage 2. A brief overview of this, imagine we have a class with a getter that does some work. Something expensive. Sometimes it does, sometimes it doesn’t. This is contrived but most people who work in JavaScript can imagine a scenario where there’s some function that returns large objects that are temporaries. + +DRO: This is a pattern I have seen a lot. It’s usually not easy to identify that this is something that is bad just by looking at this code because you don’t necessarily know whether the bar getter actually is expensive. Besides it being very expensive to call, the work is being repeated multiple times in this code. You don’t necessarily know that the first call could be an array and the second could be null. + +DRO: Just because of the nature of the logic, because you are dealing with temporaries and transient values, you don’t know what you are dealing with. You could save to a variable. But when you have multiple things, you have to have multiple instances of 1, 2, 3, 4. You can’t use the same identifier. And because these things are declared outside of the ifs, they exist for longer than you might ideally want. For example inside the if for bar2, bar1 is kept alive for the period because you don’t necessarily know when it will go away. + +DRO: So what if instead we could move these variables to be inside of the ifs or to be part of the ifs. This is something if you have dealt with other languages like C++ and Rust and Swift. They have the capability. The idea is to scope the variable inside of the if statement while using it in the if statement itself or the condition of the if. + +DRO: The main benefit is that we can reuse the same identifier as many times we want. Regardless how many times we are doing things, like if you did with trees where the values have data, data left, data right you can reuse data as it becomes a more fluid and easy to use process. This proposal extends that to allow you to use customizable conditions. So if you wanted to instead of just doing the normal truthy operation, give me an array with a length, with a length property. You can do with multiple identifiers. In this case, it requires you to provide a condition expression. So it wouldn’t try to do some magical thing where it ands them all together. You have to provide something explicit for a condition. It also supports destructuring with the rules I mentioned about multiple variables. + +DRO: So the actual syntax of this, part of the reason it took so long I thought it was a nightmare to pull this apart but it wasn’t that bad. We changed from a generic expression to allowing us to write let or const or using for the single identifier cases and this is automatically truthy checked like any variable or expression inside the if. And then if you want to do something more complicated like destructuring, you have to provide this condition expression which could do anything you want. It doesn’t have to be the variables if you don’t want to. You have to give an explicit condition so it’s not assuming something magical. The same with while statements as well. + +DRO: Same exact stuff. Where you have the single identifier case. That automatically truthy checks and the multiple identifiers in the case of destructuring or multiple variables that require the explicit condition. That’s my proposal in its current shape. There is still one sort of big looming question as part of this. And that is, whether or not the new identifiers are visible inside of the else as well as just inside of the if. + +DRO: I think everybody that I talked to say they should be available on the if. But whether or not this is extended to the else is the big question. I will do my best to briefly summarize the arguments for and against and present my thoughts to keep us moving quickly. + +DRO: So if it is exposed in the else, it allows you to basically to introspect what is wrong. With the custom condition expression it allows you to understand if one of the two is falsy or maybe it’s NaN versus empty string or some other definition of what falsy means. It gives you more understanding as to why things didn’t happen. And it lets you do more expressive things with that. + +DRO: On the other hand, you can redefine and reuse the identifiers. In my opinion, it makes things like using a lot nicer because it lets you much more narrowly define when things are alive. Along these lines, the main arguments being exposed in the else is that the transpiled version is effectively just wrapping the if inside of a new scope. And creating the variable locally there. Which isn’t great for a couple of reasons. It becomes syntactic sugar. You create a new scope which is not great for engine reasons. Again, it doesn’t provide you with a new capability in the language. Whereas scoping only to the if is something you easily can’t achieve otherwise. + +DRO: The transpiled version of it is awful mainly because of completion values. It's a more difficult thing to achieve. I have gone through it quickly, but my personal thought as to whether or not it should be available in else is that it shouldn’t be. Don’t put the variables inside the else. Only have it inside the if. But with that being said, all I really personally care about is if it's available in the if. If people want to prefer in the else, I am fine with that. I don’t think I will use that feature personally. I was using the C++ capability as an example. And I didn’t know that it was exposed in C++. I don’t necessarily care if it’s available in else. There are people that have strong opinions and I hope to come to an agreement and move forward. But that being said, so long as we have in the if, that’s what I am happy about. So Stage 2? + +DRR: Hi. I am wondering, in the example where you had the if else, where you had another variable scope if, like if what,— + +DRR: Further back. When I have let data = blah. Would that—data declarations really conflict or not introduce a new scope where data, the subsequent data, the second one could exist in its own sort of separate scope? + +DRO: So my thinking with this is that if it is in fact limited to the if, then this would be allowed. Because I think this is a valuable pattern. If it is exposed to the else, I am not sure how you could do this without running into conflicts given the fact that the second if is sort of like inside of the else. I could be wrong about that. But that’s my understanding. + +DRR: I think it would be kind of strange to—because what you are saying kind of implies if you had a let data outside of the original if, that would conflict with the immediate if let data. So I think that, you know, under sort of—the spec I would imagine where you do allow else to view the variable, there should be no conflict between those variables. That’s intuition. I don’t know if there’s any issue. In other words, the else if would shadow the original one, if you look at—the queue Keith Miller has something similar there. + +DRO: Again that is very possible. I am not completely familiar with the exact nature of this. Yeah, I suppose it could just shadow and be fine and work that way. So maybe this wasn’t exactly the best example for one of the reasons it would be better if it’s only in the if. + +DRR: That’s fine. I would like to talk more support for else in a bit + +KM: Mental model, if it is just a single statement, a block is a statement that has many statements inside of it. And so then when you say else if, you have a new statement that is like internally has a new scope that it creates which is the data. And then the data would shadow the outer one because it’s a new scope. And the same way it does for any other blocks. + +DRO: Yeah. I mean, that—that sounds reasonable. + +CDA: WH is on the queue asking asking about the spec + +WH: That’s what I am asking about. There’s no spec there. None of the new statements are defined in the spec there. + +DRO: That could be possible. I have never written a proposal or a spec thing before. So it might be that I am missing things. If that’s the case, my apologies. If there is more that needs to be added, I certainly can do that and try this again. But my understanding was that the syntax was sort of enough for the initial idea of what needed to be done as Stage 2 entrance criteria. I didn’t know I needed the entirety of the semantics. + +WH: For Stage 2,you need the semantics defined and right now there are no semantics. + +DRO: Do they have to be done in the document or the proposal? + +WH: In the spec language. + +DRO: Well, that’s my misunderstanding, then. + +CDA: There’s a point of order. Philip says a spec is not necessarily for 2. I think that’ definitely— + +JHD: The process document requires a spec to use—I am not reciting it from memory as I used to. Major + +CDA: One acceptance criterion for Stage 2 is: initial spec text including all major semantics, syntax and APIs. Place holders and editorials are acceptable. + +KG: Yeah. I was going to agree. There’s a lot more that needs to be done with the spec. Sorry, I would have called this out if I had realized earlier that was the state that it was going to for Stage 2. There’s a lot that needs to be done, especially for using, like—making it dispose before the else. There will be some work. + +MM: Okay. So the semicolon solves the real problem, I like the—the nature of the problem that it’s solving. My only misgiving about it is that given the—what semicolon means in the header of a, you know, for, not a—not a for—the header of a regular for, if seeing the meaning of semicolon in this position is just confusing, but I don’t have a better suggestion. So it’s just misgiving. I agree that there’s a genuine problem that it’s solving well. + +OFR: Why is it confusing? The second expression is the condition in the for. It would be the same here. + +MM: I’m sorry. Olivier is asking me why is it confusing + +OFR: You could write this as a form as well. Sort of. In the same of the for, the second expression is the condition and it would be the same thing here or am I misunderstanding something + +MM: Oh. + +MAH: Nothing prevents from having a second or third semicolon + +MM: my issue goes the other way. Having there being least surprised because it’s analogous is great. + +KM: The semicolon between the declaration and the condition I think is pretty standard of the C-style languages that use—that have the if declarations. So it would certainly be moving away from the other—the design of many other languages if we chose not to either—not support that at all or to pick some other syntax we would be carving our own path which in some ways creates more complications than it solves. And you know, as it is analogous + +MM: The more analogous to things that exist in the word, the happier I am and now I support the syntax. What are some examples other than for in other languages? + +KM: In C++, they do this exact syntax. You say, if auto or whatever it is, thing semicolon and whatever expression you want to be that evaluates something that is truth—a condition, it could be anything that implicitly converts to a Boolean and I believe that’s true in Rust as well, but I am not 100% + +MM: I am completely on board with the semicolon. + +RBN: So I have brought this up on the issue checker as well. I am—I am in principle not opposed to the proposal, we do have since talking about entrance criteria for Stage 2. I have some concerns that this has some overlap with the pattern matching proposals is in fix whether that ends up called is or something else expression as pattern matching proposal as it currently stands, introduces the ability to match patterns to variable bindings and wholly subsume this proposal with the exception of using. So an if condition or a while loop all of those things are completely possible with the—pattern matching is expression and let variable patterns and I think it would be important for us to have a discussion with you, with the champion for this proposal as well as the champions for the pattern matching proposal to discuss how all the things fit together before we say that this is an accepted solution to—the committee to advance it. It’s premature to discuss that until Stage 2. + +SFC: Briefly, mentioning that I’ve been running a lot of Rust code and I find myself wanting to use Rust’s if bindings that work like these separately from when I use match statements. There’s a world where both of these proposals exist. I don’t think one subsumes the other. + +KM: Yeah. I agree with SFC. I think you can use both, in certain circumstances. And like we have the syntax to do it—the syntax seems to overlap and they serve use cases, depending on what you are doing + +RBN: I am not saying—this proposal should never advance with pattern matching. We should have this how the cross-cutting concerns should be addressed and before this can advance to Stage 2. + +MM: Yeah. Just what about switches? The same logic would seem to apply to the switch head being visible across the body of all cases. + +DRO: Yeah. That was something that was originally asked. I mean, I’m not opposed to that being added as a future thing. I think my thinking with switch was the fact that you already have the sort to enumerate or have the capability to enumerate the cases, so you already have the value you’d get from the variable. Certainly if there is a desire to have all of this done at once we can move to add switch into this proposal. + +MM: Okay. My preference for all to be done at once. + +CDA: + 1 to switch from SHS and a reply from JAD. + +JAD: Isn’t quite different with switch because you wouldn’t have the condition with switch because the conditions are inside the switch statement + +MM: Yeah. So that’s actually a good point. There’s no condition. What you are doing is, you are producing a value and you are allowing a declaration to bind the value you are producing so that you can refer to the value—to the value across all of the cases with the variable that you bound. And I have written a lot of two-line switch headers to define a variable holding—variable = expression of the thing I want to switch on, switch on the variable and then refer to the variable in the body. I do that all the time. So—and if it just makes as much sense to switch, and it’s understood in the same way, which I think it would be, switching on a value, you can think of an if, as a special case, where you are switching on the truthiness of the value. I would just like to see the switch included. It’s not a strong thing if the switch is not included in the proposal. I would certainly not block on that. + +JHD: I think the switch is gross and bad and no one should use it and I don’t want to see it get better. That’s why I am involved with pattern matching because I want to be replaceable wholesale. The other thing that is sort of related is all the examples used—have curly braces. Any good codebase should include them but people omit them often. And I would have to think about what the scoping should be there. Maybe it’s just within the one line. Maybe it doesn’t work unless you use the curly braces. But I think switch has similar problems. + +MM: Are you saying the body of a switch does not syntactically require curly braces around it? + +JHD: I think the body of a switch specifically might but case bodies do not + +MM: The case nodes are nested + +JHD: There’s a huge lint rule for it, 10, 12 years + +MM: The problem with, you know, variables across, you know, being used by cases that are defined by cases, is that the variable being in scope versus the variable being live has no sane corresponds. That doesn’t have that problem + +JHD: A lot of discussion around whether it’s visible in the else in matrix has opinion pointed out that if you use in both branches, you should wrap it in a block and put it in a statement above the if. That reasoning applies to switch. Have it available in cases. And define it above the switch. Then you don’t need additional syntax. It adds value when used in a subset of the branches. + +MM: No. That’s not true at all. The syntax is simply adding value by being able to put the—just have the expression define the variable and then use it, is a minor syntactic convenience. You could do without it. The absence I would find surprising given the presence of this for if and while. + +JAD: I just want to check mark. Are you saying, in—when this is used in the switch, it wouldn’t always be processed as a conditional—even if the value is falsy, the body of the switch would still run? + +MM: Yes. Like I said, you can think of the switch as kind of a generalization of a conditional, where the conditional case switches on the truthiness of the value. But in any case, all of the counterarguments, I still have my preference, but it’s getting milder and milder and it’s certainly not blocking. So Devin, I would say, don’t worry about my switch issue, if it’s—if there’s enough disagreement. + +CDA: + 1 to switch from DJM + +NRO: When reviewing proposals internally, some people had expectations if let foo = something, check if the something exists. So if it’s nullish to have these declarations and that’s how it works with current expressions in JavaScript. I don’t have a suggestion. Just please keep this in mind and you find it like a lot of people have one specific expectation between the two. + +CDA: WH is also + 1 for `switch`. + +OFR: Okay. Yeah. I think this got moved around a bit. It went a bit fast for me here. I need to ask some questions. So you would want the scope to exclude else? Right? + +DRO: That was just my preference. + +OFR: Okay + +DRO: I don’t have a strong way, one way or the other. When I originally proposed this in 2019, there was discussion. I want to put the variable in scope to an if statement. Whether or not it’s used in the else, I don’t have a strong preference. + +OFR: Okay. You were saying that the complicated transpilation is an argument for excluding the else + +DRO: Yes. I know that sounds crazy. I was trying to think in terms of if you do allow it in the else, then you—the transpiler—you put in a block. If we focus on things that add outside value or non-simple valuing to the language to focus on things that are difficult to achieve otherwise. That was sort of my viewpoint for it. + +OFR: Okay. Fair. All right. So then maybe my comment, I think—especially if like this long if else chains, there is not even a way how you could syntactically write it as you say, transpilation needs a function. You cannot actually write it syntactically, you cannot say, okay. It starts here and it ends here with curly braces as far as I understand. And so that I would think is a bit concerning. Yeah. Like, I think historically, it’s difficult for implementation and transpiler to always get the scopes correct. That might be an argument to do the simpler thing. And yeah. Especially if you think about the future interactions with—with using and with all of these kinds of things, it could get quite tricky to get it correct and understandable. So I think slight preference for making it—for making it visible in the else as well. + +CDA: All right. We have a couple more minutes. There’s a reply from Nicolo + +NRO: Yeah. I think the transpilation would make it difficult. Regardless of which direction we go, we give a unique name to the variable. We need some use cases. But that’s not the common case. Like, the common case is letter const. It could be transpiled the other way. + +CDA: There are several items in the queue. Devin, do you want to take a look at the queue and cherry pick + +DRO: Is there anyone that is particularly in favour of the idea of not exposing it in the else? + +GCL: I am very strongly against it being available in the else. I can expand on this, if that would be desired + +DRO: I would love to get a sense as to why. + +GCL: In my mind, the like the—purpose of this proposal to exist to introduce a binding, that—and predicated on some condition, and if that condition does not pass, I do not want that binding to be available to other code in my program because it’s been deciding the binding is not value for some reason. If the binding is available elsewhere,I think it's an antipattern to use it. You use cases where data has validated in some way where it hasn’t. This is something we have seen like Kevin pointed out in the element recently, on the matrix sorry, that Rust changed their behavior. They made a breaking change to all things to work to enforce what I described with respect to drop code because it was causing bugs in assume production code to have Canada that outlives or accessible in the alternative of these conditions. So yeah. I would be—I am very against these bindings being available. + +CDA: Also + 1 against from Ross and Kevin. Clarifying question from Ashley? + +ACE: I guess addressed to GCL and the crowd this general, pro, not being exposed, is it not there at all, meaning, if there was something in the outer scope, a data higher up in an scope, you could reference the outer one or is like data in a TDZ in the else to like so it—it’s there, but it’s not being defined in you tried to access it, it would throw or go to the outer scope + +GCL: I think the right side of the screen is like what I would expect. + +DRO: My understanding would be that you would be able to access the outer data basically. So it wouldn’t be a TDZ or anything like that. + +CDA: All right, we are on time. There’s still a lot of things in the queue. I will capture the queue, if we have time for a continuation later, that will be swell. But it doesn’t It seems like there’s a path to Stage 2 today. So thanks, everyone. We are now going to have a short break. Please be back in the room in—at the 20 minute mark, that is just under 19 minutes. Thank you. + +### Speaker's Summary of Key Points + +* The proposal changed to now also allow multiple variables (e.g. comma separated lists, destructuring, etc.), the new using keyword, a second optional conditional expression (which is required if multiple variables are created), and only scope the variables to the if block. + +### Conclusion + +* More work is needed on the spec before advancing to stage 2. + +## await dictionary for Stage 2 or 2.7 + +Presenter: Ashley Claymore (ACE) + +* [proposal](https://github.com/tc39/proposal-await-dictionary/) +* no slides + +ACE: I hadn’t realized that we’d got through the agenda so quick. + +\[Awkward pause as we wait for ACE to log into Zoom to show the proposal. The dead air begs to be filled with something. Anything] + +RPR: When I lost my dictionary, my wife asked if I’d looked upstairs, and I told her, I can’t look up anything. + +ACE: I’ll go before Rob tells a second joke. So we talked about this, I think, in the last meeting. And only a little has changed since. But recap for people. + +ACE: So if someone is doing this currently in their code, then you’re creating a waterfall. So we’re not going to start getting our lovely color or getting this mass value until we finish getting our shape. So people might refactor to use `Promise.all`, get everything in flight. The thing here that’s annoying is that oh, whoopsie daisy, I’m binding color the shape. I’ve got my things mixed up. This example, in previous times I’ve shown this, it’s maybe not too bad if it’s only three. It just gets worse and worse and worse the more complex this gets. It gets particularly complex when you end up with, like, conditionals in this list, so it gets even harder to even try and start counting, oh, this is the fourth thing and then count back. So you could do this today, get things going, give these variables, people like call those like shape, capital P, that is fine. One of the down sides here is that you—there’s two things that are kind of bad here. One thing it kind of annoys me you kind of end up with twice as many variables in scope. You can scroll down later on, and when you’re typing down later on, your auto complete is going to have twice as many anythings showing up, even though after you’ve awaited shape request, effectively want to delete that from the scope, because really, why would you ever go back to the original promise if you’ve already resolved it? + +ACE: The other thing, which is perhaps more important, is so when I `await shapeRequest`, I’ve not actually associated any handlers with the other promises. They’re just like floating, and I have to wait. It’s not until I’ve actually awaited the first one that I’m going to attach the handlers, meaning if multiple things reject, they might reject with no handler and then you get a non-handled Promise rejection. + +ACE: So this proposal adds a little API. It’s like `Promise.all`, but it’s `Promise.allKeyed` where you name all the promises and then you get back a promise of an object using those same names. Now it’s much harder to muck up the order. The naming follows the naming we’re doing `Iterator.zip`, because it’s the exact same pattern. Zip takes an iterable and then gives you back an array. `Promise.all` gives you back an array. `zipKeyed` takes the named keyed iterables and gives you an object with that shape. `Promise.allKeyed` follows the exact same pattern. + +ACE: The change since last time that we discussed is: "should we do the same for `Promise.allSettled?`, and previously, there was strong support, yes, we should also do this for `Promise.allSettled`. So we do. So the spec now includes the text for that. + +ACE: So it’s currently at Stage 1, but I think we have everything to go to Stage 2.7, but if people don’t want us to go to 2.7 for some reason, happy to hear that. There’s no need to rush any of this. So, yeah, asking for stage 2.7 and then see how we go from there. + +JRL: Okay, so the queue is pretty light. JHD? + +JHD: Yeah, I just wanted to say worse was the unhandled Promise rejections. For me, what’s even worse than that is that it’s unnecessarily serializing those three calls. Like, imagine they were all three network requests or something. Instead of firing them all out in parallel more or less, concurrently, and then returning back when all three have finished, you’re not even firing the second request until the first one has completed. This is a common problem in general with await that `Promise.all` service to, and all keyed just makes the solution even more ergonomic than with `Promise.all`. So it’s a great thing for performance as well. + +JRL: That’s it for the queue. + +ACE: Are there any voices of dissent? + +JRL: So you’re asking for 2.7? + +ACE: Right. + +JRL: So are there any objections to Stage 2.7? + +CDA: I think we should ask for support first. + +JRL: Oh, sorry. Does anyone support it? + +ACE: Yeah, it’s on the queue, MF, DLM, DJM, GM, WH, which is great. Thanks, WH. CDA, JSL, Christian. + +JRL: All right, so lots of support. Are there any objections to stage 2.7? Then I think you just saved us 20 minutes. Congratulations. + +### Speaker's Summary of Key Points + +* Re-presented the motivation for the proposal and its relation with `Iterator.zipKeyed` +* The proposal has been updated to include `Promise.allSettledKeyed` as discussed previously. +* The proposal is currently stage 1 but is asking for 2.7 as the specification is complete. + +### Conclusion + +* No objections +* Support for going directly to Stage 2.7 +* Progressed to Stage 2.7 + +## Intl Unit Protocol + +Presenter: Shane Carr (SFC) + +* [proposal](https://github.com/sffc/proposal-intl-unit-protocol) +* [slides](https://docs.google.com/presentation/d/15gvLA5clt7f6nconED64JzFKi7D-buCyOjQSmKuhEFY/edit?slide=id.p#slide=id.p) + +SFC: Excellent. Okay. I want to do the same exercise with—I think I’ve got this mostly queued up and ready. Okay, are my slides visible? Excellent. And I’ll make them full screen, and I was just handed a sheet. It will either stay here for my presentation or it will float or I’ll—I’ll do my presentation. + +SFC: Also, I obviously can’t help with the notes while I’m being presenter, so someone else will have to cover me. Okay, Intl unit protocol for Stage 1. So a little bit of background. As you may have heard— + +SFC: Cool. So in the background, a number ought to be annotated with the quantity it is measuring. This is a statement you’ve heard me and others make previously with regards to some other proposals such as the measure proposal and the amount proposal. One of the main reasons is because it unlocks item features, such as automatic unit conversion, so so the unit—the key thing is that the unit is part of the data. It’s not a formatting option. It’s a fundamental part of the data model. And we want to keep it that way. We want to keep the unit associated with the number that it is formatting. This is just a little code example for a hypothetical MessageFormat, which doesn’t have to be first a first priority MessageFormat. It could be a third priority. And the message remains the same. This a little background of the use case. So proposal is as a step in this direction, we introduce what I’m calling a unit protocol. So this is a little snippet of what the code could look like. This code is—I put copied from the read-me file, which was available in the materials at the agenda deadline. These slides you just put together recently. But all of this content was in the read-me files. So let’s say the inputs you are locale, unit and number. Currently what you do is pass in the unit and the constructor as well as the locale and the constructor and you pass in the number and the format function. The proposal are allowed the optional specify the unit in the format function. You don’t have to specify it in the locale. That’s on the right side of the slide over here. We—you can see basically we take the unit, which is currently always in the constructor, and we move it down into a new options bag that we have in the format function. I’m using—I’m using a modern EMCAScript syntax here, so this is implying that the keys of the objects are named, number and unit. If that wasn’t clear. + +SFC: So I just wanted to walk through a couple of the caveats here, caveats that we know about. And there’s caveats we don’t know about because it’s early. And one main ones is construction versus formatting, so Intl has long had this concept of you have options that go into the constructor of your formatter and then you have things that go into format function. And there’s two main reasons why Intl has the separation. One of them is that it arrows the object—the formatter object to encapsulate the locale and other locale—and other formatting options. So basically the Intl part, the i18n part. This is—this allows, for example, if you’re creating a template engine, you can have your formatters treat it according to your template, according to your messages and the data is passed in later and passed in the format functions the second region is because locale data can be initialized ahead of time, and by putting it in a constructor you can actually—you and take a lot of that work and make—and do that work ahead of time so you can reuse the formatter multiple times in a tight loop and it makes code more efficient. Those are the two reasons. + +SFC: One caveat with this proposal is we advance one because we have better separation of the data model concerns from the formatting concerns, but it also has an impact on two, because we can’t preload the display names for unit we’re formatting because we have to wait until the unit is available. I’ll point out that there’s other cases, for example, when we’re formatting date times, where we don’t know what the month is going to be until you give us your date, right? So we have to—so we currently preload, like, the different possible, like, month names for calendar. And I think that there’s various steps we can take in this direction to minimize the impact on performance, such as, like, I can go into more detail on that, but basically by keeping all the display names readily available so they can be accessed without having to do an expensive data load operation, but it’s not going to be zero impact, so that’s—if you had asked me, what’s the downside of this proposal, What's the cost? It’s this. + +SFC: Cool, next slide about currency. So one of the styles in `Intl.NumberFormat` is currency. We’ve had this since version 1 of `Intl.NumberFormat`. And currency is units like, so the propose—my proposal is to include currency as part of this unit protocol. And open question I have that we don’t need to discuss in this group, but we can if we want to, I imagine we can discuss it also in TG2 and other venues is whether or not the name of the option or the name of the property in the field in the options bag that gets passed into the format function is named unit or currency if you’re trying to format with a currency. So that’s an open question. Something to discuss. Not necessarily today, but we could. Conflicting units is another caveat. I hope this is not controversial. But if you specify a unit in both the constructor and in the format function, and they’re different, then you get an exception. I hope that’s not controversial. + +SFC: Precision, so thanks to Intl trailing zero, we don’t actually need to worry about this. Precision is retainable if you’re using a string as the number type. So the number type accepts all the number types that Intl currently accepts in the format function. Which includes the number type, the BigInt types and as well as string decimals, and this is not changed. It’s just that now you can associate that also with a unit. I also want to point out options for stepping the protocol. One question that I got was, well, what—can you also associate precision with other types like numbers? Maybe you want to say what’s the number of significant digits of a number type? And that’s something that we could add in the future by adding another field into the object. Other data oriented formatting styles, people often muse about, well, how do you do rational numbers, one-third of a cup, for example? That’s something that could be supported here via an additional extension to the protocol. Also, different precision styles. A lot of these things you’ve also heard about in context of amount. But I have another—that’s actually on the next slide. I won’t get ahead of myself, but another type of thing you can add to the protocol is data precision styles. People ask me, how about margin of error? Significant digits is not always the right way to do precision. So it’s extensible in this way. + +SFC: Impact on amount, let’s talk about this. There’s the amount proposal, and this protocol does not replace the amount proposal. It’s a sort of split out from the amount proposal. So it inherits a lot of the design of the amount proposal, and actually lot of the design space of the amount proposal should be discussed in the context of this one. Some these questions about what annotations to support and so forth are actually part of this proposal. We’ve already established, like, consulting with TG3 and others that the amount proposal sort of requires having a unit protocol. So this proposal is the unit protocol piece of the amount proposal, if you will. + +SFC: But one of the key questions, and I think something that we should discuss today with the time that we have, is whether or not when we design the protocol, whether we should design it for amount or whether we should design it for cases where you’re not necessarily using amount. And I think that there are tradeoffs here. Because when I say protocol the design, I prose you have an objects request two fields that have specific names, and that makes it very ergonomic to use it if you’re just using the protocol. But—there’s other designs. One of them is that you could have functions. Functions have some advantage if you’re using—if you’re using this to get an object, because maybe you don’t have to precompute thing you may have otherwise wanted to precompute. So functions make it so that if you have the getters, if you just have getters, you don’t have to do expensive operations and the getters having functions a better Stein for that. We’ve previously discussed this with Intl. And Intl locale which we discussed earlier, and one of the biggest changes we made to that no proposal is we started with getters and switch them to functions and the functions make it more explicit that the operation is not free. So functions could be one design. If we do it that way, it of course regresses the usability of the protocol if you’re just using it via an object. + +SFC: Another option is you have Symbol functions, which is like, you know, `Symbol.iterator` or something like this, right? Which we have precedence for this elsewhere in the language. This really encapsulates the protocol very tightly. It still allows a third party amount like object to be implemented in userland, but it makes it so that it’s not easy to accidentally use and so that the protocol is sort of very much self-encapsulated and doesn’t feed into the design of the object that is implementing it. Another one is we could do, for example, an annotated string. Like, what’s shown here. And I have increased numbers of question marks on each row, because I’m not protesting anything specific. I’m saying like, a general shape, right? Like, the further down the system I get, the more abstract the shape could get, and I just want to make the point that a protocol could have multiple different shapes, so that is sort of brings up to the key question, because I think protocol I had on the slides, and the protocol in the read me file is very much oriented towards using the protocol directly. However, there’s some tradeoffs, and exploring one of these other directions where the protocol could have advantages in a future world with amount. + +SFC: So I wanted to have a discussion, and then ask for Stage 1 to explore this problem space. + +JHD: So my first thing on the queue was on that page where you said hopefully this is not controversial, I’m fine—I don’t care if it flows an consequence or not if you have conflicting units, but my question is what if I have formatter somebody gave me where the units are already defined, how do I override that? We designed regex explicitly for that use case. + +SFC: That’s a good point. Maybe when I said uncontroversial, I didn't—that’s month something that I thought of when I wrote that slide. So, yeah, that’s a good point. + +JHD: It’s certainly fine as a default. + +SFC: It’s a good observation. + +JHD: I’d love to see what the way is to avoid the error when I’m trying to do that. + +SFC: Yeah. Cool. + +JHD: Okay, and then my second topic is a bigger one we discussed bit last night in numerics breakout. In general, I feel like a protocol should have some sort of first class exemplar. We had thenables long before we had official promises, and it’s great that There's a protocol. Certain people^ over the years have feelings about the string-based instead of Symbol-based and so on and so forth. But nonetheless, it’s great we have a protocol, but everyone only really uses promises now. It’s function return, and you can await them. The fact that you can make custom thenables is relevant, and most people don’t really care. So it’s still good there’s a protocol. But, like, the thing that everyone thinks about is a promise. There was a lot of confusion around iterator helpers because iterable is a protocol that doesn’t have a thing. There isn’t a first class iterable. Iterable is just like a trait, a protocol you stamped on to something. And unfortunately we don’t have yet MF’s first class protocols proposal, which I still very dearly want and would address this concern perfectly fine. So I can’t say here is the first that is the thenable protocol. Here is the thing that is the unitable protocol, whatever you want to come up with your name here. And so in the absence of first class protocols, I would expect something like if this protocol is representing an amount, let’s say, then I would expect amount to exist and provide the protocol. Meaning the functions that take the fooables would of course read the protocol. They wouldn’t look up, you know, intern slots or anything, but users would still have a first class thing to say this is a real fooable and not, you know—or this is—amount is the real amountable, even though the functions take amountables. In the same way as, you know, you can say your function takes that thenable, but really a promise is the thing. This is sort after design principle that everyone may not share, but that’s my—like, I have this discomfort in general with adding a protocol that doesn’t have an associated first class thing. + +SFC: Yeah, just another observation I want to make is that this idea of having a protocol in this context, it’s quite novel in Intl as well. Because all the things we format in Intl have a type in language. And then the international is like, take that type and make a human readable for me, right in and that is very much to the Stein of how international worked for a long time, and adding a protocol to solve this use case would be somewhat novel in the Intl world. + +JHD: I wanted to add one more thing. The set methods that we added, they—the receivers have to be sets, but the arguments are set-likes for some definition of that. And similarly with Temporal, the—there is an options bag, a protocol, to represent each of the Temporal types. But you can convert that into a proper Temporal object as the first class thing, so like, I think that there’s a lot of precedent for some form of the design idea I’m expressing. + +JRL: Okay. Nicolo? + +NRO: Yeah, if all the options, I would go with the one that would pass an object with two string properties, like unit end, number, whatever they were. I would not overindex on this being some sort of protocol. This is like, to me, I have an amount and then we say amount has the same prompt, but looking at the slides, what I’m seeing here is just an options bag. It’s not different from many of the places where we have options be a bags. And there’s no syntax that recognizes this. It’s just literally like two functions that take the same shape of options bag. This is different for the Symbols or, like, methods, because that’s not something that people would, like, manually write in an object. Probably would have some class of library that creates it, but this feels much simpler than that. It’s just a naming thing. It’s not really a design question. + +JRL: Do you want to respond? + +SFC: Yeah. I mean, it’s an observation that when we say protocol, what we really mean is, like, the object that’s passed to as a single argument to a function has to have a certain shape. And a lot of times, that shape is an object with fields. It’s an options bag. Like, in many—I would actually—I think we would be appropriate to use the term protocol to describe that. So—but I think the reason this is called protocol was because that word had been used to describe this sort of corner of the amount proposal, and that’s where the name protocol came from. I could have named this proposal the `Intl.NumberFormat` formatable options bag proposal. Right? So I don’t think that it’s necessary to really draw a distinction there. I think that either word is appropriate. That’s a good observation. + +JRL: I’m actually next. To respond to that directly, if we are to amount, amount doesn’t necessarily need the follow this options bag. It could just special case in the format method. Like, if you receive an amount, then do this with the amount methods, or if you receive a regular object, it is expected to have these two types. That would be totally Fine. + +SFC: Yeah, so feedback we got from TG3 was that we want two avoid reading internal slots of arguments to functions. Where the argument is not the, like, this. You did read peeleds—you can read sperm slots when it’s this argument, but not when it’s just another argument to a function. + +JRL: Yeah, so I wasn’t suggesting that. Use whatever the public interface is for amount. But the amount interface does not necessarily need to follow amount and number. + +SFC: And you’re introducing yet another protocol, right? Because then basically, the—when the format function needs to do a brand check and be like, first let me try to cut to see the in is an object and read fields named unit and field named number, these folds don’t exist, then I try to read the amount Symbol getter function. Right? And I think that it would be better to just have a single protocol that we think solves the use case. You’re correct that I suppose a—like, you could have this proposal and also have an amount that implements a whole other protocol, maybe the Symbol function one. You could have both. Yeah, that’s a good observation. You could have both. + +JRL: Okay. Leia? + +LVU: I also wanted to push back little bit on the not controversial thing around conflicting declarations of units. And ask whether this really warrants an error condition, because it seems to me the author intent is clear, both at the definition point and at the format calling point. So I wonder if it might make sense to treat it as a default. And presumably, you can call it with or without a unit in both cases, co-would it make sense to treat the unspecified the constructor as a to fault, and if you use one in format, then that is used, or if you don’t specify one, you fall back to the default? That seems more flexible. And that is kind of similar to Jordan’s point, but yes, even if you can create a new one, that seems kind of annoying and finicky and it seems better if you can just specify it right there to override the defaults that are internal. + +SFC: Yeah, this is a good—actually, both your comments sort of made me think a little bit more about the design space we have here, because it was something of this shape that also has been the basis for the smart units proposal. So it could be the case that, like, if you pass in an amount object thing here with unit kilometer, and but the formatter is unit meter, maybe it converts the kilometers to meters for you. Maybe that should probably be an opt-in feature, not an automatic implicit feature. I think there’s definitely design space here. And that sense, throwing a range error for now gives us flexibility in the future to explore some of these other types of behaviors. + +JRL: Okay. Daniel Minor. + +DLM: Sure, first off, I want to say I support Stage 1 for this. I do think this makes sense, and it’s an area worth investigating. I guess I just have one question, and that is around the timing of breaking this out from the amount proposal. Do you expect this will advance more quickly, or is there a particular reason for doing that now? + +SFC: I think what we’ve been doing with the—in the numerics group has been trying to identify what are the individual questions that we’re really asking of committee, and one thing that—a topic that has come up several times in the last several plenary meetings has been this idea of, well, there’s actually a protocol that’s hidden inside the amount object, so I wanted to split that out in order to—so that we can actually focus on some of the questions that parole cool brings. And the amount is more focused on the amount it service to. And in presentation is not intended to imply that, you know, one advances more rapidly than the other, although, since this is a subset, I would expect that this would advance first, yeah. + +JRL: There’s nothing else on the queue. You’re asking for Stage 1 advancement? + +SFC: I would like to have Stage 1. I believe that this is a problem that it is worth investigating. We already have Stage 1 on amount, and if—and I think that actually, when I was writing up the proposal, I actually found some edge cases that actually we didn’t even consider the amount proposed. So I do think this a useful proposal to investigate on its own merits, so I think that I’m asking the committee for Stage 1. + +JRL: Okay, so we’ve already heard from DLM for support. On the queue, there’s also Chris and James that are supportive. Give it just a second in case anyone else. If not, is there anyone that objects to stage 1 advancement. + +JHD: I’m not objecting to Stage 1. We’re just exploring the problem space, but before pursuing stake 2, let’s work out offline those questions about first classness and conflicting units. + +SFC: Absolutely. And things like that. Absolutely. + +JRL: Okay, Dimitry is also supportive. So hearing no objections, I think you have Stage 1. + +EAO: Sorry, just could you reiterate what the problem statement is. What is it that we are exactly selecting Stage 1 for? + +SFC: Right. Good question. So the—we believe that there is a—that from the internationalization perspective, we believe being able to associate a unit with a number is useful—it’s important for internationalization purposes. And we’re exploring methods—we’re exploring a method for associating a unit with an amount that is fully encapsulated within `Intl.NumberFormat` that does not involve adding primordial to the language. There’s another proposal that adds a primordial to the language for this same use case, and this is a narrower proposal that’s motivated by—has a similar motivation, but is a narrower version. + +EAO: So I think the problem statement is like the first sentence of what you just said? + +SFC: Yes. + +EAO: Cool. + +JRL: Okay. With that, I think you have Stage 1. Congratulations. + +SFC: Thank you. + +### Speaker's Summary of Key Points + +* Committee agrees that it's valuable to associate a number with a unit as a formatting input +* Open question about how primordial Amount and Intl Unit Protocol should be prioritized and how that should influence the shape of the API +* Feedback on the behavior of conflicting units to be worked out before Stage 2 + +### Conclusion + +* Stage 1 for “explore associating a unit with a number” + +## Import Text + +Presenter: Eemeli Aro (EAO) + +* [proposal](https://github.com/eemeli/proposal-import-text) +* [slides](https://docs.google.com/presentation/d/1IMeeHjpUNZbrV7VTfgproPaht5dCeaeEFw8mE9tf7TE/edit) + +EAO: This is a bit of an odd approach at a proposal, as I’m trying to maybe speed run or min/max or something like that on how far a proposal can get with minimal effort. Because I was not successful in my earlier attempt to just expand the import bytes proposal to include this. The idea here is to import text the same way that we’re proposing maybe we can import bytes. The problem statement is that in pretty much if same way name porting JSON is useful or importing raw bytes is useful, importing text is useful, and it should be just as easy and pretty much work the same way. The way you can currently import text is, well, with the fetch API, we can already do that in many places where you await on a fetch, and then you await on the `response.text()` of that fetch. And if and once we get import bytes, which is currently at Stage 2.7, what you can do is you can import a byte array from da da da with type bytes and then you can use TextDecoder and decode what you just got there. And then the other possible solution is to do what is proposed here, add a new type text that lets you do the thing we want. + +EAO: The current state of the art of what we have is a little bit suboptimal, for the same reasons as it’s suboptimal for importing bytes. The operations are always asynchronous, and it starts late in the execution of JavaScript, and from a browser perspective, all of the relative paths are rooted at the page's location rather than the location in the module from which you’re actually doing the impart, and so we have this preferred solution that this statement should, like, just work. + +EAO: There is no intent in proposal to add any other way of customizing how you get the text, so technically, the text you get is defined by the host, the encoding, sorry. But in practice, it means that you’re doing something other than UTF8, probably needs to do something a little bit different. First, rationalize for yourself why the heck you’re doing the thing you’re doing, because you probably shouldn’t be doing that, and secondly, import as bytes and then explicitly decode it. So, yeah, my first question is can I have stage 1? And I do see there’s a queue. + +LVU: I just wanted to express support. I needed this many times. I wanted to have the use case where I think this is very useful for paving future structured formats that we may later want to add a specific type for. For instance, right now we have CSS that we can import in the web platform with type CSS. It might have been a better path for authors if they could initially import the CSS with type text and then later once we got actually importing an object, then they could upgrade to that rather that than having the all or nothing situation they have today. Same for JSON, you could more ease import it as text and then JSON parse, and you can see the same thing for future structured formats. Suppose your data is in a YAML file and not in JSON. We don’t have type YAML yes, you could fetch today and there are many situations where `meta.URL` is not reliable. For example, today bundlers mess with it. Yes, they shouldn’t, but it does happen. And something like this would be much better. Yeah. + +JRL: Okay. We have several plus one support. One from Chris, one from Michael, skipping straight to James. + +JSL: Yeah. Expressing support. I will point out, though, that, like, sometimes workers already has a variation of this implemented, works fantastic. We had users comment on it, it’s not a hypothetical case. There are real use cases for this, in the wild. Having this formally supported would be fantastic. + +JRL: Okay. And a couple more + 1s from myself and Mateo. Daniel Minor next + +DLM: Support this. I wanted to mention that in terms of implementing this, HTML spec is important. Import bytes has a draft which will be implemented right now and similar to this. I want to highlight the importance of that. + +EAO: Yeah. Absolutely. If and once this is advanced, it makes sense where there should be one or two HTML spec PRs. I haven’t done anything in that space because I don’t want to do any work that somebody else is doing and I can just copy. + +JRL: Next up, Christian. + +CHU: Yeah. I also want to explicitly express support because I think this paves the way to get away from microDLS—using for ages like, like, putting something in import and doing things which—yeah. So that’s a good idea. + +JRL: Okay. Shane? + +SFC: Yeah. I just wanted to clarify that this import text works based on either the—the explicit type option, for text, or based on the file extension because I definitely—I think there’s definitely cases where we add more file types that we don’t currently have. And those might want to use a different—loaded not as strings. + +EAO: Nothing in the spec text looks at the URL which the import is done. The extension is completely in order of the current spec you say for implementation to do all sorts of things. So doing an import as text-based on an extension is something that is allowed, this proposal does not propose to do anything about it. + +SFC: Cool + +EAO: Using .TXT in the example is meant to be purely exempt leader + +SFC: In order to get the behavior, you must have the with type text. If you are using an ESM style import statement + +EAO: If you are using an ESM-style import and use with type text, then you will gettext. This proposal and the speck does not mandate what happens when you don’t. + +SFC: Okay. + +JRL: Okay. That’s it for the queue. We had—several messages of support. + +EAO: I think it means I might have Stage 1. + +JRL: Yeah. Any objection to Stage 1? Okay. You have Stage 1. + +JRL: Next question: do you want to go straight to Stage 2? + +EAO: I would like to ask for Stage 2. + +JRL: Do you want to skip the 2.7? + +EAO: Can’t do that because we need to do a review. That’s my next slide. + +JRL: Got it. We need—okay. Okay. + +JRL: So support for Stage 2? Sorry. I did not see that. Jake? + +JAD: On the web side of this for JSON imports we require JSON mine type for it to work. What do you see it being for text? Just any mime type is fine + +EAO: I would say any mime type + +JAD: I would agree + +JRL: That’s an HTML question? + +JAD: Yeah. + +JRL: Okay. We have James Snell on—to support Stage 2. Also, CDA supports—“but I have not looked at the spec. Sounds good to me if acceptance criteria have been met” + +EAO: \[points at screen] Chris you have now looked at the spec. This is the entirety of the change here. We add a create text module abstract operation, which takes an argument source and returns a normal completion; it performs the following steps when called return. Create default exports in the module of source. And it is used in the place where currently you check for type being JSON, then a specific thing. Rather than just doing that, we do the thing with JSON here. The same text. But if it’s type text then we perform the finish loading imported module, the result is… the only change compared to the JSON is create text module then parse JSON module which does the thing which is a subset—JSON module is parsing the JSON and then you get the module around the JSON. This doesn’t do that. It gives you the string from which the JSON would have been parsed. And then, we add a bit to note here saying that because the note is currently only about type JSON, but this is also about type text. + +JRL: Okay. Jordan, do you want to reply + +JHD: I support Stage 2 and I review the spec text. I am marked as a reviewer, I can mark that too for 2.7, which also support + +JRL: Nicolo? + +NRO: I also reviewed the proposal ready a few weeks ago. And I mean, it looks fine. It’s the same spec text and one comment, but they already handled it. + +JRL: Okay. So we had support for Stage 2. There’s a new question. Guy? + +GB: Yes. Sorry. Just going through, I was thinking, any guarantee around the proper formness of the string? Can we have an unwell formed string in JavaScript? + +EAO: Yes. I don’t think any of the spec text prohibits that being the result of this thing. There’s stuff in the HTML spec, and in the behavior of any rational implementation, but effectively, if you could wrap that thing in double quotes and you know, pass it in with type JSON, it would probably work with this. The broken thing that you can think of. + +JRL: Michael with the reply. + +MF: You are saying, only supporting UTF-8 in text + +EAO: Not literally in our spec + +JHD: The spec as written, for both JSON and text modules, normatively there’s an assert that a string is a passed, which I believe like its encoding—encoding of that is specified already. And so I think it is sort of indirectly already locked down. I don’t know if that means it’s UTF-8. + +MF: JavaScript string is a sequence of UTF-16 code units + +GB: No. I was finished on that topic. It was an important detail to clarify + +JRL: Another reply from the Nicolo + +NRO: We talk about this with fetch people. And like web people and both text the code and fetch response to JSON already behave the same. Not `response.text()`. These imports follow whatever that is on the web. + +JRL: Skipping Jordan. Nicolo. Guy? Yes. Shane, I think Okay. And I screwed it up. Shane, it’s you. I don’t know what you were talking about + +SFC: Yeah. My question was, also on the character encoding thing which is, there is definitely still very much a real platform out there that don’t use UFT-8 for files .My understanding is that the module loading infrastructure figures this out for you and loads files with the correct encoding such that when they get to be strings then the strings are well formed JavaScript strings. But it also raises the question about whether or not the option should allow for reading files of different files—of different encoding types and whether that should be explicitly part of the proposal or not. If it does what I just described, is—is appropriate. But I wonder if it is also important to specify the encoding of the file at the call site. + +NRO: Can I answer this? So responsive text defaults regardless, like you cannot—you don’t have to say UTF-8. It’s assumed. There is actually a way when fetching, using the content, something like that, it should have a response. When asked to fetch people, we want to assume UFT-8 and ignore the header and force it to be UTF-8. You failed to use it manually to call it. At least the web has a strong preference for the same text UTF-8 at least in API. + +JRL: Okay. And WH? + +WH: If I understand this correctly, this can import arbitrary strings, right? + +EAO: Yes. + +WH: Yes. So here is the issue, JSON is not arbitrary strings; it has a specific structure. So it’s fairly easy to guess if you just look at its first few bytes whether it’s in UTF-8 or UTF-16 big or little endian. I don’t know if any implementations guess or not, maybe some do? But if it’s just arbitrary text, you can still guess but it’s much easier to guess wrong. And that can have some interesting consequences. + +JRL: Okay. That’s everything on the queue now. + +EAO: Would anyone object to Stage 2? + +JRL: Okay. We have had several supporters. There are no objections to Stage 2. I think you have Stage 2. + +EAO: Excellent. Could I have a couple of reviewers? + +JRL: Jordan. Nicolo first An answer to WH. On the web when you— + +JRL: Point of order. We need note-takers if we are going to discuss + +NRO: An answer to WH's question: On the web when to import JSON, it assumes that the bytes are received in UTF-8. It doesn’t do anything else. It parses the bytes as UTF-8 + +JRL: Before we move onto the next point, we need to assign Stage 2 reviewers. JHD and NRO, you have reviewed. Can I volunteer to help you two? + +JRL: Yes to both. + +JRL: Excellent. Thank you. + +JRL: Your Stage 2 reviewers. Jordan and Nicolo + +EAO: At Stage 2, I need editor review as well. MF. Thank you. + +JRL: CZW? + +CZW: So I think—I am not sure if this has been mentioned, but I think the current spec doesn’t specify which encoding and it can be defined by the host, and the host can use whatever they use to determine the encoding for the text. + +EAO: Pretty much, yeah. + +JRL: Nicolo? + +NRO: We also don’t define encoding for JSON modules + +JRL: Shane + +SFC: Yeah. This proposal exposes this encoding problem much more directly to users of JavaScript than any of the other module import types. Import bytes imports the bytes. Right? And then import JSON, import the JSON. Right? And the encoding is, like, JSON has specific requirements about how encoding works to have a well-formed JSON file. But for text files, this problem is a little bit more pertinent, and I think that I would like to—I think that it’s worthwhile, like, investigating whether the assumptions that have been made for previous types of imports still apply in the same way they do here. + +SFC: So I think that it would be good to—I know that a lot of the people on my team, for example, care a lot about text and file encoding and how they work in different programming languages, and I haven’t had the chance to review this. It would be good to spend time investigating that. + +JRL: Okay. And then a couple of replies. Michael? + +MF: I disagree. I don’t see how it’s different from JSON import. It has to be decoded as text before it’s then parsed as JSON. The—and there’s a lot of focus on the encoding here, but our role here is just as glue code basically. We don’t do the decoding. This is up to the platform. The platform can decide its encoding however it wants. If it’s a web browser, it can base it on a Content-Type header. The underlying system can make whatever choice there is. We are overly concerned about things that are not within our domain here. + +JRL: And next is me. I also agree. Let’s assume it’s UTF-8. If it’s not you can use import byte to decode in the exact representation you want. + +JRL: Sorry. I am agreeing we should not do UTF-8 and adding that if you don’t want UTF-8 there is an escape patch for you. + +EAO: Wait. What? You say, we don't—could you clarify your previous statement? + +JRL: Import text can assume it is UTF-8. It should because that’s what the web platform does. If you want something else, you have import bytes, and that gives you the bytes, and you can transform those bytes into anything you want + +EAO: To clarify, you are happy with the JavaScript spec not mentioning any of that + +JRL: Yeah. + +EAO: Cool + +JRL: Shane? + +SFC: Yeah. I assume that what happens when you—if you were to pass a, say, a big-endian UT16 encoded JSON file, and you load it in using import type JSON, then what happens now? If the engine assumes that it’s a UTF-8 file, that fails to parse. And you’re safe. Those errors are allowed and early. Whereas, if you were to pass a UTF-16 big-endian encoded text file into import text, then what you end up getting in those environments is not a failure, instead something with a bunch of, like, replacement characters or something. It’s much less loud if there is actually a problem with the file encoding. Which makes me somewhat concerned. + +JAD: So your JSON file could be like quotes, that start and end. And anything in the middle could be like what means certain characters could be another characters and encoding and you get out a string with unexpected characters in it. + +JAD: Like it wouldn’t have to be an actual failure. Right? + +SFC: The string quote is not a valid UTF-8 syntax character so the JSON has invalid—The quote for the quote is not the same because there’s a null byte involved + +EAO: What Jake is considering is situations when dealing with encoding that is not like UTF16. But is one of the older encodings that looks like UTF-8— + +JRL: Okay. So to begin with we have a point of order of less than 5 minutes remaining. Up next a clarifying question from Keith. + +KM: That same thing with, like, our encoding being for any other WebAPI or I guess probably node any API that loads from a type if the bytes are 16 and get random garbage? + +EAO: Yes. + +KM: Okay. + +MAH: So I agree with Michael. The encoding is not in the realm of the JavaScript spec. It’s a host concern. However, like, it decides to fetch and the bytes and interpret them is not something control. If it’s not matching, if what—if it is not doing its job properly, that’s not something we can control one way or another. + +JRL: Michael, you are on the queue, if you like + +MF: SFC brought up at the beginning of the topic that the Unicode Consortium should get involved in a review. Has this now convinced you? Are we getting back to agreement that that is outside of the scope of this proposal? + +SFC: I haven’t had time to think through this fully. + +MF: Okay. Okay. I wanted to see whether that was still being considered. + +JRL: Andreu + +ABO: About what should be mentioned about UTF16. It can be an issue. But for everything that the specs are doing with regards to encoding, even `response.text()` they are checking whether the actual byte, with a byte mark, and that is UTF—hmm. I am not actually sure right now. I believe it is a UTF16 byte or mark—hmm. I thought I knew this. But it’s, like, this kind of thing is at the very least checked. And it is possible that response checks could in some cases—like, if there is a—like actually decoded at UTF16. It is in any case for UTF16, like files that have a byte that is very full—because the byte order will only get stripped if it is—like if you are decoding UTF-8, it’s only stripped if it’s UTF-8. You have two—I think one character that is not at the beginning of the file. And depending on how you parsing that, that might be enough to realize that there is a problem early on. + +JRL: There is a reply to that from Nicolo. Before that we have 1 minute left. + +NRO: Most APIs don’t—maybe HTML. For JavaScript models we don’t check it. If it’s a byte, it shows up as a character + +ABO: If it’s UTF-8 byte order mark it is stripped. + +JRL: Okay. So a little bit of disagreement. Eemeli? + +EAO: I think given the ongoing conversation about some of the details here that Shane has mentioned, I would like to express interest in having a continuation later in this meeting, if there’s time possibly for a short continuation of 5 or 10 minutes to settle to reach 2.7 here + +CDA: We can go to the half-hour mark if you want to use the next few minutes + +EAO: Shane, do you think that your concerns might get settled in the next 5 minutes, or would it be better to have 5 minutes later after other off-line talks? + +SFC: I would very much appreciate having a continuation on Thursday. Because yeah. I was—the scope of this—the scope of this proposal was a little bit more than I had anticipated ahead of time. So I didn’t spend a lot of time before this meeting reading the proposal in a great level of detail because I didn’t realize it had Intl. impacts and I would like time to do that because that’s why I am on this panel. + +EAO: If there’s no time slot for continuation, I am okay with that. It’s got Stage 2. I have reviewers who seem like they are ready to approve this for 2.7. So I am pretty happy about this. Thank you, everyone. + +SFC: Also, just for the record, also, like, I am very much in support of the problem case this is solving and the general approach that Eemeli put forth which I very much support Stage 1 and 2. In terms of 2.7, I would like to look into more detail. + +JRL: Okay. So last one in the queue. Nothing else. + +JRL: Of course now. + +EAO: Mathieu? + +MAH: If the only thing delaying right now is Shane having time is maybe you could ask for a conditional 2.7 Shane has had time + +EAO: Yes, please. + +EAO: I would like to ask for that. + +CDA: Just be explicit about what the condition is? + +EAO: I am asking for conditional 2.7 at this meeting provided that we get an okay from Shane at some point later in this meeting that he’s okay with 2.7. If he doesn’t give that okay this stays at 2 and return to the topic at a later meeting + +JRL: Okay. That seems fine to me. Any objections? + +JRL: Okay. So conditional 2.7. Congratulations. + +### Speaker's Summary of Key Points + +* In a similar manner to why importing JSON or raw bytes is useful in JavaScript, importing text is useful, and should be just as easy. +* The preferred solution for this is to add support for type: 'text' in import attributes. +* This proposal is a minimal change, riding on the coattails of the Import Bytes proposal. + +### Conclusion + +* The proposal received wide support. Most of the discussion focused on the role of the JS spec in defining or considering the encoding of the imported text. +* Support was given for Stage 1 and Stage 2, with JHD and NRO as reviewers. +* Conditional Stage 2.7 support was received with reviewer and editor approval, pending on a confirmation from SFC that no encoding concerns remain. + +## TypedArray Concatenation + +Presenter: James Snell (JSL) + +* [proposal](https://github.com/tc39/proposal-typedarray-concat) +* [slides](https://docs.google.com/presentation/d/1RIhMpf4gY2wX0KZcmCUU6i9l9Ay7WBu0vY4vIsJUwTg/edit?slide=id.p#slide=id.p) + +JSL: Okay. Yes. So I am—this is for Stage 1 consideration. I am not going to go through every slide because you can go through it. It’s more background of why I want to go here. But basically looking for, problem statement here, we should provide a method of condition cat naturing TypedArrays that enables, that is the key word implementations to optimize performance in some way. + +JSL: I will point out, I use language like zero-copy and lazy copy and talk about ropes and stuff in here. None that have is actually essential at this point. We want to talk about the problem space, not how it’s implemented. + +JSL: But really, this is a long-standing problem. If we look at nodes, nodes had buffer class for a while. It has this buffer concat. We can take two of them. Get back a third one. These things concatenated together. In the language we have set. Already there. We will look at the definition of this in just a few minutes. But it does allow us to kind of concatenate these things. Right? You can allocate the third one to the total length and set that in there. It’s used fairly commonly for concatenation in the web. But still most of the cases you will find out, if you go out and search, is using `buffer.concat` in node or one of the polyfills or other runtimes. This is kind of the fall back. All this set is becoming a lot more common to find. + +JSL: Things that don’t work of course, you know, like array of from—now this is terribly slow using this. But I have seen this in the wild which was scary. Motivating use case. WritableStream is one of the big ones. It’s very common for WritableStream implementations to do this kind of accumulation and then once it’s accumulated a certain amount of data forward that alone. One of the challenges with WritableStream is it’s not—it’s never clear when given one of these. What type of stuff does it accept? Right? The API itself will just take any arbitrary value, it might be bytes, it might be strings, objects, numbers, it doesn’t matter. + +JSL: All you know is that you can write something to it. You never know what is going to be accepted. And one of the common patterns is to either concatenate like this is doing, incrementally as you go or to collect everything into an array and pass the array down. Unfortunately, you never know if something down the pipeline will accept that array or not. Typically, when it accepts bytes, it accepts one thing. A buffer or a `TypedArray` of some kind. The key challenge with this is, this gets really expensive in a lot of pipelines. If you look at service rendering pipelines a bunch of things this pattern ends up expensive and one of my goals, one of my hopes is we come up with a lower cost concatenation. That defers the actual assemble of these pieces, to when they are actually identified. You can end up accumulating these things down to the point where you use the data similar to concatenating strings. There’s other use cases here. By the datagram. I won’t go through all of this. It’s there in the slides. The proposal and again I am not married to any of the syntax. It’s to add a concat operation. It can be done by adding a new API or we can actually modify the set. Set right now, does not account for a host optimized concatenation. If you look at the steps, you know, you go down to that thing and walk-through each individual member of it. + +JSL: So it really kind of unwinds that. And it doesn’t really have a hook in there at all for kind after the HostDefined implementation of how this works. We had a host implementation hook, it could say, I am not going to copy this right now. It’s not the way the spec is written. The way this looks in the writable steam case, basically, eliminating the boilerplate. If the condition cat is deferred, getting back a thing that is stale `TypedArray`: but you know, from the user’s point of view, eliminate the code or buffer or whatever. From the runtime's perspective, we have an opportunity to actually optimize in some way which we don’t really have now. + +JSL: And that’s basically it. I mean, there’s some considerations here. Depending on how we do this, is it an immutable array or mutable. Sizable? Some details to work through. Mixed types. You know, concat a Uint. None of the use cases try to mix them. It’s fine if we fine to say, Uint arrays the same type. But again all of this is just implementation detail to get into later. + +JSL: Some prior art. If you go look at NPM, there are modules like BufferList. They kind of do this pattern. BufferList will create, allow you to accumulate and get back things that act like a buffer. 43 million downloads a week. It’s still very widely used. This is a very common pattern. I would like to see it moved into the language. That’s the preamble. There’s not much to it from there. We can go to the queue, if anyone is on the queue. No? + +MAH: I support Stage 1. I want users to have a way to express their intent, what they want to do, which is putting multiple buffers that they have accumulated together. And you lose that intent in the way you have to do it right now, which is to allocate a new buffer and copy the bytes into it. Everything else is optimization and non observable behavior that the spec is not concerned with. + +JRL: Okay. And Gus? + +GCL: Yeah. I also support Stage 1 for this. I think it's a very, very useful utility that could provide some good performance gains in practice. + +JRL: Olivier? + +OFR: Yeah. I just want to add, since—yeah. I find motivation good just because you added it as the first sentence in your proposal, repository. This will be zero-copy, I—yeah. I really don’t want to guarantee that. So I don’t see—yeah. I don’t see a zero-copy version of this appearing in engines any time soon, to be honest. + +JSL: And that’s fine. The language in the repo there and in here is just kind of aspirational, considering me put subliminal messages in there + +OFR: There’s a bit of a style that—I mean, it potentially unlocks this. But at the same time, I find it problematic when proposals are motivated with such a claim or at least at—such a claim is added to the proposal. When it’s quite a considerable implementation effort to go down that road. + +JSL: That’s fine. Any—moving forward as we progress, that language will be removed so it’s not assumed up front. + +JRL: Before we move on, is yours a reply to the current topic? About ropes? I assume so. + +YSZ: Maybe. I have one question or comment basically, V8 SpiderMonkey JavaScript, everyone is having issue… like recreate very large storage undertaking or small rope and it ends like something is taking a very large storing forever with something and like the memory is considerable or harder to find what is—given this substring is try to be mentioned in registering. So I kind of like the feeling like a rope or this thing is a bit hard to manage in terms of memory.size, life cycle. Express the data structure like—rope or something much more explicit, instead of hiding behind is a `TypedArray` + +JSL: To respond on that, at this point, my concern is more about being able to have the ability to optimize in the language rather than necessarily worrying about how it’s optimized. Right now the hook is not there to allow us to optimize and that’s what I want to make sure is there. + +OFR: Yeah. So one thing to add, I think it is actually possible—there is potential to optimize here because we can do the concatenation at once. We can allocate the correct buffer size and put everything in. The proposal brings potential to optimize this. However, ropes have annoying performance cliffs and we see those in strings all the time. And we don’t—we don’t like actually that we have ropes in strings that much. Because, for example, if you do something like index or a find or whatnot, and they also tend to be very imbalanced in practice and so actually, it causes a lot of pain. + +JSL: Yeah. It’s taken me a year to work up the courage to bring this proposal specifically for that reason, I don’t want to go down that same path but you want the optimization path. Daniel? + +DLM: We share of the the implementation concerns that have already been raised + +JSL: WH? + +WH: I support Stage 1. I also have a question: So far the discussion has been about just using a lazy concatenation strategy. I am curious if something like doubling of the buffer size would be acceptable here? + +JSL: I think so. + +WH: Okay. So we will just leave it to implementations to define how it’s done, as long as it’s reasonably efficient? + +JSL: Yeah. That’s where I am at right now. + +WH: Thank you + +MAH: Yeah. So these are not Stage 1 concerns. But reading this, we have a few observations that are Stage 2 scope. Concat is a confusing name. Concat is an instance method on strings and this presentation here and what node does is for a static method on the Buffer constructor. Also We want to figure out how to create a concatenation of immutable ArrayBuffers that is born immutable so that you don’t need to do a transferToImmutable step. But all those things are Stage 2. + +JHD: is there a proposal repo? Stage 1 does require one. It can be conditional based on adding the repo though. + +JSL: Yeah. Let’s do that. + +JRL: So yeah. Okay. Leave it—conditional Stage 1. So, do we have support for conditional Stage 1? We got it from WH. Anyone else? Jordan? Sorry MAH too. Also, Chris supports. Okay. Are there any objections? Without objections you have conditional Stage 1. Please make a repo. + +JSL: Okay. Thank you. + +### Speaker's Summary of Key Points + +* Concatenating TypedArrays is a very common use case, particularly in uses of WritableStreams, and others. It is, however, fairly difficult to optimize for. Developers need to either manually allocate and copy using `TypedArray.prototype.set` with manual offset calculation, multiple allocations, etc, all of which makes it slower, or they need to rely on non-standard APIs like Node.js' `Buffer.concat`. +* The problem statement is essentially: We should provide an optimizable way of concatenating multiple `TypedArray` instances in a single operation that affords implementations the opportunity to optimize. + +### Conclusion + +* Conditional stage 1 was accepting pending the creation of the github repo for the proposal. + +## TypedArray Find Within + +Presenter: James Snell (JSL) + +* [proposal](https://github.com/tc39/proposal-typedarray-findwithin) +* [slides](https://docs.google.com/presentation/d/1RIhMpf4gY2wX0KZcmCUU6i9l9Ay7WBu0vY4vIsJUwTg/edit?slide=id.g38e87ed9df8_0_0#slide=id.g38e87ed9df8_0_0) + +JSL: This one is equally simple. We have indexOf. We look for individual… you know bytes or elements within that. It is very common though to look for subconsequences. Node supports this in the buffer. Buffer actually overwrites indexOf to support searching for subsequences. We find this is—searching for subsequences in a lot of web apps, I think like Next.js does it. Quite a few others. And it’s really best to provide a method for searching for a subsequence within a `TypedArray`. That’s the problem statement. + +JSL: I have really no syntax suggestions on this. No, you know, I am coming with how this is implemented. It’s how I would have imagined, an implementation defined mechanism. The whole point is just find the location of the subsequence or determine if the subsequence is there. It’s like a find and a contains. One that returns an index, the other returns a Boolean. And ask is Stage 1 conditional again. I need a repo. But yeah. Super straightforward. + +JSL: Not seeing anyone on the queue. + +JRL: Okay. Give it a second. + +MAH: So… I think our main observation is there is kind of—it’s all about keeping the language consistent. And finding—so right now, we have indexOf on the string method. We have included an array. If we go with something that has slightly different syntax again, should we introduce that slightly different syntax array or iterator? So again, it’s not really Stage 1 concern. Because this is the—the problem statement we’re supportive. But we want to be careful about, like, how far we name things and the exact semantics because it overlaps with strings because it’s a multielement match really and array are single element find. So how to—not get developers confused really. + +JSL: That’s an excellent point. I would be absolutely fine if we defined this in general terms. As part of the iterator protocol, basically find a subsequence within the iterator. So… + +JRL: Up next is WH. + +WH: My point is very similar to the one that was just made. I fully support exploring the problem space, curious what the API will look like. I hope I don’t have to learn another API different from all the existing ones. I also hope I can do things like search backwards. + +JSL: And then Keith? + +KM: If you want it to be—I guess on the iterator topic, the iterator version is far less likely to give you the purview you want. Iterator protocols are super complicated in JavaScript and you need to do a lot of herculean effort and they are a lot of work and have to be done separately. In a general way, it’s very specific to exactly one case and it’s not going to fall off a cliff if you use it in some other way and it’s better to avoid that. Unless, like, I mean maybe I can imagine some hypothetical future, all the engines have optimizers, iterators and clean abstraction for it. As it stands today, it’s—many years until the place if it ever happens. I guess my two cents is—do not do the iterator version and add as a separate thing and not recommend it. But… + +JSL: Okay. You have a + 1, but I am not sure what you are + 1ing + +JRL: The iterator protocol + +JSL: And Chris, support for Stage 1 and I am—assuming that’s conditional Stage 1. + +JRL: Okay. So you are asking for conditional Stage 1 on creating a repo? + +JSL: Yeah. + +JRL: We have support from Chris. Anyone else? JHD, MAH + +JRL: Okay. Any objections— + +WH: I support this. + +JRL: WH, thank you. Are there any objections to conditional Stage 1? + +JSL: All right. Congratulations. That was easy. Thank you. + +JRL: Okay. We have 10 minutes left. Is there anything short to discuss? + +### Speaker's Summary of Key Points + +* While `TypedArray` has provided the ability to search for individual elements using indexOf, a common case in the ecosystem is searching for a sequence of elements (location) or determining if the `TypedArray` contains a subsequence of elements (predicate). This is often achieved using slow polyfills that are difficult to optimize. The proposal is that the language should provide a sub-sequence ("find within") search that can be optimized by implementers. + +### Conclusion + +* Stage 1 is accepted pending the creation of the github repo + +## TypedArray byteOffset Mistake + +Presenter: James Snell (JSL) + +* no proposal +* [slides](https://docs.google.com/presentation/d/1RIhMpf4gY2wX0KZcmCUU6i9l9Ay7WBu0vY4vIsJUwTg/edit?slide=id.g38e87ed9df8_0_0#slide=id.g38e87ed9df8_0_0) + +JSL: I wasn’t going to bring this up. I throw in the slides to have it there. I was going to bring it up in a later meeting. ByteOffset is a problem. I see this in practice a lot with subarray. Basically a mistake that is common with a lot of developers. It creates the larger subarray. The large array, the developer takes a subarray off of it and completely forgets to check byteOffset and byteLength on those. On the underlying ArrayBuffer. And tend to, you know, like to completely forget it’s there. It would be nice again—don’t worry about the syntax. It’s nice to have an option at some point to still take a subarray view of that thing but have the ByteOffset set to 0. So this mistake can be avoided or you can actually just, like, ignore the fact that this is actually a view on a larger view + +JRL: Can you make it larger + +JSL: I can try. Hold on. + +JRL: If you just hit the slide show, does it not present the slide? + +JSL: Let’s see. It does, but I don’t make it larger + +JSL: On the larger, you create a Uint8 subarray off it to create a view and pass the view off to something else that it doesn’t realize it needs the check ByteOffsets. A very common problem. It would be nice to create those views so it’s not obvious it’s a view. And if somebody forgets to check that, it still does the right thing. + +MAH: This sounds somewhat related to Jack’s proposal about limited views. Basically, constructing a view for which you cannot get back the wider ArrayBuffer. I don’t know. There may be—I know a lot of that proposal got subsumed by the Immutable ArrayBuffer proposal. But there were still a lot of other things that the proposal had and this seems like one of them. So maybe it’s still motivated to keep exploring that. + +JSL: So I was not prepared to ask for Stage 1 for this. But if there is another support for it— + +JSL: Nice. Okay. + +JSL: Then we can go from there. + +JSL: Okay. Perfect. + +RPR: Nothing else on the queue. So that wraps it up. Thank you, everyone. + +### Speaker's Summary of Key Points + +* This was an unplanned discussion given we had a few extra minutes. The byteOffset property on TypedArrays continues to be tricky for users who often forget they need to account for it in case the `TypedArray` is a view on a larger ArrayBuffer. It would be nice to have an option to effectively hide that such that they don't have to. + +### Conclusion + +* There is an existing proposal that can be progressed to address it. See https://github.com/tc39/proposal-immutable-arraybuffer diff --git a/meetings/2025-11/november-19.md b/meetings/2025-11/november-19.md new file mode 100644 index 0000000..e7c11bb --- /dev/null +++ b/meetings/2025-11/november-19.md @@ -0,0 +1,1264 @@ +# 111th TC39 Meeting + +Day Two—19 November 2025 + +**Attendees:** + +| Name | Abbreviation | Organization | +|--------------------|--------------|----------------| +| Chris de Almeida | CDA | IBM | +| Dmitry Makhnev | DJM | JetBrains | +| Philip Chimento | PFC | Igalia | +| Matthew Gaudet | MAG | Mozilla | +| Jonathan Kuperman | JKP | Bloomberg | +| Richard Gibson | RGN | Agoric | +| Waldemar Horwat | WH | Invited Expert | +| Anthony Fu | AFU | Vercel | +| Daniel Minor | DLM | Mozilla | +| Martin Alvarez | MAE | Huawei | +| Eemeli Aro | EAO | Mozilla | +| Devin Rousso | DRO | Invited Expert | +| Caio Lima | CLA | Igalia | +| Ross Kirsling | RKG | Sony | +| Keith Miller | KM | Apple | +| Yusuke Suzuki | YSZ | Apple | +| Christian Ulbrich | CHU | Zalari | +| Joshua Goldberg | JKG | Invited Expert | +| James Snell | JSL | Cloudflare | +| Lea Verou | LVU | OpenJS | +| Chip Morningstar | CM | Consensys | +| Ron Buckton | RBN | F5 | +| Daniel Rosenwasser | DRR | Microsoft | +| Istvan Sebestyen | IS | Ecma | +| Ashley Claymore | ACE | Bloomberg | +| Jacob Smith | JSH | OpenJS | +| Andreu Botella | ABO | Igalia | +| Chengzhong Wu | CZW | Bloomberg | +| Guy Bedford | GB | Bloomberg | +| Gus Caplan | GCL | Cloudflare | +| Jake Archibald | JAD | Mozilla | +| Jordan Harband | JHD | Socket | +| Kevin Gibbons | KG | F5 | +| Mathieu Hofman | MAH | Agoric | +| Michael Ficarra | MF | F5 | +| Mark S. Miller | MM | Agoric | +| Nicolò Ribaudo | NRO | Igalia | +| Olivier Flückiger | OFR | Google | +| Ruben Bridgewater | RBR | Invited Expert | +| Rob Palmer | RPR | Bloomberg | +| Shane Carr | SFC | Google | +| Stephen Hicks | SHS | Google | + +## Async iterator helpers recap/update/polyfill + +Presenter: Kevin Gibbons (KG) + +* [proposal](https://github.com/tc39/proposal-async-iterator-helpers/) +* [slides](https://docs.google.com/presentation/d/1nQvAwvOQ0gDJ-eLIVIy3rYrlZj3qGvPHCeH_Veba2cc/edit?usp=sharing) + +KG: So I apologize that this proposal has been taking so long. A combination of complexity and me having had a child. But I am hoping to get consensus, or at least agreement on certain points. I am hoping to resolve one question about scope and then come back with spec text and Stage 2.7 soon, I hope. No promises there. I thought I would be ready for the last several meetings and it hasn’t happened yet. So we will see. You can find the proposal in Github of course. + +KG: Recap. Very briefly, I am not going to keep going through this every time, but the general idea is you have using a function like `.map`, with an async iterator, this produces an async iterator which you can in principle pull from multiple times, without first waiting for the previous values to settle. The code that you see on screen, it is perfectly legal to write. The idea is that I want to make the `.map` able to perform fetches concurrently in this particular case. + +KG: So I have some principles that I am trying to use to design the APIs here. Also looking at this I am realizing that I had at least two more that I meant to write down and didn’t. The first one is of a funny one with the consuming iterators, for example, `.some` or `.every`, these are necessarily potentially going to lose values. Like, the—if you try to do those concurrently, there’s no support for that in this proposal, you will necessarily be losing a value because the—the consumer is only going to produce a true or false end. By losing values is that it will pull from the underlying iterator, and it potentially pull multiple times from the underlying operator, and those values are never exposed to the user. If you imagine the underlying iterator is yielding file objects or something by which needs to be done, I posed, consuming those with `.some` and doing so concurrently, there’s no way to decompose the values produced from the underlying operator. That’s inherent to how those works. That is not necessarily inherent to how map and filter and front map work. For the ones that do pass the predicate. They don’t need to be dropped. This has some odd implications for the design, which I will get to on the next slide. And this is also rarely going to matter because almost all consumers are going to drop values anyway. So, for example, if you are using a for loop over the result, the for loop is going to stop the first time it sees an error, or something that says `{done: true}`, for example. And so the for loop will not continue consuming the iterator past that point and the values will still be dropped. But it’s possible to consume these manually in such a way that the values that are produced by the underlying iterator are never just dropped on the floor. That means they will always end up potentially after being passed through a mapper function as a result of a call to `.next`. Then we will get to the implications of this principle in the next slide. + +KG: Also, I want to say that the results are race free. But only up through the first promise or `{done: true}`. What race free means is that if you call `.next` multiple times, you should see exactly the same results as if you called it just once and then waited for the Promise to settle and then called it again. This makes it much easier to reason about. + +KG: Originally, I had wanted to preserve this property even after `{done: true}` and so forth. But that’s not possible to do consistently with the previous principle. So, for example, imagine your mapping function throws for the first, like—the very first time it’s called. But not the second time it’s called. And you pull from that twice. The first Promise is going to be rejected. And if we were trying to maintain this property that `{done: true}` would be the natural thing you would observe the next time, if you are pulling one other time, then we would have to do that same behavior if you are doing that two at a time. That means that the value would get dropped on the floor. So the first principle makes it impossible to say that the second principle is maintained, even in the case of rejected promises and completed promises. So we slightly weaken it to say that it’s only through the first rejected promise or done true that we preserve this sort of race free. You can’t tell you are doing things concurrently property + +KG: The last thing is more debatable. Which is that I want to say that once a consumer of one of the map or filter or sum functions has observed from the underlying iterator, a `{done: true}` or something similar or produced such a value itself, it will not further consume the underlying iterator. This requires the consumer to be maintaining its own internal state. By that I mean the consumer keeping track of whether it’s closed or not. Basically. + +KG: So I have not a precise polyfill but an illustrative example on the slide of how the map ends up working. There’s a lot of complexity. And we will talk about a couple of pieces, but most of the complexity is just around keeping track of whether the iterator is done. So that they—we need to wrap calls to the underlying iterator so that we can mark our own iterator as done in case the underlying operator throws. That sort of thing. + +KG: And I am not totally sure this complexity is warranted. The point of this, all of this complexity is to maintain this last thing on the slide. Which is how iterators normally behave. But I don’t think it’s that important to behave this way. So the consequence of this is that if you, for example, close the result of the mapper function and call `.next` again, if we are trying to maintain the third principle, it—the iterator here, the result of the mapper needs to know whether the dot return call has happened previously. So it knows whether to forward the call to the underlying iterator. It’s an open request in my mind whether it’s important to keep track of this. Again, the sort of natural way to write this as a generator or something would absolutely prevent this call from being forwarded to the underlying iterator. There’s not a necessity for that. If the consumer is trying to do something like what’s on the screen here, which is a weird thing to do, we don’t necessarily need to try to save from it or protect the underlying Iterator from it. And certainly it would simplify the implementation, especially for `.map` which is by far the simplest one, if we didn’t have to keep track of this state internally. + +KG: So I welcome feedback on that, but I am leaning not to maintain the third principle on the slide, because of the complexity it adds. + +KG: Okay. And I have a couple of more questions I want to get to, but do we have anything on the queue for that specific topic before we move on? + +DLM: There is a clarifying question from Waldemar + +WH: Can you go back to the principles slide? What does “first” mean on this slide? You can create promises and resolve them in a different order. Which does “first” refer to? + +KG: Which one of these says first? Yes. Good question. What I mean is, first in terms of the sequence of promises that resolves, regardless in which order they settle. So, like, you produce five promises, let’s say by calling `.next` five times. Let’s say that the fourth one immediately settles with `{done: true}`. And then subsequent to that, the second one, rejects. Number 2 rejects after number 4 has already settled with `{done: true}`. The consistency—the race-free only goes up to number 2 in that case. So you don’t get this race freeness when things are settling out of order if earlier things are being rejected. Like, earlier sequential things. + +WH: I think I understand. + +KG: I apologize that there’s not a slide here. Not a sample here. + +WH: Okay. Continue, please. + +KG: All right. And then, the next thing I wanted to talk about was not originally in scope, but it keeps coming up in examples that I try to write or that other people happen upon in their own lives. Which is that you often need to do clean up. Technically this is true for synchronous helpers as well, but it ends up coming a lot more when you are doing async stuff. An example, one I have on the slide, is to imagine that you are mapping user IDs to databases, so you're taking each user ID and doing a database lookup and you want to close the database when you are done. This is a fairly normal thing to happen. The problem is you are producing an async iterator and there is just no way with the code here to say that you are done, to be notified that you are done. The async iteration protocol has a method, `.return`, which is called when the iterator is early exited, although it’s not called when the iterator is just exhausted. But there’s no way to hook into that method if you are using one of the helpers without manually wrapping it, which you don't want to do because the helpers support concurrency and any async generator wrapper will negate any concurrency. So ideally, we should have a way to hook into the call to `.return` so we can do cleanup here. And probably we will want this cleanup to also happen when the iterator is exhausted because within syntactic async generators it’s easy to clean up when you reach the end of the function with a finally or whatever but there’s no way to do that with iterator helpers: if the iterator helper is holding on to resources, you need to have the cleanup function be called on exhaustion and on early exit. + +KG: Also, you sometimes need to do cleanup eagerly. I guess I should say, a mental model for iterator helpers is that they are sort of wrapping something underlying. And from that point of view, you would probably expect that the cleanup function for the wrapper would only get called after completing the cleanup for the thing that it wraps, i.e., in stack order, the same way it works for `using`. Like the iterator might be depending on some resource that is held by the underlying thing so you need to finish cleaning up that underlying thing before you clean up the other thing. That’s true in general. But in some cases, you actually want to do the cleanup more eagerly than that. I am hoping people are familiar with `AbortController`, but for anyone who is not, it just gives you a signal and the signal calls a callback when the abort method is called on the controller. So it’s a simple way of signalling cancellation, many things on the web platform and many APIs support passing a `signal` parameter as a way of aborting asynchronous operations. You might hope that if you are using one of these async operations, inside of an async generator, then if you early exit from the async iterator produced by the async generator, it could call this `finally`. But it doesn’t. Because the way async generators work is that they are sequential, and each call to `.next` has to settle before the call to `.return` even triggers. Now, I think that for async generators that is how it has to work. Just syntactically, we can’t have the `finally` in this example start running while the code is paused at the await. That’s the whole cancellation debate and the resolution is you don’t have a way to cancel arbitrary operations, so, fine. But you really want to be able to cancel this particular operation because there’s no way that you will make progress past that `await` without actually finishing the operation, so you have this sort of double bind, where the thing that would tell the operation to finish can’t run until the operation finishes. So on the previous slide I was discussing, a natural way of thinking about cleanup is that it’s inside out, it’s in stack order. But in this case, you would want the cleanup to run before calling any internal cleanup. + +KG: So the question is, do we want to support having a cleanup method which is called before the underlying thing gets called? So for places like this or an iterator helper where you need to pass the abort logic into the inner thing rather than waiting for it to abort first. And I think we probably do. I think we probably want to support both. Because these cases do come up in practice. Is this something that is worth adding in the initial version of the proposal? I think this comes up enough to be worth doing. It’s one additional method. We would have to bikeshed the name. I think we can probably get away with leaving it out, because nothing else in the design of the proposal actually depends on it. But it does come up a lot. Yeah. I mostly just wanted to get the committee’s attention on the cleanup issue, and especially in the context of async consumers because they come up a lot. If anyone feels strongly it should be in the initial version of the proposal, please talk to me. Okay. + +KG: Nothing else on the queue? + +DLM: Sorry. Waldemar on the queue. Waldemar + +WH: I am not quite sure what cleanup would do here. If cleanup is just a function, then whatever is triggering cleanup could call the function. So what is it doing other than calling the cleanup function right away? + +KG: Right. I apologize for not having this example written out. Like I said, I’ve been ill. + +KG: So the idea is… this function that is producing an async iterator, wants to produce an async iterator which will have its cleanup method called when this loop exists. If you are writing syntactically an async generator, you do: + +```javascript +for await (let item of getAsyncIterator()) { + if (condition) break; +} + +async function* getAsyncIterator() { + try { + let resource = await acquire(); yield await fetch(resource); + } finally { + resource.release(); + } +} +``` + +This already works more or less today. You can have an async generator hold on to a resource and then release it in `finally`, because `finally` will get triggered when the break happens. This code is all legal today. The problem is, there’s no way to do that if you are doing something with an iterator helper as on slide 7. If this example on screen is my `getAsyncIterator`, where do I put the release logic? + +WH: Okay. I understand the problem. + +KG: Yeah. So this is why I think that it’s potentially worth including in the initial version of the proposal because there’s just no way to put any release thing here, other than manually drafting on a dot return function. + +WH: Thank you. + +KG: Okay. I didn’t have anything else. This is again a call for people who are interested in asynchronous iteration to come talk to me. I believe we will be talking about this a little more later in the meeting with concurrency. I guess, yes, we haven’t got to that topic yet. Yes, we will be talking about this a little later in the meeting. I want to emphasize that this property is inconsistent with getting optimal or even like especially good throughput. Because you are always forced to wait for the first result to settle before the consumer can start processing it. I think that that’s the right behavior for an async iterator by default. The calling document upon it, should not change the order of the results. Sequences are naturally ordered. Messing with the order is weird. Preserving that property, you get order, get results out in the order they went in, it means that you are fundamentally limited in the throughput. So I think that’s okay. We will talk later about the fairly common case where you don’t care about the order and you want to produce things as fast as they come in. You into a different set that is not in this proposal. The plan is, proceed with this. Don’t include cleanup, even though I think it ends up being basically necessary for cases like this. The—it proposal has taken long enough already. I will have a number of follow-ups if we are able to make progress on this, or if anyone else wants to help because I don’t have to be the only person championing this if anyone else is interested. + +DLM: Chip? + +CM: You were raising the question about whether the support for teardown should be in the first version of whatever this is. + +KG: Yes. + +CM: I wanted to share my perspective which I think it needs to be. The need is real. If that is not provided for, people will probably come up with a variety of ad hoc workarounds to cope with this and some of that stuff may be awful and introduce horrible ecosystem noise that we will have to deal with when we finally do get around to adding that. + +KG: That’s a very good point. + +DLM: Michael? + +MF: I am not too concerned about that risk. The awful things they do, yes, they will be awful. But they will still work. No matter what we do introduce, like, they are not going to break the patterns. The biggest risk is they end up setting a precedent and the community goes with that, and whatever we provide ends up having to be inspired by it somehow. I don’t think it’s—like, I—somewhat agree with you, there is a risk. I just disagree about what the risk is. I don’t think it’s a compatibility risk. + +DLM: Point of order. We have 3 minutes left. RGN, you are next. + +RGN: I think I largely agree with MF. KG did a good job of describing the problem. And he’s right that it will come up for anyone who interacts with this. But really, all the solutions for it, I think, are isomorphic to each other. You have to stick something along for the ride where you can register a teardown callback or stick a promise on it that you can subscribe to or something along those lines. And, yeah, I mean they all have different particulars, but fundamentally, the behavior is interconvertible. So I think I would like to see something, if we come up with a really good shape, but if we don’t, then there’s just going to be a variety of largely equivalent solutions in the ecosystem. + +KG: Yeah. The precise equivalent—it depends on what you mean by equivalent, but—there is actually a fairly important distinction in whether the cleanup function runs before or after doing cleanup on the underlying iterator. And like those are pretty subtle differences. So I would worry a little bit about if we do something that is different from ecosystem precedent. On the other hand, like I said, I think we probably want to support both. So it probably doesn’t end up mattering in practice. + +RGN: Agreed. + +DLM: Okay. Looks like that it’s for the queue. + +KG: Okay. I apologize for this proposal taking so long. I am not asking for consensus or anything. And I will get the code in the notes after my next presentation, because I think I am next. + +### Speaker's Summary of Key Points + +* Proposal for async iterator helpers continues. +* Principles: values are not lost, results are race free _up to first rejection/done:true_, if a consumer sees {done:true} then the underlying iterator will not subsequently be called. + * the last point may be dropped. +* Async iterator helpers are ordered, which means they cannot be maximal throughput. +* We probably need a helper for doing cleanup, which may or may not be in this version of the proposal. + * There was some support for including cleanup in v1, but some people thought that, while such a thing would be needed, it need not be in the initial proposal. + +### Conclusion + +No conclusion sought. Interested parties are invited to continue participation on GitHub. + +## Iterator Join for stage 1, 2, or 2.7 + +Presenter: Kevin Gibbons (KG) + +* [proposal](https://github.com/bakkot/proposal-iterator-join) +* [slides](https://docs.google.com/presentation/d/1jclIOSbSdyepVCiYXQ4eXc2Uh8FBnBKnFOtsx12N3r0/edit?usp=sharing) + +KG: Hopefully, this presentation will be a little more coherent because it’s a simpler topic, despite me putting it together literally at 3 in the morning when I couldn’t sleep. + +KG: Right. So this is a new proposal for synchronous iterators. My fundamental thesis is that it should be easier to concatenate the contents of an iterator into a string. It comes up a lot. I will make the case for this on the next slide. But take my word, it does come up a lot. Many, many people are writing code that does this. + +KG: You can do it with an iterator today, but you use `.reduce` or `Array.from`. `reduce` throws if the iterator is empty, or you need extra logic for the first element. Of course, converting to an array, you are allocating the entire array which you're just going to throw away. So I don’t think the current solutions are particularly good. + +KG: Just to make the case it comes up a lot, this is a code search on Github, showing 1700 results for just specifically a `Array.from(something.keys()).join()` We have specifically something with a keys iterator, and we have specifically putting it into `Array.from` to `.join` it. And there's the same number of results if using array spread instead of `Array.from`. There’s just thousands and thousands and thousands of examples of people already doing this, converting an iterator they already had into an array so they can call `.join` on the result. + +KG: So I hope you are convinced that this is a problem worth solving. That it does indeed come up a lot and the existing solutions are no good. Before I move past that, I would like to ask for Stage 1 for this problem statement / thesis. + +KG: This is me asking for Stage 1. Any objection or support? + +DLM: We have MF with airing of grievances. + +MF: So in many ways, I hate this proposal + +KG: You can air your grievances on Stage 2. Your grievances are not Stage 1. + +MF: You are correct. Fine. + +DLM: Okay. I guess—are there any objections to Stage 1. + 1 from MAH. That’s two voices of support. Any objections? No? +1 from WH and MF and from CM. + +KG: Okay. Moving on to the part that MF will object to.. So a concrete proposal. I think this should be `Iterator.prototype.join`. It works like `Iterator.prototype.join`. So, what are the alternatives? We could, for example, have a general collect method on iterators. And/or have a method perhaps on `String.prototype` that takes an iterator. That’s how Python’s `join` works. You have a string and call `.join` on the string and pass the iterable. That works fine. If we were designing a language in the abstract from scratch we might choose to go that way. But we’re not. We already have `Array.prototype.join` and that’s what everyone is familiar with. It’s important to keep the symmetry. The naming, I know that "join" is a heavily used word. There’s lattice join, there's joining threads. And of course there’s `Array.prototype.join`. But "join" is what the ecosystem has settled on for this operation. We are not introducing a new term in the language or into the ecosystem. But it’s not like even the type theorists in JS are using "join" to mean something else. Ramda has join. Immutable has a collection join. Every general purpose utility library JavaScript which has this functionality has called it `.join`. And in any such library that has a method called `.join`, it is this functionality. Also, it’s not just this functionality in broad strokes. They also have the precise behavior where it calls toString on the array elements and separator. As you are aware, I think this is a dumb thing to do in general. I really don’t like the way the language works this way. I think in any API that is not copying an existing API, we shouldn’t do this. But we are copying an existing API. My position is that this should work just like `Array.prototype.join` in that it should do coercion. Despite our aversion to coercion. + +KG: And here's the spec text. You can see the toString calls in here, this is `Array.prototype.join` + error handling and iterator handling. Right down to the single letter variable names which I don’t love. + +KG: Okay. That’s the proposal. I am requesting Stage 2 or 2.7 given I have spec text but it’s not been reviewed. Yeah. Let’s hear MF’s grievances and anyone else. + +MF: I agree with you. I don’t like the fact that it’s called join. I don’t like the fact that there are alternative, more generic versions of this that possibly obviate it. I really don’t like that we ToString the argument. I don't like the argument being optional and defaulting to a comma. Given all that, I realize this is probably the best we can do and I support this proposal. + +KG: I appreciate your support. + +DLM: Next up we have Ron + +RBN: Yeah. You mention in the slides prior art in ramda and I think some other libraries that use join to do the string-concatenation similar to `Array.prototype.join`. A lot of that comes that’s what `Array.prototype.join` does. But when it comes to actual queries, you can see that in ramda where it has both a join that does the string concat and a group join which is actually like a database join operation between go sets of data that there is some overloading of terms that we think through as this—before this gets to something or before we like really settle on join as the name. Not that I don’t think we couldn’t progress with join, but we need to be aware that there—if we do want to have any type of this more complex query operations to consider that potential overlap in terminology. + +KG: I feel extremely strongly that we should not use `Iterator.prototype.join` to mean anything other than this. I agree, it’s an overloaded term. But the overloadedness is already inherent to the language—it’s not something being introduced here. The particular meaning of join as `Array.prototype.join` is already inherent to the language. And I think as a consequence, regardless of the proposal, any future proposal that is doing any other notion of join would already need to deal with the fact that the term is overloaded because of its presence on `Array.prototype`. This is one of the most common methods people call in JavaScript already. I don’t think putting it on iterator prototype as well meaningfully changes anything about that. + +RBN: I do a certain thing, with `Array.prototype.join` you are dealing with something that is a fixed length. You can know that by looking at length as to maybe how costly the operation is going to be. When working with something that is an iterator, you don’t know what the size of this result is going to be. It could progress infinitely, it could just be a very large set and you have no way of calculating that cost. So I am a bit concerned that a join of this approach is a little bit—it might hide the underlying cost and complexity that you would expect for something like array. + +KG: So it’s true that in some cases, in the maximally generic case, you don’t know the size. That’s not anything like universally true. The example that I had is that you are joining the keys of a set or a map and in those cases you know the size. It’s not present on the iterator itself, but it is present in the collection from which the iterator is drawn. I think that's a perfectly reasonable thing to do. Yes, that is going to blow up in your face if the iterator is infinite, and it’s true if you are writing maximally generic code someone may hand you an infinite iterator. But in most cases you know that’s not a problem and you want to write natural code for those cases. + +RBN: Some and every do have short cuts out, though. A join does not. Join will always have to progress to the end, whereas some can progress until it matches. + +KG: forEach doesn’t have a short cut. Or, most of the time you would be using reduce. + +DLM: RGN is on the queue + +RGN: There’s no bailout here but the point is moot. People are already doing what is on screen now. Throwing iteration results in a temporary array just to call join. So the fact that a big iterator will blow up is already an issue and not affected by the introduction of an iterator prototype join. + +DLM: Okay. Next up we have SFC. + +SFC: Yeah. I was looking through the—the—the queries that you found on Github for the different places people are calling this. It seems like the—most common cases are, for example, when you need to do a debug output. There’s people who do that and pass to a `console.`log and in a lot of cases people build up SQL queries or other-related like putting stuff in syntaxes. And then the third is, calling join with the empty string. Where you just take them all and concatenate them. So in `Array.prototype` we have `.toString` which is more useful for doing debug output. There’s also `toLocaleString`. Right? Which doesn’t actually do a very good job at toLocaleString because it uses a locale specific separator, but doesn’t do list formatting. We had to take it open for a while, toLocaleString on should do list formatting. Web compatibility. But add another function for that. Maybe it could go on here. I am wondering your thoughts on why we should use join or—or whether we should consider having more specialized functions maybe like `.concatenate` and having some sort of like toString function that is more debug oriented, using `.toLocaleString` for debugging. Or it’s motivated to have a general purpose join function. + +KG: I think it’s motivated to have a general purpose join. A lot of the examples don’t want the toLocaleString. The second example on the slide, that was the screenshot which is building up a range header, which is a comma separated list. There's lots of comma separated lists in the world. And I think this comes up enough in exactly this form for it to make sense to have in exactly this form. This is what people will reach for. + +KG: Separately, I agree with you, having an operation for doing list formatting of like—locale-based list formatting is useful. I wouldn’t want to put it on `Iterator.prototype`, at least not under the name `.toLocaleString`, because I think people pretty naturally will expect that to work the same way it does for arrays if it is present with that name. So my preference would be to put it somewhere else. Potentially `Intl` and have it take an arbitrary iterable, which I am pretty sure is already how it works. + +DLM: Reply by Ashley. + +ACE: I think if the suggestion is, we should have like `Iterator.prototype.toString`, yes, that’s maybe convenient. But I think what happens more often is people accidentally `toString`ing something, but not thinking about it. And with the case with an infinite iterator, calling `.toString` implicitly somewhere that’s makes me more nervous. I wouldn’t want `toString()` on iterator to be called implicitly. Obviously there is a `.toString` on `Object.prototype`, but it returns a rubbish string and it's usually obvious as suddenly the train timetable says `[object Object]`. Whereas infinitely looping is a much worse bug. + +KG: I agree with that. One of my favourite examples of this is that if you call `Math.max()` and pass an array you get NaN out. Maybe not what you expect. But it’s because it’s calling `.toString` on its argument. And then parsing that as a number and it’s just generally very strange. + +DLM: Okay. Just a quick reminder, 5 minutes left. Shane? + +SFC: Yeah. To be clear the previous question was exploring what you see as the space of, like, what functions should eventually land on the iterator prototype and how this fits with them. I think that given `.join` is fairly explicit about taking the elements in joining them with a separator, I don’t think there is a—I think that it’s fine and harmless in terms of, you know, like it could even coexist with some other potential functions, like exploring a locale prototype function. They would coexist and would be fine. I support it. + +KG: Yeah. I agree there’s a lot of space for things vaguely adjacent to this. But I want to keep this scoped to just the one thing. + +DLM: Okay. Looks like the queue is empty. We should ask for explicit support for Stage 2. + +KG: I guess 2.7. + +DLM: We should do 2, first, I believe. And then— + +KG: Okay. Sure. I would like to request support for Stage 2. + +DLM: Okay. We have a ② from WH. With a little circle around it. MF volunteers as a reviewer, which I will take as support. And that’s two voices. Any objections? No. JHD will also be a reviewer. I think with that, we can say you have Stage 2. + +DLM: For 2.7, you need the reviewers to sign off on the spec text, as well as an editorial approval + +KG: I am an editor and I approve. + +DLM: Does that count? MF is an editor and approves. + +DLM: Any other voices for 2.7? Just as a formality. Or objections? + +KG: Okay. I guess just can I get explicit support for Stage 2.7? + +JHD: I reviewed it and it’s fine. Good for 2.7 + +DLM: Good for 2.7. And 2 minutes left to spare. + +KG: Okay. Thanks very much. Thank you. + +### Speaker's Summary of Key Points + +* Joining an iterator to a string is a common operation. Right now people have to `.reduce` or `Array.from()`, both of which have significant downsides. +* Ecosystem/language precedent is to call this operation "join". +* Given that `Array.prototype.join` already exists, we should make this operation work like it. + * `Array.prototype.join` is gross in some ways but the committee begrudgingly supports consistency. + +### Conclusion + +* Stage 2.7 + +## Composites comparator choice + +Presenter: Ashley Claymore (ACE) + +* [proposal](https://github.com/tc39/proposal-composites/) +* [slides](https://docs.google.com/presentation/d/1ByfhAVVeEfeBj2g8TkP6f55hSmq8_8tevUxuRQLfISg/) + +ACE: Great. So anyone that knows me knows that once I smell alliteration, I can’t avoid it. This is a Composite's Comparator Choice. Not asking for consensus or advancement. I just want to chat about this proposal. + +ACE: So a quick recap. I presented composites back in April for Stage 1. And while yes, April wasn’t that long ago and only Stage 1, this is really a rebranding, doing a reset on the five to ten years of discussion on records and tuples. A lot of this stuff is really not new in the slightest and it’s been something we spent easily hundreds of hours talking about when including all the discussions outside of plenary. + +ACE: The way this is kind of different from records and tuples and why I want to completely rebrand it to shake off any of the areas we had gotten into the local maximum before. Most notably this proposal is saying no new primitives. These are objects. + +ACE: And the—in some ways, you can think of records and tuples as introducing ergonomic immutability. And you also got equality. This, the way I like viewing composites, it’s almost the other way around ever so slightly. Composite is primarily thinking about equality. And a very particular form of equality. We also got the comparisons proposal, and that’s a very different type of equality. This is a very deterministic, very reliable equality. Not asserting that only at one point of time things were equal. I have presented before that when you have that type of equality, it pretty much says these things have to be immutable. So there’s a slight maybe like inversion of those two properties, the effect and the cause. + +ACE: So the kind of problem, like the use case problem we kind of keep coming back to is, if someone in a position where they want to create a set of 2D positions, if you try to have objects today, even though they are frozen and contain the same things, they are two different objects, not triple equal, not strictly equal. So `Set` says, they are not the same. You have two different positions. + +ACE: Pretty much the most common way code gets around this is they use `JSON.stringify`. Any scanning over open source code is the thing people reach for because it kind of works, and also, it’s like right there in the language. So this works. But `JSON.stringify`, you have the problem of if your keys ended up being created in a different order, they will produce different JSON strings, if you are not customizing that. It will throw if you have a BigInt. NaN becomes null, dates become strings. And while not true in all cases, there are cases where the string representation of this is going to consume more memory. Like, if you think about numbers with a lot of digits, it will take up more space to represent the digits as characters rather than a 32-bit number. + +ACE: You also end up with a Set of strings. From a TypeScript perspective, it is not very descriptive. And also, if you then want to loop over this thing and do something with them, you are going to `JSON.parse` them if you want to access the things or like `string.split`. However you formed that string. + +ACE: So that’s the idea around composites. And most people say, composites are a bad name. I know it’s not a great name. I'm always a fan of starting with a bad name to leave room for improvement. This can be called something different and the API doesn't necessarily have to be exactly like this. So you have some composite factory and when you create your composite, saying, I am creating this composite out of two things, where X is 1 and Y is 4, somehow the Set says that’s great. These things are the same. And the thing you can’t see here, things you got back are objects that have an X and Y property, then when you want to loop over at the point later, you can access those values. So it avoids the issue of having flat strings. You have descriptive things that are useful in other ways, more than just being equal. + +ACE: The two things that we discussed in April, we spent a lot of time talking about negative 0. I wasn’t expecting us to do that. The other thing that was suggested was that we approach this problem by doing interning. That was a suggestion from the V8 team, “have you thought about doing interning?” The thing I presented was that, yeah, these things work in maps and sets, but they kind of won’t work in many other places. But they won’t be interned. If you don’t know what interning is, I will explain it in a later slide. I have written that that would be a potential route to go down. It might be a potential thing. It’s important we discuss it because that decision dictates so many other decisions. It’s very hard to get anywhere else to consensus on almost anything else about the proposal, if you haven’t answered this question. So you kind of have to at least be, like, which one do we think is most likely before you can have really any success talking about anything else? + +ACE: So the kind of two different approaches you have are, one, the thing I presented before, which I am calling unique objects. So in this design world, maybe the API would always be like `new `. And you always get back a new object. So and you will be able to see at that by the fact that these two things triple equal, false, you got back two separate objects. But there will be APIs, where you can ask, yes, two different objects, but they are actually equal in a composite way? So maybe they will be like composite or equal to ask that. Or, like, maps and sets would say, yes. Those things are equal when you put them inside these collections. And also, as a result of a for, map and set, saying they are equal, they the same values are zero. `Array.includes` and includes says that, maybe array `indexOf` and array `lastIndexOf`. Particular APIs would handle composites. + +ACE: What would that look like in this made-up kind of language? I thought—yeah. I tried writing in JavaScript, but I then we would nitpick about like actually—this is not JavaScript or C++, but hand wavy intentionally. So the idea in this design space is that the composite factory always creates a new frozen object, but maybe it still computes a hash. You can imagine this one way to work. And then in all the APIs, where the equality should kick in, they will have a branch, where it detects the value is a composite and does the different type of thing. Like, if you look inside things like `Set.prototype.has` already, this is already how they do things in other types. They are switching on whether you have a BigInt or Boolean and switch into how is that thing—which comparator should I ice when I am, like, going through the entire data structure backing the set. This is an extra branch there. + +ACE: The other design space, menu option B, is interned objects. Maybe in this case, the API looks like this. You would drop the `new` keyword and have it like a factory function call. And here, you would get back—because I am creating a composite of the same kind of values, you might get back the exact same object on the second call. When I ask, are these things triple equal? It says yes. Why? These are the same object—everything in the language, and every single library says they are equal because it would be impossible for them to ever say they are not equal because they are literally the same memory address. + +ACE: Records and tuples also worked with `===` but the idea there would be overloading the triple equals operator. With Composite's all the work is done at construction and triple equal has no idea that it’s comparing composites. How would that look under the hood in a pseudocode? There would be some hidden global cache, and then that composite constructor is then kind of, like, hashing the data, looking if this composite already exists somewhere, and if it does, give that back. Otherwise, create a fresh composite and then cache it. Naturally, you don’t just want that cache to grow forever, so you need to be holding on to these things weakly and making sure they’re collected to avoid this just leaking forever. + +ACE: So if we, like, compare those two things, on the unique side, the construction call is like people can think about it it’s fairly similar to create a regular object, and a little extra overhead because it will have—potentiallying the things like sorting the keys. So a little bit more expensive than creating a regular object. There will be no new GC semantics. It’s just, like, I’m creating an object, that object behaves in WeakMaps and WeakSets and weak graphs just like any other object would, but the equality only works in certain APIs. The exact set is kind of up for debate, but it would only work—there would be no syntactic way of comparing them. You can imagine in the future this is like the signals proposal would be another API that did this, MF’s `Iterator.uniqueBy` would be another API that has the handling for composites. And in that world, that’s where if we went that route, then some of the other issues on should we be sorting the key, handle all im-- and how do we handle negative zero are all up for debate in that world, because the equality semantics aren’t ingrained into the object at creation time, so there’s a little bit more flexibility. If we go the interned route, then kind of people can think of these things as having a variable creation cost, like, sometimes these things will be cheap to create, sometimes they’ll be more expensive to create. There’s going to be some sort of new GC semantics around them. One reason records & tuples were primitives is because there’s new GC semantics and one with to avoid there’s way to avoid GC semantics is saying these aren’t objects, and strings get away with being objects on the heap, and you don’t ever expose that to the user because they’re just exposed as a primitive. + +ACE: And the great thing about interned which really excites the developers that I hang out with and meet at conferences or out on the street, is that they love the equality model here, it’s super simple for them. They’re like, equality works everywhere. They don’t have to think about which libraries may or may not support them, why the maps and sets behave differently to triple equal. It’s like generally, the people I meet really like how Simple equality is here. And if you go that route, it really dictates a bunch of design decisions such as you have to sort the keys. If you’re sorting the keys, that then complicates allowing Symbol keys. It pretty much dictates what you have to do at the prototypes. It pretty much dictates what you’re going to have to do around negative zero. And that’s why I really want to focus on this discussion, because it really forces a bunch of other decisions into other particular design spaces. + +ACE: I’m just going to have TCQ up on my phone just in case. + +DLM: Keith is on the queue. + +ACE: Great. KM? + +KM: Yes. So it seems like the main intention of this is something along the lines of—I’m just trying to reframe the problem of, like, the issue could also be equally solved in the way many other languages have solved it, is that your map and set provide your equality and hash so that the user can define them however they want. I guess I’m curious, like, how the committee in general feels about something else. I think from an engine optimization standpoint, I wouldn’t necessarily want it to be the same class as map and set, because you pessimize a lot of things. You have the TypedArray problem where all the prototype methods are horribly slow because they’re shared across all TypedArrays in engines. But outside of, that I would be open to having it be the same anyway. But having—is that something—when you feel badly about because it’s hard to write those methods correctly and they think that most users are going to get it wrong, or is it something that— + +ACE: Yeah, the other option I’ve not listed here, which we could introduce new variants on map and set in the language. It could either be, like, `new MapV2`, `new Map2026`, `new`, like, `MultiValueMap` or whatever you want to call it. Or, like, a set—I had another idea that I never presented for stage 1 of an options bag you pass to the map instead construct or the customize these things. + +ACE: Introducing a new types of maps and sets to me, I think, has a few problems. One, I think when I—I do like training for JavaScript developers. It already confuse them that, like, so many things online say JavaScript objects are like maps. You know, you can put string keys on them. And then you also have maps. And then JavaScript developers try and use the, like, array index thing on maps, and it kind of—it looks like it worked. And those maps are objects, so you can just put string keys on them, and then they get confused when they iterate over the map and those things are missing. It’s already confusing. Introducing yet another type of map I think is going to really make it an even harder language to teach. It’s also, I think, really hard to—because we’ve already got the word map in the language, i’m really struggling to think of what you’d call this other type of map. If you call it a hash map, that makes it sounds like the existing map isn’t a hash map, but it is a hash map. It does have hash map-style performance. + +ACE: The other thing is how would someone customize it. Do you pass in a custom hash function? There’s no hash utilities in the language. We could expose hashing things, but when we talked about that before, I really think it’s going to be really hard to expose, like, a hashing primitive in the language because of one of the main problems that comes up is that you have two fundamental opposing ideas. One is that the hashing function should not be completely deterministic based on the spec. Like, if the spec said “given this particular string it must hash to this particular value”, like, locking in an exact hashing function would be bad because we now can’t use newer hashing functions as they get discovered. We’d also have hash collision attack potential. On the flip side, there are people that want the language to be completely deterministic and don’t want us to introduce more things that are implementation defined. So I think that’s only just one of the problems we’d have if we wanted to start exposing a hashing utility in the language. + +ACE: I also think that—when I used to be a Java developer, it was no fun reading all the boilerplate around even keeping and passing in hashing in equality functions or getting the IDE would have if you add a new property to this object, here is the like quick fix to make sure you also update your hashing function and your equality function to make sure they’re in sync with each other. And I really don’t want to see—I love that we don’t have that in JavaScript today. And I would be upset to see a rise that type of code in the language. You’re right, it’s the other menu here I’m leaving out. In my opinion, I’d like to do one of these to things first, and only if these two things are complete writeoffs, perhaps exploring that. And happy to hear the rest of the committee on this. And I don’t want to go too long on that, because I do want to talk about these things more than that. But I think we have time. + +DLM: Next up we have GCL + +GCL: Yeah, so I’m curious what sort of concerns there are about the interned one, because I kind of feel like my instinct is to say the interned one, unless it’s not implementable for some reason, and then I feel like I’m almost being given—or we’re being given too much choice right now about which one we would want, unless there are other constraints beyond implementation concerns that would be good to know about. + +ACE: There are more slides later I’d like to go over first before we go into that. Because it starts to—it shows some of the potential down sides. + +DLM: Reply by WH. + +WH: The main concern about the interned one is that if you ever use WeakMaps, it’s impossible to unintern things, so the pool of interned objects can grow to infinity and there’s no way to remove them even if they’re not used anywhere. + +ACE: Yeah, I’ll cover that exact thing later. And then we can come back if you want to expand on that late, Waldemar, that would be great. + +MAH: I’ll be really quick because I want to discuss all those things, and regarding custom equality, I con her with everything ACE mentioned. We could do it on custom maps and sets, not really a fan of it. I am 100% opposed to any protocol for custom equality that would basically give you equality outside of just objects you create and where you specify yourself the equality you want to use for that collection. But even for that, I think it’s too complex and it’s too risky to let the user shoot themselves in the foot anyway. + +DLM: Ron. + +RBN: So a few times this has come up in the past, such as an approach using Symbols for this and—that we’ve discussed. I’ve generally been in favor of some yourself find equality. Most static languages have this capability and the closest dynamic language to JavaScript, Python also has this capabilities. One of things I found while experimenting with the shared structs developer trial in V8 some type back is that the—the lack of user defined equality makes it very difficult to create shared data structures that can be lock-free collections, for example. And as we’ve discussed with the shared structs proposal, that is something we may eventually have to propose, if we never have something like custom equality, we might eventually need to propose some type of shared or lock-free collections, because they would not really be implementable by users. There’s no way to actually define that type of equality and have it work across multiple threads. Having custom equality would be very helpful in those cases. And often times, you have collections where you want to be able to compose, say—compare URLs and not have to `toString` them, which is roughly an example similar to what was in one of the slides. + +RBN: The upside of custom equality is that you don’t have the memory overhead of having to maintain the composite, and as per WH’s concerns, the long-lived lifetime of these potentially interned values. And if you have something that is a unique value, then you’re constantly recreating them to do comparisons and it’s not very efficient compared to an algorithm that doesn’t need to maintain state. And while, yes, you can potentially shoot yourself in the foot by having custom equality, that is pretty much the case in every other language that has that capability, and it’s still fairly heavily used and used well, so I’m not sure that preventing users from being able to shoot themselves in the foot isn’t then removing the ability for them to actually get some of the work that they need done by removing the power from those users or not giving them the capabilities that they need. + +ACE: So thanks, RBN. Yeah, and I know we talked about this before. I’d really—I really appreciate this feedback, and I see everyone on the queue. I really don’t want to talk about custom user equality today. Let’s assume we’re not requesting that route, and I can definitely come back and we can do a different presentation about that choice. I would like us to, like, put ourselves in a mindset where—because we’re not trying to reach consensus at all. Let’s do a thought experiment where we’re not doing custom user equality. If we’re not doing custom user equality, how do we want to handle it? That’s the topic I would really like to talk about today, and I don’t think we have time to expand beyond that. The reason—I completely agree that there is a space for custom user equality. And I think that could be in the language. The impression I get is, yes, most languages have that. But also most languages have it because they’re just copying the pattern that was there in the ‘90s and earlier, and I don’t think it’s because it’s the best thing. I think it’s just languages copying older languages. What I see in newer languages, and this is jumping to Shane’s topic of what do other OL languages, it’s like other languages I create a record or struct and I just define the fields on it, and I for free, get hashing and equality out of the box. Like, I can override those methods, but most people are not overriding them because their use case is perfectly adequately met by just the built-in ones you get for free. So, you know, perhaps if we did have a protocol thing, you’d have some annoyingly—like, we already have classes in the language and you don’t get hash and equality for free. Like, we already have the structs proposal, and maybe there would be a type of syntax for defining structs or class like things where you get those protocols. + +ACE: The problem with that is, like, the problem we have is, JavaScript is really hard to optimize. Like, it’s, like, those other languages have compilers and have much, much more static sound type systems, even if they’re still, like, maybe JIT compiled, they’re JIT compiling a much simpler type system. I think the other thing—I think developers don’t want to be writing these things in lots of cases. I do appreciate there are cases where you do want to customize these things, but I think they are more power user niche cases that are better served by a different proposal. And also I think most developers want their things to be fast. And as soon as you have a custom protocol, it’s going to be so, so hard to optimize that because you now have to be, like, well, this could be reentering. And maybe that’s the route we’re going to get. But let’s pretend we’re not going that route, just because I would really be interested on this particular decision, even if we don’t end up going with either of them. + +DLM: Do you want to go on the with the queue, Ashley? + +ACE: I’ll get through my slides. So as I said, we’ve been talking about this type of stuff for, like, maybe, like, somewhere between five to ten years. And one of the things that I think we haven’t had in previous discussion is actual, like, numbers, I think. So I don’t think performance is, like, the first—the most important be all and end all, like, the fastest solution wins. But I think in the past, we’ve kind of gone round and we’ve speculated on performance. I think an ingredient that I thought might be an interesting ingredient to add into the mix is some actual numbers. So what I did was implemented these two different approaches in V8—as best I could, I’m not an engine implementer. (Leszek Swirski?) on the V8 team looked at my branches and pointed out where I was being a very bad developer and helped me improve them, which was really appreciated, and I don’t think they’re great implementations and they’re somewhat representative now because I received some help. As I said, this was just in V8 because that’s the one I was most familiar with. Perhaps it would be interesting to do a similar thing in other engines to compare. + +ACE: And I was spending time trying to think of how could I benchmark in and I realize I was spending more time thinking about that than running the beverage mark. The benchmark I was going to do with these two implementations is let’s create keys where you have three numbers, so like a 3D vector, and I’m just going to do, like, fill a cube with, like, all the positions in that cube. + +ACE: So I’ll go through what everything on this graph is trying to show. So there’s, like, three sets of bar charts. That’s me creating ever-growing cubes that, like, double in size. So the first cube is, like, 70 cubed. And then the next one is 88 cubed and then 111 cubed, so each cube is roughly twice the volume as the previous cube. Like, within some error, very small error. And then within each kind of bar chart, there are six, like, different implementation strategies of how has that kind of vector been turned into a key. So the first one is pass the object to `JSON.stringify`. The next one along—for people that can see color, it’s like the orange one—that is, like, a custom JavaScript implementation of interning, where I’ve got, in case, it’s like a map containing maps containing maps containing weak refs. And then the next one is the V8 native implementation where I’m not interning. So you’re always getting back a fresh object. The one next to that is, again, you’re always getting a fresh object, but it’s like a userland JavaScript polyfill. And the next one along, and now if people can see color, we’re on the grey one, third in from the right. And that’s `JSON.stringify`, and you pass it—pass in a custom replacer. It’s just like an identity replacer, you get given the key value, it gives back the value and it’s just like a singleton function, so there’s no function allocation there. And that’s effectively like turning off all of the fast paths inside `JSON.stringify`, because there’s this custom function in there. And the next one along, and you got the two darker and lighter blues, similar to before, one is native and then the next one is the JavaScript polyfill, and that’s the interning approach where there’s this hidden cache and the second time you create things, it returns the existing object. So that’s all the different implementation strategies, and then the thing that’s running here is I’m just creating all the keys, and then I’m, like, throwing them away. + +ACE: What can we see here? What we can see here is in V8, `JSON.stringify` is really, really fast. And annoyingly, while as implementing this, they kept landing things and making it faster and that line went down as I spent time, and I couldn’t work on this full-time and I would come back to it after a few weeks and `JSON.stringify` had gotten faster, which isn’t a big surprise, because one, it’s just concatenating string ropes under the hood. It’s not having to sort the keys. The thing I’m passing in here is just a small object with, like, single character, like, the property names are just single characters. And then there’s just numbers. And V8 is doing, like, SIMD optimizations to turn it into a string as fast as it can. + +ACE: The other thing that I guess isn’t a big surprise is the polyfills are slower than the native ones. The interning one, because the interning one has to do all its work at construction time, kind of has the biggest kind of overhead of trying to do that just in userland. This is not really the things are able to do that super fast. The other thing we can see is that, yeah, there’s a big cost when using V8 of doing just `JSON.stringify` versus `JSON.stringify` with a custom function. I can see there’s a clarifying question from SFC. + +SFC: Yeah, can you clarify again what the difference is between intern bespoke JS and intern composite JS? + +ACE: Intern bespoke JS is the minimal JavaScript for this exact case, where all it does is it’s interning objects that have an `x`, `y`, `z`, so it’s—whereas the composite one is the more generic I’ve been given some object, and I don’t know what the keys are. So I’m sorting the keys and I’m handling it more generically. Whereas bespoke is hand-crafted for this exact case and nothing else. + +SFC: Cool. + +ACE: So the next one, if we jump along, and if people have these slides checked out locally, you can play jumping back and forth between the two slides, this time I’m creating all the keys, but then I’m also inserting them into a set. So now what we can see, maybe the biggest thing to get out of the way is that while previously the, like, polyfill for the non-interning composite was faster than the interning one, as soon as you then actually put one of those things into a set, like, that advantage completely goes away because it’s now having to do all that work that it put off, and it’s harder for it to do that work when your monkey-patching `Set.prototype.add` compared to doing it just within your own constructor. + +ACE: The other thing we can see here is that, like, the two JSON lines both jump up. That’s because in V8, it also interns these strings lazily. And when you call `JSON.stringify`, it creates a rope. And when you put the JSON string in the set, it then interns that string, so it had a similar thing of while it could construct the string very quickly, when used that string as a key, it then triggered additional work. + +ACE: The other thing we can see here is that the three kind of other ones, like, the custom, I can only handle this very particular case of X, Y, Z, versus the two different composite approaches, they’re actually really, really close to each other, and I wasn’t expecting. I was actually expecting interning composites to be slower in this case. My hypothesis was, the cost of interning and the complexities of interning would add so much overhead when you’re constructing these things, that even when you’re inserting it into a set, it’s easier for the set, because you’re effectively doing just pointer equality style set insertion. I thought the overhead of interning would still put it on the back fill. But what we actually see is for the smallest cube, the interning composite works out faster than the non-interning one. `JSON.stringify`, though, still beat the two of them. We then go up to the the medium sized cube, and now actually the composites ended up working out slightly faster than `JSON.stringify`. And then the largest cube, you actually see a slight switch where now the interning composite is now slightly slower than the non-interning one, and I haven’t quite dug into that. I think some of it’s just noise. These are all very close. And I think also it’s, like, by the time I’ve created 3 million intern composites, I think we’re now seeing a bit more time on the GC handling those. But, yeah, the thing that surprised me most was how similar the performance of the two was. I was expecting the interning to actually work out slower here. + +ACE: So I wanted to drill a bit more into the things. You’ll notice here, the eagle eyed amongst you, there’s only three lines. Why are there only three lines? If you plot all of these things here, a lot of them just skyrocket off, and then the three that I wanted to compare look almost identical. And so to actually see any difference between them, you really don’t want to be plotting the other attempts. So the three here, so the kind of gray squares, are `JSON.stringify`. The green stars are the non-interning composite. And then the blue circles are the interning one, and what this shows is that—so—and then the X axis is me repeatedly creating keys and inserting them into a set. And I’m not clearing the set, so the first iteration is actually filling that set, and then 2, 3, 4, 5, et ceteras are effectively just doing a set lookup. So all the cost of, like, allocating and creating the data structure of the set is all paid off in the first iteration, and then the remaining iterations is kind of just showing the cost of creating the keys and performing the lookup. + +ACE: So the very first one, we can see here, like, the interning one is slightly slower because it’s paying that extra cost of having to do that interning logic. But then what we see is once we have got done that interning, the cost of creating a cache hit when you create the intern composite is really good. Like, when you get a cache hit, it does almost, like, zero allocation to do the lookup, and then it just returns the existing composite, and then again the set lookup is much cheaper because it’s having to compare much less. So the slope there is much shallower, and by the time you do the second iteration, you’re already kind of getting payback for the extra time you spent interning, whereas for the non-interning composite, while it’s cheaper to begin with, the extra work you’re having to do every single time means that the slope is steeper and you—it starts to become slower and then obviously the more you do, the more they’re different. + +ACE: And then last thing I did here was just to kind of try and remove the cost of creating the keys. So here I, like, create all the keys, put them into an array and then I just keep looping over that array putting them into the set. So here we’re kind of purely looking at the set lookup times. And you’ll notice that, like, in this gray square for JSON and the intern in parallel because they’re both using an interning approach, and unsurprise league the set lookup, it has very, very similar logic. Whereas the non-interning one has, like, the custom set equality. That one has, like, you know, that steeper line. So this kind of tracks with, like, the hypothesis. But, like, what you probably predict here, like, interning is cheaper—an interned object is cheaper to do a set lookup, versus one for custom equality, and which is why V8 has chosen to intern strings when you put them into a set, rather than do a custom act of equality comparing bytes every time. + +ACE: So as WH alluded to earlier, what’s the downside of interning in the downside of interning is the garbage collection semantics get complicated. So an example that shows this is that it is here. I will say, like, these things don’t leak until you start doing these types of things with them. Like, my implementation in V8 doesn’t leak, even though it’s interning them, it doesn’t leak them. But once you start trying to use these things in a way that does interact with the GC, you start to see kind of interesting kind of design decisions arise. + +ACE: So here we have a—I created a composite with, like, X is 1 and Y is 4. And then I have a WeakSet. I add that composite to the WeakSet so we have like a design choice of, well, what happened at that point in time? I can then ask, like, does that WeakSet have that composite that I just put into it? That’s another design choice inflection point, and I set C to null, and at that point in time, let’s assume that’s the entire program. There’s nothing else in some other module. Right now nothing has a composite like that, that they have a strong reference to. + +ACE: And then, like, await. Let’s assume GC is deterministic and this is, like, enough time to trigger a GC. I then now create that exact same composite again. I say I want X is 1 and Y is 4, and then I ask that WeakSet, hey, do you have this key? And then, again, we’re asking a question, so there’s a design choice of, like, what should the spec say? So this is, like, the design space where you go down. So, like, we created a composite. And we put it in a WeakSet. We really have, like, two choices here. Like, so add returns the WeakSet, like, it returns this. So 2 two choice there assuming that it doesn’t, like, halt is it either throws, like, the completion is either going to be like a throw completion or like a normal completion of, like, yes, here is that WeakSet. + +ACE: The next design choice is, like, okay, we’re asking a predicate. We have two choices there. Like, assuming it didn’t throw, can it return true or false? And then we sleep, and then we ask has again, and, you know, the choices we have there in, like, the spec are either it says it returns false, it maybe returns true or maybe returns false, or it should return true. A design choice I’ve not shown here is the assumption that the first line is valid, like, I created a composite that only contained strings and numbers. Another design choice is that whenever you create a composite, you have to include an object as part of the composite. And I think that’s bad for another reason, and I’ll only get into that if someone asks me to because I want to be, like—I don’t want to spend too much time. + +ACE: So this looks like oh, we have like a big design space. I think in reality, we have two choices. And that’s because if I put something in a WeakSet, and it didn’t throw, if I immediately on the very next line ask, hey, WeakSet, do you have that thing I just gave you and it returned false, that’s so weird. That is just like really bad, and people will laugh at JavaScript if it works this way. This is how it works in Java, but you have to opt in. You have to pass a flag to the WeakSet and say I’m happy for when you get give an bad value, it’s just a no op. You have to, like, consciously opt in to the WeakSet in Java. It doing that implicitly would just, I think, be so weird, and I can’t see any advantage to this value immediately falling out the WeakSet as soon as you try and put it into it. Perhaps I’m alone on, that but I think everyone one like, yeah, that’s weird. Let’s not do that. + +ACE: The other choice is, if the spec said after you sleep, then the WeakSet must say false, that is just not how GC is defined in language. We do not say every time you yield, that guarantees the garbage collector will fully run. Like, as far as the spec says, we only say which things can’t happen. An implementation of JavaScript that never collected anything would be a 100% valid implementation of the spec. So I don’t think we can start to say, after you yield, you’re guaranteed the garbage collector will definitely find all the composites put in every WeakSet and make sure they’re removed. The other, like, should it return true or should it return false, the roll of the dice, the language just doesn’t do this. We don’t have this non-determinism around the garbage collection semantics. We’re very, very clear about what should be observable, and I can’t imagine after doing all that work, I just can’t imagine we’d want to backtrack that. + +ACE: Really, it sounds like with interned objects, with the things with type of object, you really haves two choices. Either the WeakSet throws. That then—the thing that in the past people have said, that’s really bad is, like, right now, in the language, every single object, no matter how silly it is to put in a WeakSet, maybe it’s `globalThis`, we let it happen. So this would change this. Potentially this might happen anyway. It’s been discussed around shared structs, like, should shared structs be allowed in a WeakSet? They have type of objects, so maybe this comes up anyway. But that’s one choice, and I think some people really hate that. That is my gut reaction to beginning, was that seems best. We should just throw. That was my initial gut reaction to this kind of thought experiment. + +ACE: The other option is that it has to be kind of, like, a memory leak—and what I mean there is that the WeakSet actually will have a strong reference to the composite. It will see that you’re giving it a composite. It will see that the composite contains no objects. So it has no way of kind of—there’s nothing about that composite that gives it a finite lifetime. Everything in the composite has an infinite lifetime, therefore, the composite has an infinite lifetime. The WeakSet says, well, then the only thing I can do now at this point, because I didn’t throw, was that I have to hold on to it strongly. Because someone can always create that composite in the future and ask me if I have it. That’s bad, because as long as—if the WeakSet itself gets collected, then it’s all fine, or if you `WeakSet.remove` the thing, that’s fine. But if you’re not doing those things then, yeah, the WeakSet will just grow. That’s not great, because memory leaks tend to not be everyone’s favorite friend. In some ways, that’s maybe not as bad as it sounds, because we can do things like, for particular code, maybe we can do static analysis that would be able to see that’s happening. Potentially devtools could log a warning saying, hey, just to let you know, you’ve put like an infinite lifetime composite into a WeakSet. You’re probably leaking. Here is where that happened. Maybe don’t do that. If you create a heap snapshot, the heap snapshot statistics could say, here are the WeakSets that contain lots of these types of dangerous composites. You probably want to look into that. So while it sounds bad, I don’t think it’s—it’s not necessarily, like, as horrific as it maybe sounds. + +ACE: I’ll also say that, again, when I talk to a lot of JavaScript developers that aren’t just, like, obsessed with, like, just like an after JavaScript developer, most of them say, like, why would anyone need a WeakSet? I’ve never used a WeakSet. And these aren’t junior developers. The that’s are JavaScript developers that are creating stuff with JavaScript for, like, longer than I’ve been alive. And they’re like, I’ve never come across a use case where I’ve used a WeakSet. That’s not a big surprise. They only come up in very particular cases, and most—it’s also rare when you’re using a WeakSet, you’re using it where you don’t know what the values are you you’re putting into it. Yes, that does happen, and a lot of cases where you’re using it it’s used internally in the library where they know what they’re putting in the WeakSet. So while it sounds bad, I think people will be a little open minded that it’s maybe not as bad. Because I’ve been somewhat convinced that maybe throwing is a bit surprising here. Maybe the leaking with all the support and maybe, like, tooling to help warn people. Maybe if we had to choose, I’m now somewhat leaning towards that one. But, yeah, I’m very much close to 50/50 between these two choices. + +ACE: And I’d also say whichever up with you choose, you can always implement the other one. This is really like, what is the default? If the default is to throw and you wanted the other thing, you would try catch and put the value into a regular map. If the default is that it leaks, well, then you say if—like, before you put the thing in the WeakSet, you go if this thing is a composite, I will throw and say, like, this isn’t a value I’m prepared to handle. So this really is like, what is the default behavior? And this isn’t about WeakSets. It’s the same for WeakMap and WeakRef and FinalizationRegistry. And thanks for letting me get through all those slides, and back to the queue. + +DLM: Okay, just to note, I moved off the topics that are related to your most recent set of slide, and if we have time, we can go back to the earlier topics. And first up we have GCL. + +GCL: Hi, yeah, regarding WeakMap set ref, et cetera, we actually visited this space back when working on the Symbols as WeakMap keys proposal. And we came to a prior consensus that I think is quite reasonable where we defined what allowed values would be based on what we called forgeability of the values. And that’s basically saying that if you can have something that has a value in the JavaScript language that has some identity, and then lose access to that value, and then from scratch, create another value that has the same identity, you cannot use it as an entry in these types. So, like, I don’t know why we would not just use that prior consensus here. + +ACE: That was my gut feeling as well, if these things are forgeable just like numbers and strings and registered Symbols are, if you’re putting them into WeakSet, you’re probably doing something wrong, so we would throw. I’m going to say, the reason I’m convinced against that is at least with the other—like, there was already precedent with Symbol—when we made that decision, all Symbols were rejected. So there was already precedent for some rejection. Yeah, I guess I’ve convinced myself that the committee are going to block a proposal that says some things with type of object that are not null throw when you put them in a WeakSet. I’ve kind of convinced myself that’s an unpassable design within the committee. Maybe I’m wrong and I’m being too pessimistic. Academically, I think that’s the correct answer. + +DLM: Next Matthew. + +MAH: Yeah, so the—I don’t have an opinion right now. I’m not sure which way I want it to go. I just want to highlight as you mentioned, there are potentially other proposals or other objects that may exist in the future that would also have an interaction with GC. You mentioned shared structs, there’s also basically the wasm shared objects, which is similar to the JavaScript shared structs. So it’s very likely that there would be other objects that cannot be garbage collected. Those, however, have a slight difference, is that right now, it’s a restriction that they wouldn’t be able to be WeakMap keys. It is possible that in the future, they could become WeakMap keys. In which case, I still don’t know which version I’m in favor of. Because if we allow them, that means we’re leaking now, but we’re no longer leaking in the future. I don’t know. + +DLM: Okay, we have about 14 minutes left. Jake? + +JAD: Yeah, I guess I’m just agreeing with what GCL was saying. People use WeakMap and WeakSet for the GC stuff, so anything that’s going to great that semantic just seems bad. When developers ask why can’t I use strippings and numbers in a WeakMap or set, you just say, well, because of the formability thing, so I think they would understand this perfectly fine. I your point that, yeah, WeakSet is rare, but WeakMap isn’t, is it has the same problem, right? As when used as keys. So, yeah, I think throwing makes sense. + +DLM: Next up, Waldemar. + +WH: So there’s a couple things going on here. One is we should not assume developers write all the code which they are running. If they’re using a WeakMap, it’s probably deep inside some library that they’re using, so if that leaks, it will be hard to figure out what’s going on. The other thing, which we haven’t talked about yet, is the communications channel created by interning if you intern values with negative zero. Let’s say interning interns the value it sees, and the next time you intern something, if it’s === to the original value, it gives you the interned value. This lets unrelated things communicate by playing with values containing a whole bunch of ±0. + +ACE: Yeah, it’s a very common—so there’s lots of libraries already on NPM that kind of the do this interning thing. A thing I can reliably raise on all of these libraries and I have done and I fix them, and they always make the mistake, if they don’t consider negative zero and it’s first right wins. If you intern an object, and you put an negative zero, the next time someone asks for it and they pass positive zero, they get back negative zero because they currently interned one contained negative and vice versa. The records & tuples polyfill also did that in the first iteration and we had to fix it. It’s a common mistake to make because most people don’t know negative zero exists. If you ask people on the streets, they don’t know what you’re talking about. What I think we would do in that case, and it really forcing one of two decisions, either we say these things are not equal and so the thing you get back, is it positives or negatives zero would not intern to the same value. I don’t like that. I think we would always normalize map and set. So regardless of what you were interning the value you get back would always be positive zero. One thing we didn’t make clear in, interning approach, it’s not interning in like the value you cashed in is like any, it’s still a fresh object because it needs to be immutable and if you passed in a proxy, we can’t cache that proxy. We can’t to—is it kind of doesn’t matter which value was passed in to begin with. We’re always creating a new object on that fresh interning one, so we can do a normalization step. + +WH: Yeah, there’s another potential source of trouble with NaNs if you stick a NaN into an ArrayBuffer and extract which NaN it is. + +ACE: Yeah, so we possibly would normalize NaNs here as well. That’s another maybe kettle of fish to get into. I think normalization would be the strategy here for interning. + +WH: Yes, that works. + +DLM: Jordan? + +JHD: Yeah, so there’s a ton ways in the language to create memory leaks that we don’t throw for. And I’m not going to leave the opportunity to check a TC39 bingo box, and I think it’s too nannyish to be that pair Floyd about memory leaks. Not only is this unlikely to happen that there’s that many compos activities that have non-finite lifetimes that are then put in a weak place, I think that’s, like, an obscure edge case right there. But everyone who is doing stuff with weak things, whether it’s the application developer or a library developer, they—if they’re using them, and they care about leaks, and they’re not just cargo culting some constructor in, then thoughive they know about this stuff. We don’t need to do it for them. They can check for it. And if they don’t know about this stuff, they probably aren’t—are already misusing their weak collections anyway. I just am not really concerned about, like, this—the potential memory leak of this obscure edge case here, and I think it would be much weirder to make what is a weak key or, like, what—the criteria for being weakable, like, I think it would be much weirder to make that more complex. + +ACE: Yeah, I think—I do agree, if I do think we have gotten to a niche area with the WeakSets and even with WeakMaps. I agree with JAD WeakMaps are more common than WeakMaps. And people are definitely using WeakMaps more. And I will say, yes, we don’t throw in all ways you can memory leak. That’s because we attendant detect all ways you can memory leak. I think one thing about this is it’s trivial to detect that this is kind of fundamentally wrong. So it’s easy for us to throw. And it aligns with how we already throw for similar values. + +JHD: But Symbols aren’t similar values, so we don’t already throw for any object, except for I think window, because it’s exotic. But, yeah, as to—I see a queue item and I’m just saying, memory leak is not a breakage. Neither is a code regression. The performance works fine. + +ACE: Until you hit OOM, which then it’s still there. + +JHD: Sure. + +DLM: Waldemar? + +WH: I strongly disagree with the preceding statements. If somebody has written a library which uses a WeakMap and they don’t update it, it will be broken. Not only will the WeakMap inside the library continue to grow, it will also create a leak inside the interner. Which is a very different scenario from just having a fixed number of a few long-lived global objects. The interner itself will leak these things. + +ACE: Just to confirm, WH, you’re not saying that throwing would break libraries. Your preference is to throw? + +WH: Yes. + +ACE: Right. Thank you. + +DLM: MAH? + +MAH: Yeah, just I want to reiterate that the problematic here is application creating these composites passing them in libraries that internally use these weak collections and the application is not really in control of whether the library they use is able to handle that situation. So then the application would be faced with a choice of not using composites, or to either leak or basically the library not functions anymore. + +DLM: Okay, Keith? + +KM: Yeah, I guess on the same vein as that, like, the—any time we add any of these new features anywhere in language, every library that uses WeakSets needs to be updated instantaneously, otherwise it’s broken. It doesn’t fail safe. It fails badly, and I guess to my second point of memory leaks aren’t breakages, there are certainly platforms that exist that many people have, probably in this room, where if the website uses too much memory, it will just kill your web page. And it’s not controlled by the browser, the operating system does this. And there’s no fallback, there’s no escape. You just die. It’s not like it starts paging to disk. It just kills you. So I guess I would argue that leaking memory is breakage in some contexts. + +ACE: And, then, just so I have it on the record, you’re also for throwing for this particular case? I have similar things where I was talking to Google last night about caching things, and caching things to avoid computations later sounds good, but you can run out of memory. It’s much harder to run out of CPU. Yeah. + +DLM: Point of order, we have actually now about four minutes left. + +ACE: So I’m really interested in all of these other things. I am wondering—yeah, let’s just keep going with the queue. + +DLM: SHS? + +SHS: Yeah, so I mean, people are talking about, you know, these libraries that are using weak collections and that they’re going to leak all of a sudden. The alternative if we throw, they’re just going to fail fast and also be broken and if you’re not controlling your library, you still can’t use this library. And I’m trying to get of sense of are we saying failing fast is at least a better alternative or something else entirely? + +ACE: Yeah, because this is why I’ve been asking for clarification, and some people may say throwing breaks a library, because now if I pass a composite, these forgeable composites, now that library throws where it didn’t throw before. It’s a backwards compatible change because composites don’t exist yet. No existing code would break. You would have to start using composites to do this. Personally I think this is, yes, if a library wants to start supporting these forgeable composites and it takes them into a WeakMap or WeakSet, then they need to be updated. I think it’s very natural in the ecosystem, if you want to a new feature, you have to wait for a library to update, you have to fork it and move to that new version. Like, it’s not great, but it does seem like it’s not that bad that the ecosystem will have to release new versions if they want to support new features. + +SHS: Yeah, because I mean, everything using it would be leaking right now—it’s not actually fixing any breakages. + +DLM: Okay, next up is Ron. + +RBN: Whether the concern is that it breaks because it leaks memory and the tab get shut down or it throws an exception, throwing the exception will inform the developer or the consumer that the—where the issue is specifically, whereas leaking will just result in a crash that it’s much harder to track down. So throwing and failing fast is much more reliable and much easier to fix. + +DLM: Thanks, Ron. Matthew? + +MAG: So I just wanted to note we started trying to decide a little bit about how did we feel about interning versus the version that doesn’t intern. Coming back to that point a little bit, people seem excited about interning. I’m excited about interning. But there is architectural limitations for SpiderMonkey that might pose problems making this, like, potentially unimplementable and at the very least very hard. So I just am doing my obligatory wet blanketing here. + +ACE: I think Iain raised an issue from the SpiderMonkey team raising in, and I do apologize I implemented this in V8. I was much more familiar with V8’s garbage collector and semantics than spider. And I wasn’t aware of some of the different strategies that SpiderMonkey had, and I think I understand the issue that SpiderMonkey has than I did before. I definitely don’t understand it as well as the SpiderMonkey team. And I’m wondering an actual next step here, I think, could be I go away and I try and do a SpiderMonkey implementation, because I don’t want to put that burden on to you folk. To kind of really, really feel that pain and just kind of understand that. Yeah, thanks for raising. It was news to me last week. Thank you. + +DLM: Okay, we have under one minute folks. Actually, we just ran out of time. And I’m not holding back anyone from lunch. I don’t know, I’ll leave it up to the other chairs whether we want to try to do a quick continuation later on. + +CDA: If Ashley wants to do a continuation, we can. + +ACE: Yeah, and the other topic on the queue here is the kind of wider design decision of, like, neither of these things and a different thing. So whatever we do, I think I’ll be coming back to plenary with more slides. And I don’t want to take time away from stuff already on the agenda for this meeting. + +CDA: I think we will have some time available towards the end. + +ACE: If we do have time, I would appreciate it. + +### Speaker's Summary of Key Points + +* A quick recap of the problem space around complex Map/Set keys was presented. +* A core design choice that dictates almost all other aspects of the proposal is if Composites are interned or not. +* Two experimental implementations of Composites were made, one that interned, one that didn't. +* Benchmark performance results comparing the different approaches were presented. While interning did add overhead to the initial call to create the key, as long as the key was needed twice the overhead was paid back due to the faster lookup and subsequent pre-interned keys. + +### Conclusion + +(discussion continues on [day three](./november-20.md)) + +## Concurrency Control stage 1 update + +Presenter: Michael Ficarra (MF) + +* [proposal](https://github.com/tc39/proposal-concurrency-control) +* [slides](https://docs.google.com/presentation/d/1WoEqtVKEJgIhyTbOO2aWbNKLCFNPXHMb0ZW3gMFpyvU) + +MF: So this is an update on the concurrency control proposal. Remember, this is a Stage 1 proposal, so we’ve agreed in the general, you know—the general problem space that we think it’s worth solving, but we don’t have any agreement on the solution space yet. And I have refined it a little bit more since we last talked about it, and I want to present some of that and then get some feedback. + +MF: So remember the problem space that we're addressing is that there there’s no convenient built-in way to orchestrate or limit concurrent access to a resource. This can be any resource. These can be things you typically think of as resources like file handles or database connections or something like that. But I want to mostly focus my efforts here on functions and async iterators. Although they are generally useful. But those are things we have built into the language now. + +MF: I want to remind you of the context around this proposal. We originally had Iterator helpers, which is now at Stage 4. This gave us this very small set of methods on Iterator prototype for either composing iterators or consuming iterators. And KG has a proposal that’s at Stage 2 called Async Iterator helpers, which is the same thing but for AsyncIterator and that proposal is also going through a lot of work to make sure the async iterators it does produce can be consumed concurrently, but there are no facilities for controlling that. So in this proposal I want to add those facilities. And, you know, as a prerequisite to that, a way to describe concurrency strategies. + +MF: Also, I want to remind you that, like as a follow-up to this, we hope to get to a point where we can have unordered AsyncIterator helpers, when used with the things provided within this proposal to describe some amount of concurrency, could be a lot more efficiently consumed than async iterator helpers that are always consumed sequentially. And then we expect that this will be a majority of the usage of async iterators, they would be consumed in this unordered way and be much more efficient because of this sequence of proposals here. And just a reminder of what exactly we’re talking about for those. The iterator helpers added map and filter and stuff like that to `Iterator.prototype`. Async iterator helpers is doing the same for `AsyncIterator.prototype`, and `AsyncIterator.fromAsync` and the buffered method on `AsyncIterator.prototype`. And we’re looking for something like a way to opt into an unordered AsyncIterator prototype that then has all of the same methods, and this would be like something like an unordered method on AsyncIterators, so once you have an AsyncIterator, you can call a `.unordered()` method to opt you in to getting unordered helpers. + +MF: What are we looking for this proposal to provide to get us to that point? I want to go over the context of this proposal as I'm imagining them at the moment. It may seem like a lot, and I’ll have a summary at the end and I don't think it’s that much. So first thing we need do is for, you know, integration with async iterator prototype, we need to add a parameter to each of the six currently (as of this proposal) present consumers of async iterators that are there for AsyncIterator prototype. So here I’ve just added an optional concurrency parameter at the end of each of these parameter lists. That parameter is—you can for now think of as an integer and that just tells you, you know, how many concurrent operations can be happening, can be performed by that helper. This can also take a more abstract description of concurrency that we’re going to call Governors that I’ll get to in a second. As an example on the right you can see what you might do prior to this proposal where you for-await over some AsyncIterator, and then you have to await some predicate, and this is basically implementing `AsyncIterator.prototype.some` manually. But you can see that it won’t do anything concurrently. It will await this element and then it will wait the promised return by this predicate and await the next element and it all just happens in sequence. So that would be equivalent to what is going to be introduced with async iterator helpers. That proposal doesn’t change that at all other than making it convenient to write. You would say `asyncIter.some(predicate)` on line 10 here. + +MF: So with this proposal, you can do the same operation with a concurrency of 5 by just simply passing 5. It should be that easy. If we want to do some kind of more complex strategy we can pass a governor, which I said, which we’ll get to. So additionally, if we are giving these easy ways for people to consume AsyncIterators concurrently, we probably want to give them an easy way to opt out from the production side, from being consumed more concurrently than they would want to be. So this propose also adds a single additional prototype method for AsyncIterator called `.limit(N)`, which limits how many pulls can happen to the underlying iterator. So if you look at the example, we can create an AsyncIterator here that logs every time it’s pulled. And then we created a new AsyncIterator that is limited to two. And if we next it a bunch of times, only those first two get logged immediately, and then the next ones will not get logged until after we’ve awaited these first ones. + +MF: Third of four slides here I have on this. I told you that we wanted to be able to describe more complex forms of concurrency. This is how we’re planning on doing it. We have the governor interface, and we want to give the developer the ability to define their own governors. This is not a feature that is going to be entirely built in and controlled by us. Because there’s lots of different kinds of concurrency strategies that people are going to want to describe that we can’t predict ahead of time. This is definitely a place that needs a protocol because of that necessity of user extensibility. So I’ve defined the governor interface, which has a sync and async version of acquiring a token, which gives you the right to use the protected resource, and then that token has a way to release it. Which gives back that allocation so that others can do an acquisition. This is done through either the, you know, ergonomic `release()` and `asyncRelease()` methods or the identical `Symbol.dispose` and `Symbol.asyncDispose` from explicit resource management. There’s also a governor constructor itself to make it convenient to, like, subclass, as you see in the example on the right. And a couple of prototype methods that you get with it that make it easy to actually use those governors in the way we expect people to use them. If you look at the example, we are implementing some custom governor where we override the `acquire` and `tryAcquire` methods, returning some token that can be released. I’ve omitted the actual details of the kind of concurrency strategy that’s being described because it’s not important for this. And then you can see a usage of it down here in lines 12 through 16 where we create a governor that is governing some resource, and in some async function, we await the acquisition of a token. So it will wait until—until the resource is available, and when it is, it can use it, and at the end of this block, you know, explicit resource management's `using` will clean up for us. Alternatively, we could have used one of these prototype methods from `Governor.prototype`. If we had done `gov.wrap` on a function F that didn’t have line 14, it would behave just like this, like it did at line 14. + +MF: And finally we have one built-in actual concrete governor called counting governor. This is a semaphore, if you’re familiar. It used to be called semaphore actually in an earlier version of this proposal and people had some issues with that. So this is a built-in governor. It describes the most common kind of concurrency limitation, is just we have some fixed number of some resource that I don’t want anybody using more of than that number at the same time. This is also useful for sharing some resource without coordinating ahead of time. So if I want two different unrelated operations to use the same pool of allocations, like, that’s—that’s facilitated by this rather than just an integer like we saw before. So as an example, I can create this governor. I can use it in these two different `forEach` calls on AsyncIterator prototype, and I can also use it in async function F, and these will share that same pool of two resources. + +MF: So that was, like, an in-depth view of everything that is currently in my preferred solution for this proposal. Here is the summary of it. I’ll just go over it very quickly now. We have the additional parameter on those six AsyncIterator prototype methods. If it's passed an integer, it’s the same something as passing in a counting governor. And you can also pass in arbitrary governors. And we also have the addition of a new `AsyncIterator.prototype` method for limiting concurrency because it’s appropriate to do that if we’re giving a convenient way to consume these concurrently. We are establishing two new interfaces for governor and governor token. And governor has a prototype with two methods on it, `with()` and `wrap()`. And then we are introducing the concrete governor counting governor, which is the by far most common kind of concurrency strategy that we believe people will want to use. + +MF: So it came up in the issue tracker and during a previous presentation, I believe DLM, and possibly others had some doubts about the motivation for this proposal and I wanted to quash that with these next couple of slides. We have here a list of some incredibly popular NPM libraries. Not all of them, but a lot of them, most of them on this slide, are very, very popular NPM libraries, and next to it is a single line of how you would replace that entire library using the things provided in this proposal. I don’t know if it’s too valuable to actually spend our time going through each one of those, but you can trust me that for the most part, all of these libraries are now unnecessary with this proposal, with the exception of the `async` library at the end, which is another incredibly popular library, one of the most poplar libraries on NPM, which includes a whole lot more, and possibly a space we would like to explore for pulling in with follow-on proposals. And this throttle one would like a time-based governor. We don’t like the idea of introducing the concept of time within this committee, so that’s left out of this proposal. + +MF: And here is just like some download numbers just to show you these are very, very popular NPM libraries. Lots and lots of projects use them. So I think it shows that there's definitely a very strong need for these kinds of things. + +MF: We spent a lot of time going down kind of a rabbit hole of trying to solve the whole space of concurrent task queues as well in this proposal. It is surely the case that there’s a big need for concurrent task queues just as there’s a big need for these other concurrency helpers we’re providing here. But as you can see from these libraries, all of which have lots of uses, they are all very different, both in their complexity and capability. They use very different subsets of the total capabilities. + +MF: So, you know, it is very important for us to provide something like governor protocol built in to the language, because it’s a coordination primitive. That’s what we need to do in a language, provide these coordination primitives so that the ecosystem can standardize on them and then work together, right? That's what we do, build standards. So it’s very important that we have those kind of things as part of the standard library. Additionally, we maintain the standard library and the standard library, in particular async iterator, is a built-in consumer of such things, so unquestionably those should be part of this proposal. But for concurrent task queues, even though they are clearly very desirable and much needed, the design space is a whole lot bigger. + +MF: There’s a lot of variety in those different libraries. They go from very, very simple kind of like one-pager implementations to very complex libraries, and they all choose different subset of all of these features, which are all useful in their own right. And you sometimes don’t just want something with everything. A lot of the people who just have one of those one-pagers with a priority and none of these other things don’t want to think about all these other things and have that all built in. And additionally the thing we’re providing here, Governor, would be helpful in building such a thing, so it makes it even easier to build those libraries. + +MF: Now, I do think that it would be valuable to explore this space. I think it would be a great Stage 1 proposal where somebody actually looks at where we could draw a line and reasonably include the features that are needed by the most people without excluding too much, and make it extensible or something. But I don’t want that holding up the rest of this proposal. It is a possible follow on. I don’t know if I will do it, but I don’t know if we should forever leave it to the community. Maybe we should wait for more centralization. I don’t think that will happen, because as we talked about, the variety is pretty extreme. But it’s an area for exploration. For now, we've just completely removed that whole space from this proposal. We’re not trying to solve concurrent task queues. I will continue using these libraries in my own code, though. It seems like everyone needs a concurrent task queue. + +MF: So we’ve also considered how this interacts with the ecosystem. As I said before, we interact with explicit resource management, the using syntax, because governor tokens are disposable. So they implement `Symbol.dispose` and `Symbol.asyncDispose`. We’ve talked about cancellation a lot. The—you know, it’s important to be able to abort token acquisition, right? When I try to acquire, I may, you know, at some point say, "oh, never mind, I don’t want that resource anymore". And I need to be able to, you know, stop acquiring. This is going to come up a ton. So there needs to be some way to do it. Right now, cancellation on the web happens with abort control and abort signal, and we want this thing to kind of work well with things that are cancelable on the web. So in my opinion, our hands are pretty much tied. I went down the route of trying to design something really nice with abortable governors that are separate from governors and we can make nice guarantees about if you’re a non-abortable governor you can’t abort the request, and that's beneficial for some case, but it was ignoring the greater context that we want this to work well with other cancelable web interfaces. We need to do something with passing in a signal and working with abort control and abort signal. There will be some changes to make that integration. We also need to consider that atomic mutex from the shared structs proposal is somewhat overlapping in the way that you would maybe confuse them with counting governors. Maybe we just need to choose the same method name, but they just have different prefixes. I mean, we’re not doing any kind of atomic actions within this proposal. You know, I know people had an issue with, like, naming counting governor semaphore before because they, again, thought it was only for, like, threading use cases. Even though semaphore just means a counter. So anyway, we need to consider how those two will exist together. That is work to be done still. + +MF: And then we have design questions. These are like things that could go either way, and I would really like feedback. I mean, I don’t have to get feedback. I can just make decisions. But if there are people that are going to have opinions after I made that decision, I would like to hear that feedback sooner rather than later. These will be in no particular order. I’m just going to go through them and explain what I mean here. But some of them are not very important at all and some of them are pretty important. + +MF: So should counting governors have idle listeners? This is a thing we saw a lot in the concurrent task queues, is that they would want to know when there’s no work being done anymore. Similarly, somebody might want to know when there’s no consumers of a particular resource. And they want to be notified in the event that that happens, not have to poll for it. So we could add that. I have experimented with it in the polyfill. It’s fine. Is it useful to include? I don’t know. I think it probably pays for itself, but I don’t want this to have a massive surface area that I put in front of the committee, and hear this is scary, it’s too big. I put in right now what I think is absolutely necessary for sure. And if everybody says, like, yeah, we should add that too, I’m happy to pull stuff in. So I think it would be probably good, probably pay for itself. + +MF: Should there be a prototype for GovernorToken in the same way we put a prototype on governor? Should GovernorToken be a thing rather than just an interface? This could be helpful because we have the ergonomic string-named `.release()` method, which is supposed to do the same thing as Symbol dispose and then you can just implement one and then the prototype is helpful in defaulting the other. Alternatively, we could just have the Symbol named methods for doing that, and expect people to always use explicit resource management or have a really unergonomic invocation of the disposal method. And I don’t know what else we would put on it. Maybe somebody else has ideas for what helper methods might go on GovernorToken one day and maybe at that point we could add it. Maybe we can’t. I don’t know. I’d have to think about that. But should it be there? I’d like to hear feedback. + +MF: So I talked briefly about it before, but, should there be some kind of time-based Governor that can do throttling? CountingGovernor is obviously the most common description of a concurrency strategy, but a throttling governor seems to be like the second most common thing that people want to describe. We saw the need for that in some of those libraries. I think probably eventually we should have something built in here. Do we want to have it as part of this proposal or as a follow on? That I think is more of the question there. Again, I didn’t want to present some big mega proposal and then it gets a little scary. But if people think, yeah, this is obviously going to need to go in, we can pull it in. + +MF: Oh, yeah, I kind of talked about release, and asyncRelease being string properties that are equivalent to the Symbol ones. If we drop the release names, and I say like it’s not ergonomic, would we also want acquire to be a Symbol and that be a Symbol-based protocol? I’m okay with that too. This is acquire on a governor, not a method on the governor token. I’m open either way there. + +MF: Oh, you know, I don’t remember who brought this up, but somebody brought up that, like, you know, every time we acquire, we create one of those governor tokens. That’s another allocation. Should we allow people to reduce allocation by passing in some representation of an existing token that now represents the acquisition? Should it be done as an optional acquire parameter? If we do that, then I kind of should have done the final bullet point first, that then, like that takes up that space, and we might want to use that space for other things. So I’d like to hear opinions on that. Is it really valuable to save those allocations? I don’t know. We’ve done it for other APIs in the past. + +MF: This second to last bullet point about avoiding deadlocks is almost certainly a necessity at this point. I was thinking about it would be nice just for convenience to be able to have like a `governor.all` that takes a couple of different governors and says, if I try to acquire this, then you try to acquire all of the governors that were composed. I was only originally thinking it was a convenience, but actually we need to solve the problem of someone who acquires one governor and tries to acquire a second one while some other actor is doing the opposite, and they’re deadlocking. I think this is, like, a really common thing that’s going to happen. So I think it would be irresponsible to add these without adding some way to compose them and use the typical strategy for trying to acquire multiple semaphores. So we probably have to add a `governor.all`. I should have just done that because I’m very confident that that’s the appropriate thing to do. + +MF: And then finally I talked about governors having a configuration as they’re constructed, but they might also want to know something about the actual acquisition site, right? So, for example, you might have a governor that is parameterized by some priority of the thing that’s trying to do the acquisition, and it passes that in. So would it be okay for governors to take an optional parameter for `.acquire` that tells them about who’s acquiring it and why or whatever. Again, this is all very open ended thing, because we’re talking about user extensibility here, where who knows what they would want to use that parameter space for. But I can imagine a couple of cases, and that means that there’s probably a lot more that developers will end up thinking about. But it makes sense that you want not just fixed configuration at construction time, but also dynamic information about who is doing the acquisition. + +MF: So finally, these are the things that I believe have to get done before I present for Stage 2. We need to figure out how to integrate AbortController or AbortSignal for cancellation. That’s a very important thing. We need to make decisions on all of these open design questions that I just presented. If there’s any feedback today, I need to incorporate that. I need to update the proposal explainer. It’s definitely out of date. And we have some portion of a polyfill, but again also out of date. And that’s going to need to be updated too. But that can’t really provide any value until the polyfill for async iterator helpers is complete, which we’ll be waiting on KG for. And, yeah, I’ll have to provide some spec text, but that should be fine. And that’s my presentation. I don’t know how much time. I used a half hour of my time. So we have half of the time for feedback. Hopefully there is a lot on the queue. + +KG: Yes. Great presentation. I want to argue for CountingGovernor being named semaphore. I think the people who thought it should be named not semaphore were wrong. This is what everyone in JavaScript calls it. Also, as we’ve been discussing briefly on the Matrix chat, it’s totally possible that this could be made to work across threads, and then it would actually serve the cross thread use case as well. But I think even if it’s not, it’s definitely valuable on its own. Semaphores are for concurrency, not parallelism. It should be called semaphore. We can fight about that later, though. + +CDA: Okay. NRO? + +NRO: Yeah. Disclaimer, I don’t really don’t know what I’m talking about. But if, like, use case is presented for the counting governor is that you have some resource, and say you have three buckets cannot do more than four things in parallel with three buckets and you want to limit yourself to three, and then when you acquire the right to use the buckets, would it be helpful for the counting governor to give you the bucket that you can use? + +MF: What do you mean give you the bucket? + +NRO: Give you an object. I don’t know, like, you have three connections. Acquiring gives you a connection object that you can use, maybe subclass talking. I don’t really know. + +MF: I see. Instead of just—instead of, like, just giving you the token that represents that you have the authority to use the resource, give you a pointer to the resource itself? + +NRO: Yes. + +MF: It’s not how we’ve designed it. I can think about that. Off the top of my head, I’m not going to be able to give a good reason why we don’t actually manage a resource itself. But let me think about it. + +CDA: Kevin? + +KG: Yeah, it does work like that in Rust, but Rust obviously has its extremely powerful type checker so that it can actually guarantee that the token that is vended by the lock is the only thing that grants access to the resource. I don’t think it necessarily makes sense to do that in JavaScript, just because we don’t have that type checker. And that’s the main reason you want to do it in Rust. In JavaScript, it’s easy enough to say assuming you have a token, you’re allowed to call a `poll` method or something. + +PFC: In the bottom point on this slide, can acquire take an optional parameter and—did I understand correctly that it’s passing a user-supplied value through to protocol methods? + +MF: Yeah. So the—so the acquire method is part of the governor protocol. And, you know, it would not be used by counting governor because it doesn’t need any additional information about the call site. But for something that, in my example, like priority, for something that needs like a priority at the call site, it can take in that information and use that for maybe—deciding which of the many things that are trying to make an acquisition actually get one first, so I wouldn’t say it’s like passed through to the implementation, because the governor itself would just be implementing an acquire that consumes the parameter rather than ignores the parameter. + +PFC: Okay, but fundamentally, is a userland value going into the engine and then back out into userland and then back into the engine? + +MF: No. + +PFC: Oh, okay. + +MF: We’re talking about user-defined governors here. If I would write my own priority governor of some kind that has an acquire method that has a parameter rather than does not have a parameter. That’s the question at the end. Like, is it allowed to have a parameter. + +PFC: Okay. I was going to caution you about some of the cans of worms that we opened in Temporal when we still had protocols there. But it sounds like this doesn’t apply. Great. + +CDA: Ruben? + +RBR: So I believe in general, it’s great to have something like that. I’m just wondering if is it actually simple enough for most developers to being used? Because, like, the current helpers that are meant to be replaced with it are actually very simple, often. They’re just straightforward for everyone to understand, and with the governor token, definitely being more powerful, you can do a lot more with it, and I believe it is good from that perspective. Just is it really intuitive as I said? I somehow doubt that, that a lot of people will be able to use it. And there’s another downside that I see with it. It’s actually only governing in one area. You don’t know the resources of that machine that you’re running on and you do not know with whom you might also compete with a different governor on that same machine, so that’s a big problem for me that I would like to solve, because I have looked into the same problem from a different perspective before to take the overall resources of a machine into account. + +MF: Yeah, so to the first point, I think the vast majority of developers are actually going to interact with this like we see on line 13 here. They’re just going to pass a number and it’s going to get faster. You know, they won’t be thinking about governors unless they have a more complex desire for concurrency, and most desires for concurrency is just "bigger number". So I think we don’t need to worry about the understandability there. You only interact with governors when you actually know—I don’t want to say you know what you’re doing, but know what you want. On the second point, I explicitly do not want to solve that problem that you’re talking about, of trying to assert authority over some entirety of a resource. We are talking about a problem space where you know a resource that you have, and you’re delegating authority to that resource in order to share that authority. The problem space of, like, trying to say, I’m on a physical machine and now I am the authority over all of this machine's available resources is a totally unrelated thing, in my opinion. I do not want to get into that. + +CDA: RGN? + +RGN: Right. So `AbortSignal` is obviously important to consider. I’m glad that you called it out head on. But it’s also a giant can of worms. And I was wondering if there’s any appetite for pushing something more fundamental and kind of taking the lead on a protocol or an interface or a pattern that isn’t so bound up in muddling capabilities and in requiring a whole lot of the web platform? + +MF: I think—KG’s on the queue next and I think he has thoughts. + +KG: Yes. Absolutely, RGN. I have thoughts on this topic. I fully agree we do not want to pull in all of `AbortSignal` and `AbortController`. And I also think that there are things that would need to be improved about those interfaces to make them usable for us. In particular, it cannot be the case that the way that you register that you want to get an abort callback called is doing addEventListener and passing the string "abort". + +KG: There must be a better interface for us to be able to use it. And there’s also a bunch of other thing that are wrong with abort signal having to do with the event machinery and cancellation and capability sharing. I think that the route forward is to try to improve those things on the web platform, as part of WHATWG. Potentially with the motivation that we would like to be able to use those things in JavaScript, but I think it’s also well motivated to improve the things on the web platform. As evidence for this, I present any the web internal uses of abort signal all work exactly the way that you would want userland to work, so it’s understood on the web how these things should work. It’s just that the capability of using these things in the correct way is not exposed to users, only to web internals. So I think that we can probably, hopefully, work with WHATWG to improve the usability of abort signal and abort controller. And then having done that, define a subset of those interfaces in JavaScript, so what we could say is in JS, there’s a class AbortController such that instantiating that class gives you an instance that has a `.signal` property, which is an AbortSignal, and AbortSignal have a, for example, "onTeardown" method, which takes a callback. And on the web platform, these classes, AbortController and AbortSignal, would have a bunch of other stuff, and those things would not be defined in JavaScript, and these would be extending JavaScript which wouldn’t require changes to the web platform. It’s allowed to do that. And other platforms could also have that subset that’s only in JavaScript and have cancellation that interops with how it works on the web. + +RGN: All right, I’m thrilled to hear you say that you also agree that there’s a path forward. Cancellation is obviously very important, but we just can’t use the status quo. I think it will probably be a long road, but that’s very encouraging. And I’m happy to have an ally. + +KG: Yeah. I do also want to say, I don’t think there’s any route forward to this other than improving AbortController and AbortSignal. We can’t define a new thing. It has to be something that is, like, transparently already what the web platform is doing. + +CDA: All right. We have exhausted the queue. + +MF: Okay. I’ll give it like another minute, but, you know, while we wait for anybody else to get on the queue, I just want to remind you that, like, there’s an issue tracker, you can post opinions there. Talk about any of these open design questions there. So I would love to see more feedback on the issue tracker, you know, before I really get going on updating this proposal. + +OFR: Maybe since we have time, so I was wondering about universality. So you showed, like, how this is coming up in different libraries, and it’s, I don’t really know much about these things but it looks like an opinionated design, so I was wondering is there limits with what you then can do it with since—yeah, I was kind of missing that topic from the presentation. What are the limits, what can’t we support? What would we have to add on top of it to support everything? + +MF: Yeah, that’s a good question. I hope this interface is not too limiting. As I showed in the bottom bullet point here,, once we start thinking about additional concurrency strategies that people want to implement, we learn things like oh, it’s actually useful to know about the call site. Maybe you need to have a parameter passed in to acquire. That changes this governor interface, and hopefully during Stage 2, we could do enough of that, learn enough through experimentation, that we feel confident that it is very broadly applicable to the kinds of things people want to do. I’m unusually optimistic that we will actually be able to get good coverage there, because it is a simple concept of saying, hey, I need some time with that limited thing. And then, okay, I’m done. I no longer need some time with that thing. There’s really not much more to it than that, other than as we said, maybe telling the controller, why I need that time or who I am or something like that. And we could be fairly flexible with it. Just saying, like, throw an options bag into the acquire. So, like, I feel pretty good. I feel pretty good about it. I’d love to hear if people come across cases that are not covered by this, and I can then talk about whether that is desirable. + +CHU: Yeah, coming back a little bit to this, what OFR was saying. So thanks for the presentation. I think from a developer’s perspective, I think it is useful. Especially I also think the prospect of kind of, like, you know, getting rid of so many different libraries is something that is pretty interesting. But, yes, as weed say, so I need some time to digest the whole thing, and my only concern so far would be the report, you know, like, API design, so naming, stuff like that. So that’s what people were kind of also saying in the queue. So apart from that, I think it’s good. Yeah. + +CDA: Stephen. + +SHS: Yeah, so if you had an additional optional parameter to the acquire method, my understanding is that all of these iterator helpers would be calling acquire. And would not know what to pass to. Obviously it’s optional for a reason, but I guess how do you see that working together? + +MF: Yeah, that’s why it would have to be optional, because some consumers just won’t have that information to pass. So any governor that’s written to observe that parameter would need to expect that it’s sometimes not present. Unless you have any idea of what additional information the AsyncIterator prototype methods would provide. + +SHS: No, I’m just trying to imagine if somebody would want it to somehow pass those—the extra information along, maybe need another parameter, they want another parameter to those methods to again say what kind of—I don’t know. I was trying to Imagine what people would want. + +MF: I see. + +SHS: Or lacking. + +MF: That’s a good point. That is something I should think about, is if the caller of the `AsyncIterator.prototype` methods would provide that and then it gets passed through during that orchestration. That’s something worth exploring. + +CDA: We have exhausted the queue. + +MF: Okay. That’s fine by me. I can yield the rest of my time. Thank you all for the feedback, and remember to participate in the issue tracker. + +CDA: Would you like to dictate key points summary, conclusion for the notes. + +MF: I would prefer not to. + +CDA: Okay. Will you commit to— + +MF: Yes, I’ll write it in the notes, yes. + +CDA: Okay. I have to ask. + +KG: Just before we move on, I do want to say that the effort to get abort controller and abort signal sort of cleaned up in WHATWG and some subset of them imported in the language I think is important and something potentially a lot of people will be interested in, so please anyone who is interested in that topic come chat in Matrix and at some point, I will try to put together some sort of presentation to bring to WHATWG. I’m especially hoping that I can get the participants from browsers to help out a little bit there, because I have personally found it very hard to get feedback from people in WHATWG historically, and this is going to be a blocker for this feature getting added to JavaScript. + +### Speaker's Summary of Key Points + +* The concurrency control proposal has evolved since last presented +* Scope has been limited to not include concurrent task queues +* Reinforced justification through comparison to highly popular npm libraries +* Reviewed remaining open design questions and cross-cutting concerns + +### Conclusion + +* Committee has been updated and some feedback has been given + +## `Object.propertyCount` for Stage 2 + +Presenter: Ruben Bridgewater (RBR) + +* [proposal](https://github.com/tc39/proposal-object-property-count) +* slides (not shared) + +CDA: Are we attempting to get the screen? Okay, there we go. + +RBR: Sorry, I had to—I was still in a Zoom call, and that’s actually the wrong window. Give me a second. Sorry. All right, sorry. So like we have spoken about performant object property counting before, and in my original proposal was for problem space where we are often and definitely needing the number of properties on enumerable own keys, that’s very frequent use-case. I was also suggesting to do the same for something like get on property names and for getting property Symbols. I wanted to make that as a very generic API general originally, where it would work with an options bag so pretty much any possibility can be retrieved by any user. Because, like, at the moment, and we are allocating an intermediate area to getting the data, this causes obviously, like, memory pressure and such, like, the garbage collector is involved, and we normally don’t need this at all. Like, with the engine can likely optimize this at least from an after first access to know how many properties are on—could count it definitely. + +RBR: Now, the original one was rejected, at least in its current form, and therefore, I was looking into it again to make it simpler. And to separate it in three different built-in methods that we also discussed before to just have the object keys links method as well as potentially object get own property names links and get own property Symbols links. This would not have any options anymore, so it aligns with the existing methods, and also as less possible options in general, like, with the original one, it would have been possible to, for example, get non-enumerable property count, which is a rare use case, definitely. And I have not found any use case before that. And that’s something that would not be possible as such directly anymore. And my focus is only actually for this one. And my suggestion is we discuss this as a main key. And, like, I would ask the committee to consider `Object.keysLength()`, and to be implemented as such. And we are—I’m also suggesting the other two that I would like to separate it into different steps for a vote. Some usage examples are, for these simple case, we discussed it before multiple times that we definitely have sufficient usage for that. What was way more difficult to find is usages for the others. And like get own property names links is actually something that is used a lot in pretty much all end code. Why? Because, for example, babble is used everywhere. It’s always vendored or transpiled in the end, and there’s another module I forgot, which also contains it. I believe it was one of yours. + +JHD: Yeah, there’s one of my mine called `hasSymbols` that I do this check for because I have to detect core JS’s Symbol polyfill or attempted Symbol polyfill. And I would be able to take advantage of the faster check-in and engine. + +RBR: So and, like, I tried to actually filter those, and it’s not so easy always, which definitely uses moment and video.js and grape-js, which are direct usages, and I just had it open, and I don’t know, my Windows got confused when I was playing around here, and I don’t have it open anymore, and I can open it again in a second. And actually, on—as a future reference, what we could consider while I was looking into it, I definitely found that more likely usage what would be actual usage is Symbols. Like, everything we do, and when we work with it is probably also a little bit babble related or helpers. Every code base tries to filter for enumerable Symbols. And not that it’s a super heavy task regularly, but it’s a common task. Why is it not super heavy, because we don’t have as many Symbols on objects. It’s still much faster in the end probably because, like, in that case, the filtering is completely gone. So that would be a potential and future thing. But for now, I want to focus on the simple keys lengths and would ask the committee for voting only for that for Stage 2. Jordan, do you have anything to add for now information + +JHD: yeah, in general, the last presentation of this proposal had a single method with an options bag, and there was some pushback from folks saying, you know, I’m paraphrasing here, like, they don’t like options bags, they’d rather see a bunch of separate methods. There were differing subjective opinions about which pattern is more discoverable, you know, within an IDE with tab completion. There’s examples of both patterns being discoverable, so kind of it’s not really clear that either one of them is more discoverable than the other. What I would point out is this committee has long preferred smaller proposals that build on each other over time. That’s fine. That’s a great way to design stuff. But if the full future design direction is not thought through to some degree, then things can organically go in weird directions so you end up with weird words. I’m sure everybody’s got a pet thing in their this might qualify for that. So in this case, in the fullness of time, if we can convince the committee that all four of these types of counting are necessary, then we’re going to end up having four—either four separate methods of, you know, like westbound a length suffix or a count suffix or whatever, or one separate method. + +JHD: If people are cool of peppering four separate methods knowing that’s the definition we’re going for. Great. Separate method is the right API design to go with now and works very easily as the composable thing and add one at a time and parallel proposals that advance together kind of thing. However, if that feels distasteful to anyone, then it might make more sense to have a single method that has progressively added options support so that we still only have one method moving forward. You know, I think obviously I think Ruben and I have the preference of the original design and one method with the options bag. We find that more discoverable and easier to use and document and so on and cleaner. But that’s a subjective opinion. You all can have different ones. But since whether it’s separate methods or single method is a major semantic that is something that has to be decided before Stage 2. Just wanted to make it clear to everyone that, like, we fully intend to eventually convince you all that all four of these problems need solving. Assuming that happens, we will have four methods with the current proposal. So if you don’t like that, please offer your thoughts on a single one. + +KM: I think in general, this proposal kind of the intention of many respects of this proposal is to avoid allocating an object to then say the API requires allocating an object to call it kind of defeats the purpose in many respects. Certainly when your engine is optimized enough, you can eliminate the object allocation but most code on the web does not run in any tier that does any optimization. And when people come to the committee and say I have a proposal to improve performance and to avoid an object allocation and then obviously the array allocation will be a lot bigger. + +JHD: And the other note here is that your options bag you only need to define once. You have one object whereas you call the function end times. + +KM: Nobody hoists the option bag and write the literal— + +JHD: I understand that’s the pattern. What I’m saying if the goal is to avoid allocations you would do that. Totally fair to then say we shouldn’t design something that has a pit of success or something. Yeah, like a foot gun like that and you have to be something extra to have it be performative that’s fair feedback and to have a single method without the option is great, I don’t know of one off the top of my head. It’s not entirely true given the usage patterns that having the options bag cancels out the performance, it requires the hoisting. + +KM: I think people just don’t do that. I have never seen that in any code that I optimized in the web. I haven’t seen the source thing. It’s just there. And this can’t be done by the transpiler because it’s actually semantically wrong because the identity of the object changes from being one to many and so they don’t know if the thing you’re calling is actually the real web API that will care about the identity or not. They can’t do that removal. So they just don’t. And maybe there should be some flag or something where you say I promise I really don’t care about options bags. Web API says it’s an option bag, please just hoist it for me. Then people run into weird bugs and turn it off. And so, like, I do worry that, yeah, the options—I guess my point, you know… + +NRO: Yeah, question. So you said that engines will be able to optimize this but only in the most advanced tiers and not in general? + +KM: I mean, maybe there’s some hypothetical world where you could do this. Again, you don’t know what you’re calling, right? You need to do something where you have some sort of SSA form of your program and that is at least for us on most code is like code ever CC1 runs on that state at all. Everything else runs in a completely and execute the byte codes in the interpreter or in the JIT code and no nonbyte code optimization and object allocation is not in the same thing as the function call that would be— + +NRO: I would expect it in this case the case where cost of the object matters when you’re running it as many times. Probably go through the most advanced tiers any way. But here my personal position is the proposal I would like to follow what engine developers think it’s best. + +KM: People say that but most code doesn’t run on that. And there’s, you know, you can call this thing in many different places all over the code base and it could be smeared all over the code base and isn’t going to get optimized. + +NRO: Okay, thank you. + +MAH: We like the multi-method approach. I think it’s more easy for users to understand what it does. + +LVU: I think at this point a lot of the things I was going to say have been already mentioned. But overall, I think there is a need for something like this. So +1 to the general need. I’ve also come across use cases where I wanted to see the length of own properties, not just keys. I’ve seen use cases for both. I don’t think I have ever seen use cases for counting the length of Symbols without actually accessing the Symbols. So I don’t know if there are use cases or if this is just for completeness. I agree with JHD that the options bag would be a lot more elegant. The way I see it which may not be the motivation for everyone, but the way I see it, this is the method that primarily exists for performance or otherwise you can get object case length or object get own properties length. It seems to me that the primary reason to use this one instead is to avoid the whole on the allocation. If we require the options bag and we have that performance over here, it kind of seems like it defeats the purpose. So I would also even though I generally do like options bags, I think in this case it’s not a good fit. I would also vote for multiple methods although some of the method names proposed seem a little comically long. I wonder if something key count or own property count, I don’t know. + +LVU: And I kind of want to +1 in advance what EAO is going to say. The object is empty. That seems like a really nice thing where a lot of use cases around this is basically figuring out if it’s zero. And that covers that while avoiding all the more elaborate design decisions around the individual methods. + +RBR: I agree that it is indeed like about the empty case, it’s probably the most common case. But it’s definitely not the only case. Actually when we were looking into this, we had, for example, a couple of situations where it was checking for a single or maybe two known properties to be the only own properties on an object. For that completely not work anymore. You still have to use the other method. + +JHD: The other thing is there is not a single concept of empty. Does that mean zero own enumerable Symbols and some care about Symbols and not strings and some care about strings and not Symbols. Some of them, I don’t know, is it an object with under protonull empty, I don’t know. For each given application it’s easy to say this is what empty means here. In the broad general sense for the language, I don’t think that’s an easy answerable question. We can decide something. As Ruben mentioned we spent hours looking at scraped results of code searching and very few of the cases were as simple as just `Object.keys` length equals zero or not equals zero. Most of them were doing more complex things that would motivate the additional methods or having the ability to count and not just check for zero. + +RBR: Also for a fast test for comparison. Like, that’s very important actually. You want to know if something is identical or not. And to just decline without having to spend any additional CPU resources and just check for equality of the lengths. That’s a very common CC1 use case. + +MAG: Basically I want to echo what KM said from the perspective of performance. The object bag undoes most of the value of having a new method. If the goal of this is performance, and I think it is, let’s not do the options bag. + +KM: I also one of the thing for us at least on JavaScriptCore, the returned backing of the Array is copy on write and shared with every single one that you return. Actually allocating the options bag will allocate more memory than the wrapper around the array and would eventually worsen the situation. Once we’re talking about the higher optimization tiers we could in theory know the array length and not allocate anything any way in either case, all you’ve done is made performance worse in the lower tiers than the higher tiers. + +RBR: To cut that short because I believe a lot of people were speaking up for no options bag is someone in favor of an options bag? + +RBR: I don’t see anyone. That means that’s ruled out. + +JHD: That’s fine. The reason I brought this up is also because during the Temporal discussion there was some push back from implementers about the number of methods that exist and the desire was to have fewer. And this is the opposite of that. So if that’s fine, because this isn’t 50 methods, possibly 4 or 5 that like cool. We can go ahead with single methods. More important to solve the problem. + +EAO: Feels weird to be replying with my own topic after it’s been considered already. Fundamentally it sounds like we are being asked to make a decision based on improving performance for certain cases. Improving ergonomics for something that is related to performance and we are told about looking at many sides, all these examples but then do you have further data of what you gathered? The question I specifically would have is, yes, I entirely believe there are many cases where you care about a length other than zero about what that might be and so on. I have no clue what fraction of the whole of the times when there is interest in the length is about interest in anything other than zero. Is it like 90% is about asking for zero or not or is it like 50% is about asking for that? And it feels to me like a sense of this would be important in order to figure out the semantics of what is the appropriate thing to promote to Stage 2? + +RBR: If I may answer about that, so the numbers actually even if we would have a full data on that which I cannot deliver as such with a percentage, but I don’t believe it’s the right angle to tackle it, because actually the empty cases often for options, which are not as many, and when you are having more properties, it’s often the comparison. And now how many times is the single module used or this method used in what circumstance? This matters a lot actually for validation. I also care about the length and because I have an expectation that an object has a specific shape. I can immediately decline anything in validation if I know it doesn’t match my expectation. That is definitely a performance sensitive thing on the server side and I want to know is it right or wrong? And in this case, like, the server will probably have a huge use case, about like how many instances are there. So I’m struggling with what numbers are we actually looking at? Even if we would have the number that you were requesting. + +JHD: The other thing to add is that if you’re looking at how many humans have written the code that cares about, you know, non-zero numbers or like specific non-zero numbers, we haven’t done that research yet, but if you’re looking at how many humans run the code that does that, because it appears in Babel helpers that NROs queue item I’m sure will talk about later, it’s such an unimaginably large number of websites and unimaginably large number of humans are impacted, it doesn’t matter if one person wrote the code one time because it’s so prolific. + +CDA: Couple things. We have quite a large queue still. We have less than 15 minutes to get through it. We’re getting some feedback from folks remotely that people in the room are hard to hear. Please speak into the microphone. Make sure you are audible. (It was on when JHD was speaking). Maybe like a little closer to your mouth when you speak JHD. + +KG: Just to reply to the question about how often you want this just to be zero versus actually caring about the count, I think you actually care about the count pretty frequently. The case this comes up for me is that I’m using object as a string keyed map which is like a pretty normal thing to do. I mean, we do it in our own standard library functions. And I mean, how often do you care about `.size` on maps for the count just being zero versus actually caring about the count. I mean, pretty frequently you care about the actual count. Literally every time you do that, you would also do it here because, again, it’s often when you want this, it’s just because you’re using an object as a map. + +MAH: So there’s been a lot of talking about performance optimization here. The thing I think to realize there are a case that impacts us quite a bit where performance is not the only problem. It’s like the memory cost of doing a call and basically doing the length on it especially in the case of TypedArrays. We basically want to know if there’s extra properties non-indexed properties in TypedArrays. TypedArrays can be pretty large. If we need to get the full list of all the index properties just to realize there is no index properties on it, it’s just a massive allocation for no reason. And you may run out of memory just for that. And then you have a correctness problem, not just a performance problem. So in our case, we’re interested in getting the counts of own properties name properties sufficient on the TypedArray so that we can detect if there’s no extra properties on it. And there’s no other good ways than if you want to be careful about memory allocation. + +KG: I’m very happy to see `keysLength` or `keyCount` whatever we’re calling it to go forward to Stage 2. I’m not totally convinced by any of the other things. JHD mentioned we’re splitting this up and bringing the parts individually as four or five proposals. You’re welcome to do that but do not expect it to sail through committee. I haven’t seen a case convincing to me other than the basic one. Basic one, one hundred percent. + +JHD: That is totally fair we need to make the case for them better regardless of API structure. But with the stuff RRB and I looked through all last night, all four have enough use cases we have to take enough time to prepare the case and deliver it. In a future case I’m sure we can do that. + +CDA: +1 from Devon and Ross. Matthew is next on the queue. + +MAH: As I just mentioned we need to know about non-enumerable properties. Care about the keys. Having non-enumerable ones. + +CDA: +1 from Christian. + +CM: Just asking from a position of genuine ignorance: in surveying of all the code that’s out there, I don’t have any doubt that you seen occurrences of these patterns a lot, but can you tell if they’re in performance sensitive contexts? Just because people write the code a lot doesn’t necessarily mean that code gets executed a lot, in the sense of being in a loop or in some operation you’re performing frequently. Do you know anything about that? + +RBR: Well, on the server side, as said, is validation. Depends on what object you’re validating especially when there’s any TypedArrays involved. Definitely very performance sensitive part. + +NRO: The usage in Babel, I can remember where we were using it. I was checking it now. We do count Symbols, but that’s mostly for some earlier terms. There are some proposals CC1 where it’s based on whether there is properties or not on some object so we need to implement that. There are some other usages where we maybe need the number of enumerable Symbols of the object spread but that’s like for all features that other people should stop. So people use the API, they’re probably running in browsers that support object. We probably update the API but ideally wouldn’t impact very few users because users subject not to use this transformative if benefit from the API. + +JHD: It’s a fine thing to say if they do in fact support only the modern engines that they should be, you know, tightening up the transpiler targets so they don’t need most of the helpers but in practice I think we know that’s just not the case. + +NRO: In practice, transpile too much. Here we’re talking about transfer of the future eight years ago but in practice users tend to transpile too much. + +CDA: That’s it for the queue. + +RBR: May I ask for Stage 2 for object keys length. + +KG: Sorry, I also didn’t get on the queue about this. I am tentatively okay with it going for Stage 2 right now, but it is very hard to prepare for presentations like this when the materials aren’t linked and the state of the readme doesn’t describe the thing that’s going to be proposed. Like, there’s a reason we have the agenda deadline. I guess I don’t insist on being a stickler about it for this particular case, because I think—I mean, MF and RBN are in the meeting and presumably also on board. So everyone who would have participated in those conversations within our company specifically has had a chance to talk about what is actually being proposed now that we have seen what has actually been proposed. But, yeah, I want to call out this as an exceptional case; that you shouldn’t expect to be able to advance proposals that you haven’t put on the agenda with all of the supporting materials ten days before the meeting. + +RBR: Duly noted. + +JHD: To be a little separately from what Kevin just said that he has noted, since the broader problem space is not completely solved by keys length, hopefully cool to leave it as Stage 1 and make a brand new `Object.keys` length proposal at Stage 2 and keep working on it and present it separately? Is that fine for everybody and also make sure that the part that Kevin is convinced of is Stage 2 and the parts he’s not convinced of is still Stage That also makes it clear hopefully. + +?>> NRO says +1 to Kevin but already said it yesterday. Okay. + +?>> Sorry. I just added something. I am not super convinced about they’re very related problems. Are we talking about like splitting this proposal into tiny bits. + +JHD: Yes. But I think that it would also be reasonable to rejoin them later if enough of them advance. I agree they’re highly related. And in particular RBR is motivated to solve any portion of this problem as quickly as possible so that we can incorporate it into various code bases. But if we don’t split it up, then it gets kind of confusing about, like, because we don’t want to slow down keys length while still making the case for the others. + +MAH: As a user, I would be concerned why is there keys length and not a length of the other APIs that are very similar? + +JHD: Sure. But I mean, there’s a lot of confusing things about the static APIs. + +KG: What other APIs that are very similar? + +MAH: Get own property names, get own property Symbols. + +JHD: The other ones on the screen. + +KG: Those don't look anything like `Object.keys`. Those are just observably very different things. + +MAH: Different name. + +KG: They have extremely different names, yes. I mean, observably very different. I don’t know why you would expect— + +JHD: Either way, I would say that the number of developers who use these four APIs that give you the arrays is very, very large for `Object.keys` and very small for the other three. The number of users impacted is massive for all of them. Most of them don’t even know that the rest exist. I’m not worried about user confusion in this case. I think most people won’t even notice. My hope is we can fast follow with the others any way. + +CDA: We have a couple minutes left. And just gentle reminder we’re playing a little fast and loose with the queue. Please be mindful. EAO, can you be brief? + +EAO: Yeah, did I miss and did we discuss in this presentation why it's "length" and not "count"? Why is it "keysLength" and not "keyCount" which seems much more natural to me at least? + +RBR: Since originally it was property count and that is natural and it is generic thing. To align how users are currently using it that is pretty much like object keys target length, that’s why it’s called object keys lengths to key that aligned. I don’t have a strong opinion about that. Like, I would totally be fine with count instead. + +JHD: That’s also a Stage 2 level bikeshed I think. + +EAO: Sure. If the whole proposal is like this much text and the title of it is maybe the most important part, I think that is significant even at this stage especially as it seems that what is being asked for Stage 2 has evolved during this whole—now it’s just the `Object.keysLength()` or maybe `Object.keyCount` that you’re asking for? + +RBR: Like, my first step was to ask for that. And then afterwards, I would have liked to continue. But I don’t believe we have enough time actually to even go for the other parts. And like to continue discussing the others. + +CDA: We are just about out of time. So at this point, yeah, do you want to call for consensus or just wait and schedule a continuation to do whatever else? + +JHD: Yeah, I think we should ask—I think we would like to ask for consensus for Stage 2 for `Object.keys` length as a peeled out proposal and leave it as Stage 1 and then come back at a future meeting to try advancing the rest of the parts? + +RBR: While doing so, we can always align the names. I don’t worry about this. That should not be a problem. + +CDA: Do we have support for advancing `Object.keys` length to Stage 2? You have a +1 from EAO. +1 from Matthieu but frustrated about splitting. Do we have any objections to Stage 2? Okay. Noting we have a little bit of dissent about the naming and the splitting. But it sounds like you have Stage 2 for `Object.keysSomething()`. Length or count. Should be clear for the notes. Thanks. Yes, applause. James noted that the note taking was rather difficult with the quick back and forth. So please go back and check your comments for accuracy if you were speaking in the last 15 to 20 minutes, I would say. RBR and/or JHD, would you like to dictate summary, key points, conclusion, et cetera? You got consensus. Stage 2 for object— + +### Conclusion + +Object property count remains at Stage 1. Object.key\[sLength|Count] is separated out to be a new Stage 2 proposal and we will continue to iterate on both of these—the entire problem area which spans both of these proposals. The name will need to be decided before Stage 2.7. + +## WHATWG Stages + +Presenter: Chengzhong Wu (CZW) + +* [slides](https://docs.google.com/presentation/d/1I-3g1QFGaiazy98hf0RisfH5f0BVn6SRH5lfxxXJ2g4/edit?usp=sharing) + +CZW: Good evening and afternoon on the Zoom. This time I will talk about the WHATWG stages introduced. First of all, a disclaimer. I’m not speaking for WHATWG or any organizations. The presentation is from the point of view of a TC39 proposal champion. So if you find anything wrong or not accurate, please feel free to join the queue to correct me. + +CZW: So first of all, what is the WHATWG stage process? So usually when we contribute to WHATWG specs, we will submit a request to the specification, and it’s more dynamic than compared to TC39 proposals. WHATWG stage process was a new optional opt-in process and people are trying to contribute to the WHATWG specs, and the stages are asking for explicit implementer involvement at multiple check points and what we are at TC39 here and it’s useful for the broader community to see what’s the progress of a certain contribution, because it’s not easy to tell the steps of a proposal, how is it going, and if there are any concerns, and if it’s close to be accepted to the WHATWG specifications. So the stages give the community that how close a feature is going to be landed on the WHATWG specifications. So there was a blog post in April 2025 or just a few months ago that announced the introduction of the stage proposals at WHATWG. So what are the details of the stages in WHATWG? So it’s loosely modeled after the TC39 stages. So there are Stage 1, 2, 3, 4, but no Stage 2.7. It’s kind of like the previous version of the TC39 stages. + +CZW: So the Stage 3 in WHATWG requires the WPT of the new feature. And similar to what we have in TC39 a contribution to the WHATWG specification will require a explainer document but it’s not as the same as the specification text that we have here that is written in the very special text formulation. It’s just a required only the explainer document is required and there’s no formal format of the document. And taking a look at the WHATWG stages of view, it’s pretty similar to what we have here in TC39. So that’s kind of like loosely modeled after TC39 stages. And, yeah, going back to the presentation. + +CZW: So the issues that we are trying to address with the introduction of the stages are like we are—the TC39 and WHATWG are separate organizations and we have our own working model and there might be some discrepancies between the two organizations and there are some—sometimes for TC39 proposals, we need web API integration to be successful in the introduction of the new features and, for example, the ECMA script modules require the web integration and we have the syntax that work with the web APIs to be able to work to be useful. So this TC39 proposals we need to integrate with the web APIs but TC39 proposals also being staged. So we have to be able to inform the web editors that at what point that the TC39 proposals are being considered stable to be working because otherwise there are back and forth reviewing process that the proposals are going to change. If the proposals are going to be changed in TC39, the web part of the specification, we also need to be updated. So that’s kind of like back and forth between the two organizations. And that will cost a lot of burdens on the proposal champions to work with. + +CZW: So that’s a first issue that we want to address with the potentially with the introduction of the staged process. And the second is that we need to know how this proposal, TC39 proposals work exactly with this web APIs, like, for example we have the modules and the syntax proposals and we want to know how exactly in detail this proposals are going to work with web APIs and which web APIs this proposal will need integration. This also gives the TC39 committee here an idea how these proposals are going to work with the web APIs. And the third point is that we will like to mention before the stage process in WHATWG also give the committee how this web integration work is being progressed in WHATWG and how the acceptance—how the WHATWG is willing to accept the changes in the web space. So we hope that the introduction of the stage process could also unlock the TC39 proposal from being in the deadlock state being back and forth with the web specifications. For example, which party should advance the proposal first? But of course the introduction of the stage process itself does not address this issue alone, because we also have to coordinate between the two organizations. + +CZW: And we have talked about the stage process. And we can also see that what TC39 proposals or what TC39 proposals should go through the WHATWG stage process, of course, the stage process is purely an optional, opt-in process. It’s definitely going to be on the proposal champions willingness to be involved in this new staged process. But I think it’s recommended for proposal champion to go through the staged process if the integration work will involve large web integration work, for example, if it—well, it’s purely subjective to say what changes will be considered large of course. But it’s a recommendation that if the proposed champion find that the integration work is not trivial and go through the stage process might help the standardization. And so the recommendation is of course that the champions will have to obtain through the process and the question of us here is—the first question is, should TC39 explicitly document this kind of criteria for TC39 proposal to go through the WHATWG stage process? And the second question is, should we review what TC39 proposals should go through the process later? So when a proposal is going to advance in the WHATWG stages and we would like to say that how the two parties should advance, like, it is TC39 proposal should advance before a WHATWG contribution if it’s at Stage 1 and Stage 2 because at these two stages, a change in TC39 proposal is likely to be happened and we would like that. We don’t go back and forth between the two organizations. + +CZW: We would like to say that the TC39 proposal should be formalized first in the TC39 committee first. So that the fundamental of the work could be formalized and for Stage 3 and Stage 4, I would say that we should recommend the two proposals, the TC39 proposal and the WHATWG contribution of the integration part should advance together that could mean that we could ask a conditional advancement first and then say if this proposal advances next at TC39, we could say that the integration at the WHATWG could also advance conditionally or can we say that the contribution at WHATWG be advanced to Stage 3 before the proposal reaches Stage 3 at TC39 first? I think that will be a question for the committee. And there’s no Stage 2.7 at WHATWG. And I think it could potentially be viewed as on par with WHATWG Stage 3 because they have similar stage advancement criteria. + +CZW: So, yeah. And last what current TC39 proposals should go through the process? Once again, this is a pure voluntary process for TC39 proposals. So first we have AsyncContext at the TC39 and we have the champion support going through the process because we found that the web integration is not trivia and it could help us to express the states of the web integration work to the committee that we are not being stalled and working on the proposal and we are working on the web integration. And it’s currently at WHATWG Stage 1 now. + +CZW: We presented at TPAC last week on November 11th. And, yes, it’s already in the WHATWG stage process and it’s at Stage 1 now. And there are other candidates in the TC39. We have like ShadowRealm at Stage 2.7 and there were web integration documents and there were web integration needs. And also the phase import that is also at Stage 2.7 and I would expect that the proposal of the ESM phase import would be not as satisfactory if we don’t have the web integration available and also it’s nontrivial as a phased import to be integrated into the Node.JS as it has a node VM module that has a virtualization in the module in the node VM API and the ESM phase import would require nontrivial integration in web node J S and there are other proposals for the WHATWG process? That’s all the presentation. We can go to the queue now if there are any items on the queue. + +NRO: Mentioned and discussed WHATWG last week and the feedback be too formal. We should try to align document on the side and having to switch to Stage 4 together. They don’t care if the way we do things together is like unofficial like conditional consensus or something. The champion can just like see there is basic consensus on one side especially because on the website WHATWG you don’t see this every two months, there is much more active process to see if there is some consensus. The champion got to groups maybe TC39 first and then on the other side agree and ready to move and then we can formalize it on the other side also. + +MF: I agree with the sentiment expressed. And I think what you’ve presented is kind of very structured and trying to say let’s align stages or let’s try to have some kind of idea of conditional approval based on advancement or trying to align within the same week or something. I think that’s just excessive. I think maybe we can get to a point where we have something like that especially if the stages evolve over time to be more closely aligned. But I really don’t think we need that. I think what you’ve been getting at here is something we have talked about a bit in the past about like something our process document lacks is any kind of acknowledgment that there is a broader web ecosystem that will need integration or experimentation work and adding additional entrance criteria to one of the stages along the lines that like we have done that work, we feel confident in the direction, we have like the signs from them, you know, that’s a much more generic thing. And more generically applicable too. As the standard ecosystem around us evolves, either the stage process or what standards are relevant, it would still be applicable and new criteria for our—entrance criteria for the stages. I think, you know, trying to go about it that way is a little bit better and more flexible and still accomplishes what you’re trying to do here. + +DLM: I agree with what has been said. I think what’s important for us there’s at least some strong signal for proposals that have an effect on the broader web platform and acceptable on the HTML side and AsyncContext is a great example that the implementation and JavaScript is not concerning but has a large impact on the web platform. So I think this is a good sign that you’re going through the stage process here. + +ABO: So I think, considering some of the dynamics in this committee, when we were going through this and looking at the stages process, I suggest that is probably good to advance to Stage 3 and 4 together. And in particular, like, even if it’s not together together, having input to the committee some even if it’s an informal statement by WHATWG saying “from our side, it looks ready for Stage 2.7, or 3 or 4”. And then, like, I think that is still very valuable input to this committee—like, everyone who is not being involved in the web integration can know that, yes, the web integration side of this is actually involved. Like, that they agree with moving to the next stage. And in that sense, that would also be useful for 2.7 even if WHATWG doesn’t have a 2.7. + +CDA: All right. Sorry. I had to re-add some things to the queue. I don’t know. Something bugged out. JSL was up next. + +JSL: Generally agree with the statements about not being too formal. But I do have some rather, you know, very deep concerns about tying ourselves too closely to with WHATWG process. The reason WinterTC was created and ultimately TC55 exists was started is because WHATWG specifically ignored the requirements coming from node and server-side run times. In fact, in the charter, you know, in many conversations, they specifically say we just don’t care about those use cases, right? And I want to be very careful about tying advancement of proposals in this committee to another body that specifically rules out use cases coming from members of this committee. So I’m all for, you know, building relationships and making sure we actually have this alignment and things are moving forward but I want to make sure we’re not tying ourselves too closely to that. It’s very important. + +CZW: Yeah, I think I would definitely agree with this saying that the TC39 process are not going to be deeply coupled with WHATWG process and that also suggest I’m not suggesting that we are going to rule out any other runtimes from the integration process of TC39. So like I mentioned on this slide, that I say the integration with Node.js module is important to be as it is significant. For this particular presentation I think the point is that the two standardization parties can help—will need to work together to make a TC39 proposal successful and potentially we can also have other run times integration as well like Node.js. + +CDA:: NRO, I say you had a reply. + +NRO: Topic and reply are the same thing. Next on the queue. + +CDA: You’re up next. + +NRO: So WHATWG early stages can also be a good way to inform whether we want to continue to propose or not. I think something not proceeding WHATWG does not automatically imply that we should not do it here. which means maybe a proposal is with in this group some good feature for JavaScript but some web APIs would not get a tied integration with it while run times may get better integration for the proposal. For the reason we might think it’s good to put it in JavaScript. Even if something is blocked at WHATWG, we should decide maybe want to continue. There are some examples like ShadowRealm where in practice, even if we were going through the staging process, ShadowRealm maybe not going to Stage 1 and maybe imply we decide not to do the proposal. Too late to know what we have done. There is proposal like explicit that has no web integration at all but has quite good integration with service run times and we still thought here it was good for us to like design this proposal as a core feature of the language. + +EAO: Noting that the import text earlier that a couple of months ago advanced to 2.7 import bytes proposal have a lot of overlap with the implementation work that’s going to be—the proposal work going to be needed that we do in the HTML spec. I would be interested in hearing what signals are expected or needed by TC39 to unlock the advancement of these proposals in our committee and specifically given the context is there an expectation of the proposals going through the staging process of WHATWG in order for that to provide the appropriate signals for the advancement here or would it be better for the WHATWG part to be something ad hoc that is made up just for this? + +DLM: From my point of view, I would like to see merged MOS spec. I don’t think it’s necessary to go through the stages process. I think the PRs would be small and I think it would be easier to have them merged prior to them advancing. + +EAO: Wait, you want to see a merged PR in the HTML spec before it lands in the JavaScript spec in Stage 3 or 4? He said yes. But that is even though the text in the HTML spec is referring specifically to things that are added abstract operations that are added in these proposals that don’t exist at the time when it would land? I would presume that the HTML spec depending on the JavaScript spec means that the JavaScript spec needs to have the feature in order for the HTML to refer to it? + +DLM: I just don’t see— + +NRO: My reply here, I think that depends on whether we are going on WHATWG side through the process or not. If I remember correctly, the next standard way we have been doing things when working with WHATWG there’s a request and the request gets merged to the HTML spec and links to the proposal. And the request gets merged when basically the design is agreed upon and browsers committed to implement it. That’s basically equivalent of Stage 3. I think when going through the stages process, the request gets then merged with Stage 4, so maybe the going through the stage process, the signal the browsers want the Stage 3 even if that request is not merged yet but a separate document. + +CDA: We have one minute. + +DLM: Okay. Try to organize my thoughts. Stage 2.7 means JS specification is stable. Hopefully that’s a strong enough signal on the HTML side to move ahead. I guess my point is import bytes is like a draft PR and I guess I would like to see an actual PR. And in this case it’s module and so much is done in the host. It’s difficult to do meaningful implementation without knowing what the HTML spec side was going to look like. + +NRO: The reply was specifically for this topic about whether we should do stages for import syntax and that’s for the champion choice and for context we decide to go to stages because it’s a very large integration and many points we need feedback for import text and bytes that is probably much smaller and might be overkill to go through stages. + +CZW: I think another point that it might be worth mentioning is that what the WHATWG staged process are checked through GitHub issue labels and not like what we have here at TC39 and we need a repo and we need like sort of all the materials that are available. It could be more WHATWG compared to the Node.js proposal here and maybe apply to the request saying Stage 3 would be sufficient to the question. + +### Speaker's Summary of Key Points + +WHATWG now has a stages process similar to TC39. We discussed how TC39 proposals that have a significant web integration should interact with it. The involvement of the WHATWG stage process is voluntary for champions. + +The inclusion of the WHATWG stage process is not exclusive in the TC39. There can be other runtime integration as part of a TC39 proposal, like Node.js. + +AsyncContext has reached Stage 1 in the WHATWG stage process. + +### Conclusion + +The WHATWG stage process will not be an official criteria for advancement in the TC39 process. Stage 2.7 in TC39 should be a strong signal on the HTML side to move ahead. + +## Spec-defined or Implementation-defined limits + +Presenter: Shane Carr (SFC) + +* [slides](https://docs.google.com/presentation/d/1NsezmIvFSr4qH4EXnh-cqOjikiUx196feKNM797m6fw/edit?slide=id.p#slide=id.p) + +SFC: All right. Hello everyone. So what is this talk about? It’s called spec defined or implementation defined limits. So many JavaScript features have limits of things, upper limits defined by memory or because of memory limitations or so forth. And sometimes these limits are defined in the spec. Sometimes defined by the implementation. I’m going to walk through a few examples and then I’m going to have some discussion questions to guide the development proposals. First of all start with array. This is an example where there’s a spec-defined limit. So the longest length allowed for the array is UInt32 and says right here in the spec. If you don’t believe me look in ECMA 262, it’s right here. I checked in browsers. All the engines that I checked comply with this. It’s an array. The limit is here. This means that when engines implement this, they don’t have to—I’ll stick to the background and save the commentary for later. I want to present evidence. Array constructor has the maximum length. Intl mathematical value we discussed and I brought back a pull request in the last meeting. This is a spec-defined limit and we introduced in Ecma 402 and currently the limit is for the size of the number is defined to be limited to the range of exponents that an IEEE float supports. However, in the last meeting, we decided—agreed to change the limit slightly to cover more use cases. But it is still a spec-defined limit. + +SFC: ArrayBuffer. ArrayBuffer is interesting. This one is a little bit of a hybrid. So it has both a spec-defined and implementation-defined limit. There is a spec-defined limit says if size is 2 to the 53rd power minus 1 throw a RangeError. If it is possible to have the data block size byte throw the RangeError. It’s spec-defined and implementation-defined. The biggest that implementation can support is 2 to the 53rd power. + +SFC: BigInt. That’s very much implementation-defined. And I spent some time to try to figure out what is the implementation-defined maximum BigInt. What I found here is that it seems like Firefox has a limit of 313592 digits. As soon as you try to create a BigInt with 313593 digits, you get an exception thrown uncaught range error. And Safari throws uncaught RangeError. And it is slightly different of Firefox and same order of magnitude. Chrome has a BigInt and RangeError maximum BigInt size exceeded. The only way to reach the Chrome limit is not via the string constructor and Chrome has the smaller limit than BigInt and able to reach it by using some crazy like mathematical operation here in order to get Chrome to finally throw a range error due to BigInt size. + +SFC: Strings. Strings don’t have implementation-defined. There’s no limit written from the spec. This is an example, for example, when I take `String.prototype.concat` and no wiggle room and says return the string concat operation and no opportunity to return the error. This is how browsers behave. So I did this little thing where I take a one character string and I keep doubling the length until the browsers yell at me. Chrome gets to 28 iterations of the loop and throws the range error. Firefox gets to 29 iterations of the loop and prints uncaught internal error. Whatever an internal error is. And Safari gets to 30 and prints range error out of memory. I also tried getting this from an `Array.fill.join`. I could have maybe been able to use `iterator.join` but now use `Array.join` because that’s what I have. On Chrome when I run this, the tab crashes. It gives me the dead tab icon. Firefox when I run the line of code throws an exception. RangeError out of memory. Safari hangs (it’s been running on my laptop for an hour and it’s just hanging). So that’s what happens with strings. + +SFC: So one question here is are exceptions when out of memory conformant? So on the previous slide with string, for example, Firefox throws a RangeError. The spec doesn’t tell—let’s say it can. Firefox does. The spec doesn’t say it can. Also same thing with BigInt. Doesn’t say that you’re allowed to throw an exception yet all the engines throw an exception for BigInt when out of range. Is it compliant for engines to throw the exception or is the only reasonable behavior to either kill the tab and give me a dead tab icon on my screen or else just run infinitely and hang forever like Safari is doing? By the way, my computer’s CPU doesn’t notice there’s an issue here. I feel like Safari is like I detected you hit infinite unsupported request so I will just stop the program running. I don’t know what it’s doing. But there’s a few linked issues if you like to follow along on the issues. + +SFC: So this slide, considerations. When we’re thinking about implementation-defined versus spec-defined limit is some considerations we should take into account. One is implementations with different constraints. So, for example, we range on XS running on tiny devices and V8 running in data centres and this is implementation of spec defined limit. If you have the spec-defined limit does it work in both environments? Maybe it does or doesn’t. That’s one consideration. Another is behavior across engines. If I run code especially true for browsers, when I run code I expect the code to behave the same of course across different implementations. That’s kind of core to why we’re sitting here in this room. We care about consistency. And one is ambiguity of implementing. This hits me a lot working on some of the proposals. Like, if the spec doesn’t say what the limit is supposed to be, someone has to make the decision. Someone somewhere has to make the decision or else like, you know, whether it’s just relying on your memory allocator to make the decision or relying on the programmer to avoid the allocator making the decision and choosing something heuristic and someone needs to make the decision. As the implementer I much prefer the spec tells me what to do than me trying to be like I have a limit even though spec doesn’t tell me to have a limit because then I have to make a decision that really I shouldn’t be the one making it. It should be the proposal champion making the decision, not me. + +SFC: Difficulty picking a limit. So as an implementer I can say I don’t want to pick the limit. But the spec author is like I don’t want to pick it either. It’s hard to pick a limit. I want the BigInts to work and multiply BigInts and work. Even though it may crash some browsers and not others, I don’t want to think about that. It’s difficult to pick the limit. How do you decide what is too big or what is too small? And future proofing. + +SFC: This came up with Intl mathematical value. The limit we picked with Intl mathematical value is implementing all currently available data types and we had feedback that it is not scalable for future BigDecimal and Decimal128 types, and please fix. If you do choose the limit and too low does it break things when you increase it later? That’s another question. So I have some questions for today. And again, this is motivated because I’m working on proposals that involve like setting these constraints and I want to sort of discuss some of these questions. Under what circumstances should the implementation defined limit be preferred over the spec-defined limit and some cases where the implementation-defined limit is the right thing to do? Maybe there’s cases that spec-defined limit is the right thing to do. How do you make the call? One thing I want to state here is about the use cases. I guess that’s actually the second one. + +SFC: What guidelines should be used when determining the spec-defined limit? If you’re implementing a feature like Decimal, are you in the position to say, well, I think that all known use cases from the Decimal type are going to need no more than 10 to the 1000 power or something like this? And decimal gets this by using the decimal 128 type. Actually this comes up in Amount rather than decimal. Amounts where do we set the limit there? Set it to the decimal 128 limit or more than that? I don’t know what the answer is there. So what guidelines should we use? And then the third question is, should we sort of use this hybrid approach more? We saw this hybrid approach also in ArrayBuffer? I don’t know if it was intentional or not and hybrid limit. Should we favor more hybrids and favor conformant implementation need to support at least this big of whatever the thing is and maybe at most the other limit thing is and could pick between the minimum and maximum and that’s hybrid. And code written against the specification and conformant supports something in some range and doesn’t support something outside of another range. In-between the two is implementation-defined and complying code won’t write things that sort of hit the medium range. + +SFC: So those are my slides. This is the last slide. I was looking for some discussion on guidance here. Looks like we have a little bit of a queue growing, which is good. Why don’t we start going through the queue. + +WH: Let me try to organize the discussion a little bit. There are a few questions here. One is should there be limits? What should the limits be? And what happens when the limits get exceeded? We’re not running Turing machines with infinite tapes. There will be limits. + +WH: Let’s start from the last one: what happens when the limits get exceeded? The spec doesn’t seem to say and that is actually an area of concern because when you exceed things like memory limits or possibly fall into the infinite loop that somehow gets broken out of, you have a possibility that you might break some spec invariants. We have a lot of parts on the spec which maintain some invariants. Those often temporarily break invariants inside spec code but fix them up before the spec code finishes. If those get broken, you could have security issues, you could have all kinds of trouble. And implementations are cognizant of that. One thing that we might want to look at is specifying how implementations should respond to things like running out of memory. + +WH: The next question is what should the limits be. Should they be spec-defined or implementation-defined? This came up recently in a recent meeting when we were discussing the spread operator to build arrays. It turns out that implementations have fairly different ideas about how many arguments to a function are too many. I personally do not think that it’s possible to specify all of those limits within the spec. Like, I can’t think of how I could define the maximum limit on the number of stack frames you can have before things blow up. Implementations will differ as to what is considered a stack frame. You can’t specify limits in the spec on memory. implementations differ quite a bit in their memory allocation strategy—some may aggressively intern strings, while others may be content with the existence of lots of independently generated equal strings, each allocated separately. These things are impossible for us to specify. There are a few things which can be specified but for the most part, I consider this to be an unsolvable problem with the advice to implementations being just to be reasonable. Like, what is the maximum length of a string you can have? + +MAH: So if MM is around, he can probably take my topic better than I can. The issue is not just for—so WH just mentioned what is the spec going to do if one of these limits is broken? Might break invariants. If you fail in the location and basically end up having an operation failing when the program doesn’t expect it, if the program cannot observe it by having the exception thrown, then the program might get into an inconsistent situation itself. And this is why there is a Stage 1 proposal about “out of memory situations must fail fast”. So that really the program should not observe those situations when there is an unexpected condition encountered like this. Unfortunately there are diverging opinions on, I believe, which is probably why it has not made much progress. But we still strongly believe that programs should not get to observe the situations and the agent should be killed or actually the agent cluster. At least for operations where there is no reasonable ground that the program might expect an error. Like, this is where, for example, you had the example about creating the new ArrayBuffer. There are potentially expectations there that creating a new ArrayBuffer might actually fail. It is actually spec-defined that it is acceptable to fail there. But if it’s not specified if the caller has no expectation, it should not become observable. + +MM: I can clarify. MAH is right about our starting position. To explain the controversy and what the path forward is, is that the browsers currently do throw an observable out of memory or out of stack or probably both and they’re not willing to change the default behavior to fail the agent rather than throw the error. And I understand that certainly the status quo counts on that. However, none of these out of resource conditions are currently in the spec. So it’s our choice how to go forward in the spec in a way that both meets the needs of programmers and recognizes implementable reality. So the proposal “OOM must fail fast” basically turned into one of host fault handlers when one of these exceptions that programmers cannot reasonably recover from like out of memory even though right now in browsers, it’s presented to the program, it’s not practical to write programs that are fully defense against errors that might happen at every little micro condition. So the idea is for all of these, to instead delegate to a host fault handler and then as a wrinkle on top that could be part of the same proposal or could be part of a later proposal is to have the host fault handler then be able to delegate back to a user fault handler which might be data describing choices, might be something in another agent so you’re not depending on the own agent to—or might be just a callback and you hope things are safe enough. So the bottom line is that going forward to admit resource exhaustion into the spec to recognize reality, which we favor must allow an implementation to react to these resource exhaustion issues with a fail fast, with a sudden stop of the agent. It must enable that and if going forward with the proposal that recognizes finite resource reality and does not enable a conformant implementation to fail fast in reaction is not something that we would approve. + +MAG: So I just wanted to say kind of tying on to this, the spec doesn’t expect these sorts of like exceptions and it does get SpiderMonkey just specific trouble because we try, we are one of the engines that actually tries to throw out of memory and try to recover from out of memory conditions, and this actually gets us in trouble because we end up having to try to handle states that don’t exist in the spec, but only exist as a result of out of memory conditions in our engine. So one of my current background tasks to see whether or not we could flip it so that it worked more like Chrome and just crashed on memory. + +MM: Sorry. Chrome crashes on out of memory? + +MAG: That’s the tab crash. + +MM: I’m left with the mystery that questions raised by SYG representing Chrome or representing Google that caused us to give us on having a fail fast be the default behavior. + +MAG: Yeah, I very vaguely remember those conversations but I can’t provide any colours of them. + +MM: If we can get an agreement in the committee to have the default be to immediately fail the agent and then as needs arise provide opt-ins for something else, but start with the default being resource exhaustions that might happen in places reasonable programmers cannot prepare for should immediately crash the agent. That would be wonderful. + +MAG: Yeah. But just the actual point I wanted to make here is that pursuing this how far we pursue this, you get into the situation where a lot of the spec invariants suddenly stop being invariants because if you set new limits, they can be violated and then those—now you can’t write the nice exclamation points of syntax around the thing and never be an abrupt completion here. A lot of the spec will get kind of grosser is my suspicion. I’m not saying it’s wrong, but just a heads up that trying to handle all these errors is a pain. There’s a gradient between versus mill Tuesday to the implementation and the valueOf the spec that I can read this and reason about this in the 99.9% case. + +MM: Let me just double check with you in the default that I would prefer, the fail fast, the thing we originally proposed, there would be no such—it would recognize reality of finite resources and provide a spec recognized way to react and it would create none of the complexity that you just stated. Is that all correct? + +MAG: Yes. I’m just talking because the proposal or the discussion here is from Shane where he’s like, you know, where should we add new limits? Should we add new limits? How should we define them versus implementation-defined? I would caution that bringing all implementation-defined limits into the spec—and you could argue we should go further down the road—will make the spec actually worse. I’m not sure that’s worth paying the price. + +MM: Where the spec has spec-defined limits or not is—you agree it’s orthogonal to the issue of whether the default should be that the agent fails fast? + +MAG: Probably. Mostly using OOM fails fast is make mention of the spec change problems, but yes. + +YSZ: I’d like to just mention if we install user crafted handler as a full handler, there’s a high chance that it ends up doing out of memory due to the handler of this. So a lot of engines is having, for example, some fixed size of heap as a batch of memory agent so then OOM can be rather, it is extreme condition which is actually exhausting all the memory anymore and any kind of execution of user code would be allocating before something than embody the function and in this case it is doing fading due to the OOM, just a chance. + +OFR: Since this was asked to Chrome out of memory is not recoverable generally, so it will crash and yes similar to what you just mentioned, typically when you’re out of memory, you’re out of memory. It’s hard to do anything at this point. However, probably what MM was referring to there are some limits that we introduce, for example, we have the maximum string length and maximum array length and things like that and sometimes get a RangeError in these cases even though spec doesn’t mention them. As far as I understand, this is the current case. Also typically when we tinker with the limits, people tend to be really unhappy if they go up or down or whatnot. It’s actually something that people rely on and I don’t think we could just crash in all of these. We definitely could not crash in all of these cases. + +MM: Can I ask you a question? When you say you can’t crash in these cases, is that just because of legacy? Do you agree that practical programs, it’s beyond what practical programs can do to be defensive against thrown errors for some of the other limits you just mentioned? + +OFR: I don’t think I agree with that. I mean, I find it totally practical to try to allocate an array and have like maybe the input of the array is user controlled and then have the backup strategy if that is not possible right now. I don’t think it’s per se something that we should ban. + +RPR: KM is next. + +KM: On that point, definitely being compatible, plenty of websites where they handle OOM for like allocating some enormous array in the spot where they know they’re allocating something enormous. And they intentionally want to handle it. I also think that crashing is more likely to cause web compatibility issues in general because then all of a sudden it’s like your browser is slightly less efficient than the other browser in the context and instead of being the OOM that the website can recover from and it’s a full blown tab crash and no way for the tab to recover if you wanted to, and if they have a video game and trying to allocate stuff until they run out of memory. Browser A, you like—it works fine because they can just happens to sit under the limits and browser B, you know, they go over the limit and then there’s some way they can handle it even if they wanted to. + +JHD: The rationale that MM has talked about seems good in general. But to what OFR was saying, I think there absolutely are places on the web where people are feature detecting a known limit—not in a wild “double the string until it blows up” way, but in a “I know this precise number makes these browsers, that I have to worry about, fail, so I will do one thing and in those cases I will do something different”. I can’t remember off the top of my head if any of my older shims have that stuff. If they do, I didn’t put them there, someone else did, but I wouldn’t be shocked if they did. And so I definitely think just banning it outright is not fully web compatible. + +OFR: Now the slide changed. So there was this number to the 53 minus 1 on the slide. I just wanted to mention this it because it looks kind of strange but this slide makes sense. Step 1 is making sure that your number will be representable as a double position float without using precision. If you go above that, then you don’t get—you cannot represent the integer in a float anymore. And then the second thing just acknowledges that probably on TypedArray, often people allocate big arrays and maybe we need to fail earlier than that even. So I think this is actually—to me, this looks like a very sane choice. + +SFC: That’s very much the case here. Like, the spec once return the length of an ArrayBuffer as a float presumably, so it implemented that as a limit. It also is still the case that this is a limit. I agree with you that it seems like this is unlikely—like, this limit was chosen not because of the ones to have to avoid out of memory situations. It is still a limit. And this slide is also interesting because it is one of the only cases in the spec that explicitly allows a range error to be thrown. So there’s sort of a few interesting things here. + +OFR: Just wanted to add it’s not that we want to return it as a float, but it’s the only number that we have accept BigInt and returning the BigInt, well, maybe nowadays we could talk about it, but probably not a good idea in this case. So we have to. + +NRO: Very similar to what was just said. We don’t have just limits ready to out of memory situations, like, for example, the Intl NumberFormat limit that we had. I believe it was introduced for the memory problem, but it’s just because we felt it was good to have the limit there, which is now that we can increase the limit to something, something larger. Maybe we could at some point have the surety of when we need to introduce limits that are stricter than just oh, well, maybe you can do a thousand billion because that might fit in memory, but it will be good to limit users to just doing a thousand and things like that. + +SFC: I will reply to that that is also the topic of my topic below. But the limit that we have in Intl mathematical value is because of implementation limits. That’s why we added it. We added it because it’s more expensive as an implementer to handle the case of this has infinite precision. Then you have to write your code to be robust and have robust out of memory handling. Many of the libraries that the browsers depend on like ICU and others have questionable behavior when it comes to out of memory errors. It’s actually quite challenging to write in the browser engine that handles out of memory and in a proper way. So we added limits because of that issue. And the limits we chose, it was fairly arbitrary how we chose them. I don’t want to say there is any really, really good principled way that we chose them, which is one of the questions on this slide. We chose them because, well, if we’re going to be picking a limit, we may as well pick something that is small enough that is easy and cheap to implement and optimize it but using text storage when we can and things like this. If we are going to choose a limit, maybe we choose a really low one that is super cheap to implement but also handles all the use cases. And that’s what we ended up doing with Intl mathematical value. + +WH: Go back to the ArrayBuffer slide. So I’d like to point out that the spec does have a limit on string length. According to the spec the maximum length is 253-1 code units. On the other hand, the spec never says what happens when you exceed that limit. Of course implementations have more practical limits on the length of a string + +WH: Even if the committee doesn’t want to pin down a numeric limit on the length of a string or size of a BigInt, I would support it if the champions were proposing to introduce mechanisms like the one on line 2 of this slide for other cases such as string concatenation or BigInts building. I’d like to point out that a string exceeding a maximum length error is typically not an out-of-memory error. It’s usually quite reasonable to proceed with other computation and it will work just fine. The same thing happens when you get a BigInt that’s too big. So for those cases, it’s perfectly reasonable to sprinkle optional RangeError throws in the places in the spec where that can arise. I wouldn’t want to pin down the implementations of what the exact values of the limits should be. + +MAG: Basically this ends up being a +1 to WH because I like this language quite a bit because it recognizes reality and it provides a nice like exception type to throw. It means that when you’re writing algorithms against this is not shown to be infallible operation when in fact it’s fallible. So I like this idea of maybe being a little more judicious about this and, yeah, that’s about it. + +SFC: I also like this type of language. I would like to see more of it. I also want to emphasize part of the point here is I don’t know why we want to use this word impossible or deferring to the memory allocator. It seems really silly to like say that—also expensive to implement. As an implementer of Intl stuff I can say that like it’s really really annoying and hard to write code that checks every time that you call the system allocator checks to make sure this is correctly handled and returns errors and make sure that all the APIs do the errors properly. Like, in a perfect ideal world, this is how code would be written. In practice, this is not how code is written. In practice, the way that code is written is like when there’s—when malloc returns null then you exit the program. It’s very hard to write robust code in this way. It’s much easier if you write your code such that you—it’s very difficult to hit an out of memory error. So I have a little bit of—I’m not super excited about using the word impossible here. I would rather it be like if—I would rather the error be like if the implementation decides for whatever reason that it doesn’t want to create such a data block, it doesn’t necessarily need to be using the word impossible here. And it could decide tomorrow that it’s OK to create a block that it wasn’t able to create today. + +MAG: Basically, we already write code like that and it sucks. We have OOM simulations to do at that because you need to try, what happens if an OOM happens here. We have to build infrastructure to support this and it’s not fun. I support your notion of making this written differently than impossible. It would be the host may choose not to fulfill this request. You know, we can—for various reasons at various points. I don’t have a real real problem with impossible because I choose to interpret it loosely. I could see why you want to change it. + +SFC: I am going back to this question slide because I think that we had a good discussion today but I am going to sort of state what I see is the answer to the these. And then we’re out of time. So one is under what circumstances should an implementation versus spec defined limit be specified. It doesn’t sound like we answered this except that I heard a number of people in the room expression that the spec should acknowledge that these situations happen. And in that sense, then, we end up with sort of specific—end with hybrids like ArrayBuffer. I heard that. The second was what guidelines should be used when determining the spec-defined limit? We didn’t completely answer that question. Mathieu said, make it open enough that we could—implementations could choose to do something that is not just based on what the memory allocate says we could do. + +SFC: The third question is easier to discuss in the context of a specific proposal, Amount, which is “should we favor spec-defined minimums and implementation-defined maximums.”, something like this. And I think that that is—this is an interesting area to explore. And so for example, when talking about Intl mathematical value, say all engines must support at least a thousand digits of number, and may support more, but may also throw a RangeError or have other behavior for handling those cases if these chose not it. I would encourage any proposal champions who are dealing with this—with questions in this area, this is my main message here. I would encourage any proposal champions working on proposals that touch this type of thing to think about these questions. And when writing your specification text, look at what we do with ArrayBuffer, try to think about some of the questions whether you should set minimums, choose your guidelines—trying to add some flexibility and I hope that that’s what we can do moving forward. + +KM: A minimum runs into problems of yeah, if you actually run out of memory. What do you do? If the minimum is large to hit that without like to recover in the general case, let’s say the limit—like, you have to support a BigInt of 10,000 digits. That’s a big allocation. If that allocation must exceed your program crashes. Spec-compliant then like that might cause compatibility issues in and of itself + +SFC: Let me jump back in here. The minimum in my mind should be driven by all known use cases are like 99.999% of use cases are handled by the minimum. And ideally the minimum—the minimum should be set such that even XS running on a smart watch has no problem meeting the minimum. The minimum is not something that should be so large. It should be—it can be quite small. It’s not intended to be, like, pushing the limit of what an OS can do. + +WH: With regard to numerics we have existing, very longstanding precedents in the language: The numeric literal grammar lets you write as many digits after the decimal point as you want. However, implementations are allowed to ignore them after a while. + +SFC: Cool. I agree with that. I don’t see anyone else in the queue. So what I said earlier is what I will repeat or I will go put it in the notes as the summary. Thank you for taking the time to discuss this. + +RPR: Thank you, SFC. That was a very good summary earlier. Thank you for offering to put that in the notes. + +### Speaker's Summary of Key Points + +* There is a fair bit of support for explicitly allowing engines to throw exceptions when hitting memory limits +* Consider language that allows engines to throw exceptions not only when the memory allocator fails +* Spec-defined minimums could be appropriate in specific proposals + +### Conclusion + +Future proposals that involve unbounded operations should refer to these principles. + +## Module-declaration like proposals in other areas of the web + +Presenter: Nicolò Ribaudo (NRO) + +* [slides](https://docs.google.com/presentation/d/1DQkU3Bgqp0M9afRALa21GWNyAmyCy4A5lUhzdQe_WAs/edit?slide=id.p#slide=id.p) + +NRO: Hi. So this is also another update from what I learned last week at TPAC. There are multiple proposals in the web platform that deal with modules and introduce module-like concepts to some of the other web languages. And so this is an overview of what is happening out there. And disclaimer none of these are close to being cross-browser standard. Some of them are closer to others to shipping one browser. But that’s how things are standardized on the web. It doesn’t mean they are stable. This was maybe three years ago. We have this proposal here in this committee. That basically, allows you to define multiple modules in a single file. The use case here is to simplify bundlers, making it possible for bundlers to represent procedure semantics to bundler existing implementation, existing browsers without having to export this somehow, Stage 2 is very tentative. Important for places to use them. So you could have a bundle with a bunch of modules. You could split, put in some file and some other modules with some other file. + +NRO: There is something very similar for CSS. There is this proposal with the `@sheet` rule. That would allow you to put multiple style sheets in a file, and give them a name. In this example here we have—a single file. That by itself, defines that div has the color blue. Then defines these two nested style sheets not applied by default for just changing style. You can import this style sheet. Here is `@sheet foo`. You can then add import foo from the file. It’s different from JavaScript. Because like CSS, the outcome of a CSS file is a set of side effects, whereas for JS the outcome is exports. So the syntax looks the same as we have in JavaScript, just get foo out of a file. This is actually not giving you a reference to foo, it was giving the reference defined in there. You can also link directly to the sheet within HTML. There is some discussion on whether this would also play the stats to sheet or just what is defined in sheet foo. + +NRO: You can also import from JavaScript. Wake up the web platform `type: “css”` as a module type. So you can import something from a CSS file and you get like the default import and get an instanceof CSS sheet object. This is used mostly with web components. And the proposed behavior with the add sheet, there is to be name export from CSS files for the various subsheets. + +NRO: HTML is modules. Modules contain HTML code. The current proposal is that we have an HTML file. It has—some exports. So in this case, it exports the element with a blog post. Then you can import HTML modules. Like importing the exports. The proposal says that unless otherwise specified, all HTML modules have a default export which is basically like a whole document like a DOM document defined in an HTML file. + +NRO: There is—there is also discussion about allowing define CSS modules directly inside HTML modules. There was actually multiple sessions at the TPAC. Seems to me this proposal is being actively worked on more than the others. This gives a specifier. This specifier is a similar concept to what we call a specifier in JavaScript, except that in JavaScript imports we have a kind of specifier, specifier by itself does not module. Refers pair that point us to a module. This will be a global like absolute specifier. + +NRO: So we can define a CSS module. We can then import it in HTML templates with this shadow root mode sheets attribute that gets one or more of these global specifier names. So inside this template element we are basically importing this foo-style module. Which would apply the style to this contents of the template and this is scoped not like most CSS global for the document. You can import in JavaScript using—just put the global specifier in—in the, like, import specifier. It uses import maps under the hood. When trying to resolve the foo, it is checking the import map and somehow the previous definition installs in the import map. There were some active discussions about whether this global is a good idea or not. Whether what happens technically proposes is supported in separate files so there was discussion about what happens if you do import before \[inaudible] is loaded because this JavaScript import is just pointing to some registry in not actually loading it. But then this behaves exactly like—from the JavaScript point of view, foo behaves exactly like the existing type CSS imports. + +NRO: So this is—what we learn and I wonder if anybody has comments and opinions? Opinions are not for me, but you want to share your opinions with people. Ashley? + +ACE: Being lazy, do you know off the top of your head, you said the CSS specifiers are like an absolute global, if there are slashes, what’s the—is it first in, right last errors, do you know? + +NRO: That was again an active topic of discussion. The two options she can have, the first one wins. Or maybe—a style sheet object is not like—not a static object. You can replace its contents. There is like a `.replaceText` or something. So maybe if the—if the DOM changes there is a new style module with a specifier, it could update the contents, but there isn’t a definite answer to that. + +ACE: I don’t know if there’s overlap with the new map extension where it only grows, it can never be replaced. They should be aligned + +NRO: About the conflict also, in the—the current semantics, it’s like not that difficult of a conflict because we have one file of contents HTML. You can have a global view. If you consider the proposals for HTML modules, it is more complex because maybe you have separate HTML files that define the same specifier and it might end up conflicting with that. Not the same. + +JAD: I don’t know if you said this, but in terms of import maps, the current proposal that populates it. And it was discussed if you edit the source does it modify the source of the import map as well. And also, what happens if you change the specifier attribute and that was all kind of left up in the air. I don’t know. Our—you might want to talk about this because we were not keen on this at all. + +LVU: Yeah. I was in that session there was pushback around this and basically, I think—at a high level HTML and CSS declarative and reactive languages and this is part of their power, you change something and everything just updates. You don’t worry about the side effects. This means every feature needs to take account for the mutability. When an author sees an specifier, at the and to change the specifier attribute and now the module specifier has changed. Which brings up a lot of questions that never had to deal with JavaScript. Because JavaScript is top to bottom, usually semantics, you never have to deal with that sort of thing. Same with the contents. There’s all ways to change the content of a style element. CSS object model. Regular DOM methods to overwrite the text content. How does that work? That is easier to model because even in JavaScript you can import an object and change values of properties in that object. So that already has precedent. But changing the specifier and having the import change has no precedent whatsoever. It’s not even something that authors want to do. But to be consistent with the language, you can’t say, there’s this HTML feature that behaves differently from the entirety of the rest of the language. And I think this is something we will hit, going to keep hitting with these features if you have—if it’s both of the language and importing local resources, importing URLs you don’t have that problem because a URL can’t change under your feet. When defining local resources, then how do you deal with that? I don’t know. There’s also the question of a lot of existing web platform features that import things that have been designed to work with just URLs. ECMAScript modules were defined between URLs and specifiers from the beginning. It’s well-defined. CSS imports on the other hand, treat everything as a URL. So now you add additional syntax to make them work with specifiers. Which is not insurmountable, but another work. Then the question of what problem were these proposals solving? The need for modules in JavaScript is very clear. The need for modules within CSS is also clear. But what we need to have specifiers that become part of the same module map, or like it seems to me if you dig deep into some of the use cases, often it’s around resource loading and working around bugs and issues with how resource loading works. So maybe the solution is not? Specifiers at all. I am not sure. + +ACE: For some of these things, maybe it’s like developer experience, where we expect the developer might want to author some of these things. It seems it’s also motivated by—like optimization to get more things into, like, one HTTP request. I guess I have two questions. One, is there—what is the primary and the secondary? Is it primarily about getting more into a single HTTP request and also maybe this could be useful for some DX things or one? Another question after, but… + +NRO: So a lot of at least motivation for some of these proposals maybe Jake, you probably know better than me. If you want to reply to that + +JAD: Most is driven by declarative shadow DOM. Right now the shadow DOM for each incomplete instance of the web component is different depending on the—yeah, the attributes or whatever. But your styles tend to be the same because you have one block of style prepared for whatever content. Right now, the best you can do really is have a line style block for each instance of your web components and they will be exactly the same for each one. You can’t have a link URL style sheet pointing to a URL. The link in the body will load asynchronously. It would be a flash of unstyled content. So yeah. What we need is a way of being able to sort of reference styles from somewhere else, and then have those render block in the head. So it’s like saying, it’s a bundling thing. Those styles might be bundled for efficiency. But yes, a part of which they haven’t done is referencing that in the head to say block rendering until these are ready. + +ACE: And my second question was, I know there’s a few other things in this space around like optimization. So there’s—there was something around web bundles. I don’t know where that got it. I saw recently, one of the browsers I am not going to guess which one it was, shipped—shared compression dictionaries as a way to share resources across multiple things. I am wondering, if HTML wants HTML and CC to be embedded JavaScript, maybe—is that the right thing, or should be looking at a higher level of merging arbitrary things as opposed to each domain doing independently? I don’t know. That’s a question. + +NRO: There is some value in having this as part of the language because we have way more tools that specialize in a single language which makes it easier to adopt these things. But I don’t know if it would be the best one. + +GB: This is a really interesting discussion. And I am really glad we have folks bringing a TC39 perspective to them. And sort of a module perspective. For addressing questions, I think there is a lot of design in the addressing of modules that would be great—sorry for module declarations that would be great to have in these discussions, has—you touched on some of the topics, but there’s a lot more here. Were you able to have those kinds of discussions at TPAC? Or do you think that there are ways that we should continue to have those discussions? + +NRO: I think we should continue to have the discussions. We should figure out who to invite to the—our meetings much it’s great it figure out if the infrastructure we are building for modules is something better used by other things like ideally the way this modules are exposed to JavaScript, the same as nested to JavaScript exposed to not like a whole new thing. So we need to work more with them, to figure out how much we can align. + +GB: Yeah. I just want to reiterate there’s huge value in building some alignment where we think about the cross-use cases and thanks for bridging those discussions + +NRO: And I don’t know who “them” is. That’s also still to be figured out on my side. + +JAD: Yeah. I think “them” is a combination of what—they have the module integration and the CSS working group. Yeah. I am worried about this whole—like, the problem with CSS is that it has an object model you can change what it does and I think that seems inherently incompatible with specifying modules. Yeah. I don’t know if there’s going fob a way out of that + +NRO: Like, for example, there’s—the other proposal, feels very similar to the JavaScript one. Maybe just very much on the surface, maybe it is something more deep. I just don’t know yet. + +JAD: The difficulty with the sheet thing, in the object model you will be able to go in and change the specifier name dynamically and I don’t know how that would work. + +NRO: Yeah. I don’t know either. + +### Speaker's Summary of Key Points + +We went through an overview of different proposals developed in other web standard bodies that introduce new types of modules, or "nested files": + +* HTML imports +* inline CSS modules +* css `@sheet` rules + +We discussed the similarities and differences that they have with TC39's module declarations proposal, and how well they do or do not integrate with JS's module system. + +## Comparisons + +Presenter: Jacob Smith (JSH) + +* [proposal](https://github.com/JakobJingleheimer/proposal-comparisons) +* [slides](https://docs.google.com/presentation/d/1tu8yK57yMDdBsD4FgDX7GuRndLZfqvrukEG_AukYeJU/view) + +JSH: So I have returned from A Coruña with up dates to a set of proposals that were made there. And this was the first of what became three. This one was sort of the core one and the other two were ancillary and we decided in A Coruña that they had merit on their own so they were spun off immediately. So this is the core of the first one. So the gist of what this proposal is, is A different from B. If so, how? + +JSH: Changes from things that were presented in Spain, there’s a new co-champion, RGN. And we’ve settled on just one comparison function. Name to be bikeshed later. Instead of trying to figure out the—like a search and expect type stuff, that’s sort of a different thing. The comparison can have two kinds of outputs: either `true` or “deviations”, depending on the mode that you are working in. Or just `undefined` on success there are no differences. + +JSH: Deviations would be an iterator, keyed by the path to the deviating leaf, and its value is kind of the "expected" / "actual" and then, what we are calling "reason". More on that in a second. Leafs are compared with `SameValuesZero`. And each branch segment is checked for exact sameness, to avoid unnecessary drilling. It’s not—compare is not (yet) a replacement for `assert` or `expect`. They could use it under the hood and surface that information in whichever way they want. We’ve spoken to authors of userland libraries and they have voiced eagerness to use this, it does a lot of the work they don’t care to do. We have broken out `pretty` as a problem for later, potentially, reduced after some of ancillary proposals land, and the reason for that is because this is useful without it and unblocks this proposal from a daisy-chain of those other two proposals. + +JSH: So what this would look like in some quick samples here, is sort of what you see before you. We have added `mode` here in case what our real hope is, is not feasible. So if it is sufficiently performant, then we would probably collapse the number of modes. So mode `first` is—it gives you the first deviation. And then mode `all` would give you all of the deviations. And then, under `reasons`, it would provide a dictionary detailing the problems or like the difference—the causes of the differences. The—yeah the main ones are listed here. And—so we do—as I mentioned, have some open questions about mode, if that’s even necessary at all. If it’s optimizable enough, maybe we drop `all`. Custom handling for leaf comparisons, "I do care about enumerability". "I care about things that were not discovered in the base dictionary". "How do I handle that?" And is further—further customized, would it be needed now? Or if that is a "tomorrow problem"? + +JSH: So some other things that came up in those discussions are things like matchers. Commonly, in—in writing something, you might say, like this thing is going to be some kind of number. I don’t care what it is. Just as long it is a number. That’s a related problem that we’re aware of, but we think is out of scope for this. And what it calls this, comparisons versus differences, something like that. That is the TLDR for the update to the proposal and asking for Stage 1. + +RGN: All right. First thing, just to set the tone for the following discussion: I would encourage everyone to not get too hung up on specific example APIs shown in the slides. It’s okay to discuss them, but remember and do keep in mind that we are seeking Stage 1, not Stage 2 or higher. + +JHD: Yeah. I don’t understand why you need the first mode at all, when you can just `.take(1)` on the iterator? + +JSH: Sorry. Can you repeat it? + +JHD: Yeah. If you just delete the middle snippet and you use the all mode only, you only want one, do not take one and close the iterator, take the first item and presumably, I am assuming obviously this could be checked, that is sufficiently optimizable to make that fast. That’s—to me, that’s the reason to make it an iterator, to choose to only take one. If you want all of them, it would just be a big array. + +JSH: I think in previous discussions, we had talked about some under the hood cost that you might pay or something. I don’t remember what that was. If just—grabbing the first one does address those—those performance issues, then yeah. + +JHD: Yeah. If to to N items is prohibited for some reason, then you just wait until the second item is requested before you start computing the rest of them. And that works fine. I have no idea what the performance profile is. Stuff would be, but, you know, if there is a fast threshold—the threshold where fast turns to slow, you just do the slow work at that point when they have taken that item. That’s my intuition anyway. + +OFR: I haven’t fully thought about it, but I was wondering what is the intended usage? Is it—expect most of them will come through anyway, and the second thing, because that might depend a bit. So dropping `first`, might have a bit—could have an effect on the implementation, it could be more complicated because you potentially have to keep around a bit of state to figure out where you left the last time. I guess, it also depends if we expect this to happen often or the `fast` case, we get back `true`. + +JHD: My personal use cases of this are three fold. One would use the one on the left, for a predicate. One of those would actually use the one in the middle, so I can give some sort of explanation for why they're not equal/similar/whatever. And anything that is doing inspection or logging use the one on the right. I would like them as fast as possible, of course, and if we need first to exist, so be it. Unless there’s evidence we need it, it seems like we don’t. + +CDA: All right. I just want to note that we have quite a long queue and possibly we're dipping into later stage concerns quite a bit. This is just a proposal going for Stage 1 at this time. So just please be mindful of that and try to be somewhat brief in your comments. Ruben? + +RBR: When it comes to the all case iterator in general, I share the concerns from OFR that keeping around the state is actually something that might be difficult, also the object might be mutated in between. I believe if we return all, then it should be kind of like—I don’t know. Like a set or array. I don’t care. + +LVU: I would not debate use cases for this. My worry is, is this the right level of specificity? It seems to me this might be a special case of a broader problem around recursive traversal of deep structures. I mean if we think about the flat case, compared to arrays, doing diffing of two arrays, we iterate over one and look up values on the other array. So how does that translate to deeper recursive structures? Most people have written helpers for deep equals many times or just walking structures. Or merging structure. Or effectively, mapping. Like all of the concepts we already have for regular iterators, it kind of translates to deeper traversal. And I wonder if something like that could solve this plus a lot more problems rather than something specific to comparisons and diffing. Comparison and diffing, this is more like diffing rather than comparison. Like, in terms of naming. Yeah. That’s it. + +MAH: So I mean, just a general concern. Like, worry about—it really depends on the shape of the API, but I want to find some shape of API that doesn’t encourage users to build equality predicates. An equality can only be reliable if data is immutable. So yeah. I just general worry about people abusing any comparison mechanism + +JHD: I don’t think anyone holds an expectation that content-based equality persists when things are mutable. But in practice, many objects that are being compared aren’t mutated, so it’s fine. + +MAH: Yes. I understand. I—I just want to find an API shape that steers towards users not doing that. I know I can’t prevent it. + +CDA: Please use the queue. CHU? + +CHU: So my question would be, what are deviations useful for? I get it, they could be used for nice error messages like for an `expect()` style testing. But the way, I remember when you presented this in Spain, the proposal was about equality. And not about deviations—so the major use case was whether something is deeply equal or not. Not about—if objects are not equal, how they are not equal. Because I think that—with paying respect to currently asked stage advancement, the API is not clear and this opens up a lot of other problems and questions. Like, for example, with nested objects, having the same key names, deeply nested within, if I would have deviated structure, I would—I don’t know, reconstruct it. So I am asking what kind of problem do you want to solve? My impression was that it was strictly about equality and now they are also deviations, so what is the focus now? + +JSH: Kind of still yes. It does tell you whether something is the same thing. And as you said, if it’s not the same, then how. That’s what the reasons are. It tells you the bits that are not the same + +CHU: We talked about the assertion use case. For assertions, it's sufficient, when objects are deeply equal or not. So why now the how part, the deviations? + +RBR: Before assertions, clarifying, part to that, is actually that normally want to print something to the user in one way or the other and the information about the traversal— + +CHU: That’s not the initial problem space in Spain, at least not, how I remember it. Back then we were talking about how to implement equality, I see what you have changed, using a function now. I can relate to that. But I—I would rather have a proper description of what the deviations are and the larger things that they are used for. I know what you can use them for, but there are already various implementations out there. And I don’t know so that’s—what would that be used for, besides that? + +CDA: Again, please be mindful and use the queue. We have a reply from JHD. + +JHD: Assertions—meaning a condition that throws if it’s not met—is not by any means the only way that people check things or test things, et cetera. There are many test frameworks that continue running the rest of the tests even when a test fails and you need to print something there. And many of those tests outputs have a headline with some extra detail and the first failure is a great thing to put as the headline and the extra detail would contain them all, for example + +MF: This is not a comment on, you know, whether I feel this proposal is valuable or not, but I don’t agree with CHU’s assertions. As far as I remember, the major motivating factor was its use in presenting human-readable descriptions of a failure when an assertion failed. + +JSH: That is correct. + +CDA: All right. JHD is on the queue with this clearly an important problem area to explore + 1 for Stage + +WH: I still don’t understand the goal of including this in the language. This seems like it would be perfect for a userland framework. There are so many different ways you can compare things. What do you do when you have recursive structures and infinitely recursive things? Getters and setters? Run the getter or see if it’s the same getter function? So I just don’t see why this should be considered for the language, rather than remain as a userland testing framework because of its many different options—such a large API surface. + +JSH: So for what we have seen, the differences are rather small, most of them do the same things. And as to why make it part of the language, one of the reasons to cite is all of our neighbors have this. So quite a lot of people believe that this should be core to a language itself. And it’s kind of a bit strange we don’t have something like this. In terms of why native userland this is related to some of the extra access that native can subsequently provide, that user-land can’t really. For instance, like Node is a special case because we have more access than, say, like in a browser. And so we’re able to leverage that. But you can’t really expose that to user-land because then they could like naughty things + +WH: I don’t understand the answer. + +JSH: In its entirety or— + +WH: I don’t understand what it does that you can’t do in userland. + +JSH: For—okay. For instance, are you familiar with the sibling proposals? + +WH: No. + +JSH: Okay. So one of the things we had talked about in Spain was like for instance when you have a proxy: that can’t be detectable in user-land, but that could be super helpful to a user trying to debug. Information we want to surface under particular circumstances, there are those other proposals that sort of deal with the complexities of that. And this feeds into that. So this provides something that then you can subsequently work together with those things. But if this is not there, then you basically have no foundation. + +WH: Okay. I still don’t understand the answer. But are you saying that this will expose proxies to general scripts? + +JSH: You mean to user-land + +WH: This was in the context of things which users can’t do otherwise? + +JSH: Do you mean, would we expose whether to—a user observable way, would expose to a proxy? + +WH: Yes + +JSH: No. Explicitly not. + +CDA: Okay. We have a reply from Michael + +MF: Yeah. I pretty much share the same sentiment of WH. I do think that this is a useful thing. But I don’t think it’s very common. There’s a small number of libraries that need to do this. And they can exist as libraries. I don’t think it can really do anything that’s all that special, as we were discussing. The difference is that it can show, and should be limited to the difference already, given that we don’t want this introducing new capabilities of piercing proxies or describing internal slots that differ. It would be great if it could additionally describe those things to the end-user, but that can’t go through the language as a string as it would basically expose that information. It doesn’t actually become special. I don’t think it’s either common enough or special enough to warrant its inclusion in the standard library + +CDA: Rubin + +RBR: I also agree that this does not add anything that user-land cannot reproduce. Absolutely. And it actually exists, I am the main `node:assert` maintainer, and in this case, it’s an opinionated algorithm for the comparison. Every comparison algorithm and JavaScript is an opinionated algorithm. As such, the main difference or difficulty that we have is actually uniformity across all the comparisons. I believe having that as a standard is actually a good idea. Because then we don’t have to bikeshed about it anymore. It’s not a discussion, "why is this working with my one comparison algorithm, but I have the expectation for the other one". That’s something I commonly see when comparing any of the libraries and often bug reports. It’s an opinionated implementation. + +CDA: We have a reply from JAD: + 1. This seems like a “dev dependency.” And not needed in the standard library. Mathieu? + +MAH: Yeah. I am wondering, do all places that do these deep comparisons agree on what is something that is equal? Because if they can’t agree, how can we agree? And find something that everybody agrees with. + +CDA: A reply from MF + +MF: Yeah. Relatedly, I would be more convinced if I saw the coordination naturally happening among the libraries. And that could come to us, you know, I don’t think we should be guiding that process there. What is preventing libraries from coordinating. + +JSH: You are saying that if all of the libraries did subsequently agree, then a proposal should move forward? Or we just leave them at their agreement, and move on? + +MF: Probably the latter. But I don’t think that we should be guiding that. That coordination— + +CDA: We have a reply from RGN + +RGN: This is not attempting to coordinate. This coordination isn’t even required. You know, any difference that isn’t relevant for a particular application can just be skipped over in the iteration results. + +RBR: So one very big reason for the algorithms deviating is performance. In node I use some functionalities to make algorithms faster that are not exposed that I want to add to the language. But that’s a different story. + +RBR: And in that case, it’s something where a lot of the comparisons are not done because they are seen as "okay, like, it’s good enough" as a comparison. And otherwise, I would slow down the comparison. That is something why I believe putting in the language is beneficial. A written in the engine itself would be a faster way to compare these. + +CDA: Okay. We are starting to get low on time. There’s a reply from Keith. And now, a reply from Daniel. I would really like to get to EAO’s topic. KM be brief + +KM: Sure. I guess on that point, an open thing it’s good to know we standardize. They won’t keep the opportunities and it doesn’t have the behavior I want. Yeah. + +CDA: DRR? + +DRR: I think the argument around performance is almost subtle because being able to optimize implementation means you have a different ordering and how you produce results. And in some cases you may decide to do something different. Whereas, having a default implementation in the standard means you can’t change that as easily. I would urge caution and point that out. That’s it + +CDA: All right. We have 5 minutes EAO. + +EAO: So yes. I don’t understand yet what is the clear expression of the problem or need that we are asked to advance possibly to Stage 1 on this. The previous conversation just now, was really informative and sounded really interesting and had potential. But I would like to hear from the champions what is the explicit problem statement or something like that that we are being asked about here. My understanding kind of reading between the lines, which I should not be doing for a Stage 1 proposal, is that it something like, it would be useful to standardization a representation of how object the different from each other. I don’t know if that’s the case. Please tell me the problem we are trying to solve here. + +JSH: Yes. Like your summary, I think it is—how do I go back? I think that aligns pretty well. + +CDA: The slides—different from B and if so, how. + +JSH: Yeah. I think that aligns pretty well with what EAO just said. Reading between the lines. But apparently, not. So I think what EAO said is indeed what we are going for. + +JSH: Anything else to add, RGN? + +RGN: It is a common need to present a description in varying levels of detail for how one structure differs from another. + +CDA: Do we have support for Stage 1 for comparisons? JHD was on the queue earlier with support for Stage 1. + +CDA: Do we have any other voices of support for Stage 1? + +CDA: We tend to like to see more than one voice of support. + +RKG: I don’t block, but like, they asked for a problem statement, which should include _why_ you want this. You haven’t answered that, so… This seems insufficient as a justification for Stage 1. + +CDA: Like, do we have any—call for any—any objections to Stage 1? So some folks are unconvinced, but if we don’t have somebody else to support + +JHD: I get that. Stage 1, we will keep talking about it. The API is a Stage 2 concern and potentially it could not be on the slides and it would have been a similar ask. The reason why I want this is, I maintain multiple packages that are deep-equal comparison predicates and one of them that tries to give an English string describes why the things aren’t sameish for some value of that. And that is not just a dev dependency. I am not aware of anything that is even things that are primarily dev dependency, that don’t run in production somewhere, and that’s things definitely want to run in production. I mentioned two packages on matrix, 55 million downloads a week that this proposal would make obsolete. Yeah. I want this functionality in the language. I don’t care about my packages downloads. I want the clearly heavily used use cases to be addressed + +CDA: Thank you, JHD. Last call. We have less than—I see responses in the queue. I had to clear it earlier. We don’t have time. And JSH is not around tomorrow. We cannot do a continuation of this. So with JHD’s comment, did that convince anyone to support Stage 1 + +JSL: I will support it. With the caveat that the repo does need to have a clearer problem statement with the why along the lines you just explained. + +CDA: Okay. So JHD and JSL support Stage 1. Did not hear any objections. Some healthy skepticism. + +MF: Yes. I am—I am not convinced that this is a problem that is good use of the committee time at the moment. It doesn’t mean it will not be in the future. I think it can come back for sure. Stage 0 is fine to continue talking about it. I just don’t think it’s ready for Stage 1 yet. + +CDA: Okay. Comparisons remain at Stage 0. + +### Speaker's Summary of Key Points + +* There is a need to clarify the problem statement +* There is also some skepticism about this functionality being included in the standard library +* Some specific **Stage 2** concerns included: + * What constitutes “difference” with respect to cyclic structures/accessors/post-hoc mutation? + * To what extent such a built-in API can foster performance + +### Conclusion + +* Comparisons remains at Stage 0 diff --git a/meetings/2025-11/november-20.md b/meetings/2025-11/november-20.md new file mode 100644 index 0000000..6faf074 --- /dev/null +++ b/meetings/2025-11/november-20.md @@ -0,0 +1,1396 @@ +# 111th TC39 Meeting + +Day Three—20 November 2025 + +**Attendees:** + +| Name | Abbreviation | Organization | +|--------------------|--------------|--------------------| +| Dmitry Makhnev | DJM | JetBrains | +| Jesse Alama | JMN | Igalia | +| Waldemar Horwat | WH | Invited Expert | +| Ashley Claymore | ACE | Bloomberg | +| Eemeli Aro | EAO | Mozilla | +| Ron Buckton | RBN | F5 | +| Devin Rousso | DRO | Invited Expert | +| Daniel Rosenwasser | DRR | Microsoft | +| Samina Husain | SHN | Ecma | +| Joshua Goldberg | JKG | Invited Expert | +| Ross Kirsling | RKG | Sony | +| Richard Gibson | RGN | Agoric | +| Lea Verou | LVU | OpenJS | +| Christian Ulbrich | CHU | Zalari | +| Jonathan Kuperman | JKP | Bloomberg | +| Shane F Carr | SFC | Google | +| Daniel Minor | DLM | Mozilla | +| Matthew Gaudet | MAG | Mozilla | +| Keith Miller | KM | Apple | +| Yusuke Suzuki | YSZ | Apple | +| Istvan Sebestyen | IS | Ecma | +| James Snell | JSL | Cloudflare | +| Andreu Botella | ABO | Igalia | +| Aki Braun | AKI | Ecma International | +| Ben Allen | BAN | Igalia | +| Chris de Almeida | CDA | IBM | +| Chip Morningstar | CM | Consensys | +| Chengzhong Wu | CZW | Bloomberg | +| Gus Caplan | GCL | Deno | +| Jake Archibald | JAD | Mozilla | +| Jordan Harband | JHD | Socket | +| Justin Ridgewell | JRL | Google | +| Kevin Gibbons | KG | F5 | +| Mathieu Hofman | MAH | Agoric | +| Michael Ficarra | MF | F5 | +| Mark S. Miller | MM | Agoric | +| Nicolò Ribaudo | NRO | Igalia | +| Olivier Flückiger | OFR | Google | +| Ruben Bridgewater | RBR | Invited Expert | +| Rob Palmer | RPR | Bloomberg | +| Stephen Hicks | SHS | Google | + +## Intl Era Monthcode for Stage 3 + +Presenter: Ben Allen (BAN) + +* [proposal](https://github.com/tc39/proposal-intl-era-monthcode/) +* [slides](https://notes.igalia.com/p/Lne8U2E5K#/) + +BAN: Fantastic. Cool. I just want to start by saying that we had originally planned to ask for Stage 3 at in meeting as a result of the need for a couple of normative changes, we’re going to hold off until January. I anticipate this might not take anywhere near the requested timebox, since we won’t be asking for Stage 3. But without further ado, I’m going to share my screen. + +BAN: All right, so, yeah, the first thing the notice is we have crossed often the request for Stage 3. I’m going to give you an update on where we’re at. We are in fact perilously close the Stage 3, but as I said, we’ve got a couple of late break normative changes that made us decide we should hold off until the next meeting for that. But the premise behind Intl era month code is Temporal supports a number of non-iso-8601 calendars, and previously the calendars has been defined out of EMCAScript, so in practice, in ECMAScript it's a lot of implementation defined behavior in practice. It’s at the level of IGR or—or/IC4X. But Temporal adds a lot of calendar arithmetic capability, so adding and subtracting dates and so forth. And all don’t want to specify the arithmetic for every calendar, just because it can get complicated, especially in the case of calendars, like the Chinese calendar that use lunar solar months or the Japanese regular calendars or there’s orthodox calendars that have intercalendar months, so 12 months that are 30 days and then five days that are in their own 13th month. So we don’t want to explicitly specify the arithmetic for every calendar this is handled in practice at another level. We don’t want guard rails around implementation behavior in order to avoid divergence, and this shows up in, for example, the way the leap months work in Hebrew calendar differs from how they work in other calendars with eight months, so den quay or the Chinese calendar. Long story short, there’s a leap month that isn’t inserted in the Hebrew calendar every year called Adar 1. This—in years with leap months, there’s two months named Adar, and the first one is considered leap month, not the second one. Which means that if you’re doing calendar arithmetic based on those months, you’ll land somewhere differently from how other calendars involve leap months. So we want to implementation divergence for calendar specific details, and again, we don’t want to specify the arithmetic for every calendar since that’s typically makes sense to have that implementation defined at the EMCAScript level. + +BAN: Okay, so as I was saying, our goal is to not oversea spes fie behavior for matters on which ECMAScript is not the correct authority, and within that constraint, minimize opportunities for implementation divergence, and our additions to ECMA404, we have explicit description of the calendars which we support, which removes potential ambiguities. There’s a lot of ambiguities related to sort of historically contingent effects, for example, the calendar that is labeled Islamic, just there’s a lot of different Islamic calendars that we support. The one that’s—it’s been labeled just plain Islamic was—didn’t actually reflect the reality of any particular Islamic calendar, so we’re excluding that one. We’ve got our list of valid error codes and aliases as standardized in CLDR, so this specific Japanese eras we’re supporting, the names of eras in the orthodox Coptic calendars and so forth. Valid ranges of era years for each calendar. One thing that I believe came up last meet that we added last—meeting or the meeting before is an expanded range of selection of reference years. Basically any year in any calendar because of how Temporal represents dates, it has to have some date in ISO 8601 that it refers to. So this is fairly simple in ISO 8601, and Gregorian calendars, so you can’t just use 1970, for example, you can’t use the Unix epoch as the reference years because, well, there was no February 29th in that year. So in the Gregorian-like calendars, well, we can just use 1972 as the reference year because every day that appeared in those calendars exists in 1972 because there was a leap day there. Well, for example, in the Chinese calendars, there are a number of different leap months that can occur. And those leap months could have a leap day inside them. And some of the possible leap months and leap days within leap months are incredibly rare. So winter months, to find the last time that those months occurred, you have to go back to in some cases the 1400s. Well, okay, the reason why we ended up expanding the range for selection of reference years to 2035 is that there is a leap month that—in Chinese calendar that will be coming up in 2035 that hasn’t come up in several hundred years. We’re considering the sort of valid range for the calendars is going to go back to 1900, just because it’s difficult to pin down exactly how to represent—there’s disagreements on—there’s disagreements about how those calendars worked before the year 1900. So the way we resolved the problem of, okay, there’s this leap month that hasn’t occurred for about 50 0 years but will occur in 2023 is we expanded the range of selection for reference years to 2035. That way we can actually represent those months, the days within those months correctly. Also, we’ve—the last bullet point here, we’ve got the list of the epoch years per calendar in Temporal `PlainDate.prototype.year`. We also have specifics on which calendars supports week numbers, which was left in implementation to find, in terms of week numbers, everything that’s not ISO-8601 doesn’t use week numbers. + +BAN: We’ve also added constraining behavior when adding years in lunar solar adds, an algorithm for determining the difference between two dates, which can get complicated when you’re considering years with leap months and leap days within those leap months and we have special handling of the CLDR historical calendar IDs with an implementation defined algorithm. Okay, so the reason why we’re not asking for Stage 3 this time is we have two small normative changes that I’ll be asking for consensus on that are fairly late breaking. One of them is so the next CLDR is going to be removing several era aliases and there are two error aliases in the Ethiopian calendar `incar` and `mundi`, those we'll be removing to match CLDR’s behavior [PR](https://github.com/tc39/proposal-intl-era-monthcode/pull/72). And likewise, we’ll remove several error aliases for the republic of China calendar, and this is syncing is what CLDR is doing. The second one, and actually I’ve got them loaded up. The change is pretty straightforward. We have a table of what the sort of alias are, and we’re simply removing the aliases that aren’t going to be in CLDR anymore. + +BAN: And this is a bigger [PR](https://github.com/tc39/proposal-intl-era-monthcode/pull/89). Previously, we had a spurious check for out of range error years. These actually have always been permitted and they’re necessary for the Japanese imperial calendar. So if the behavior is such that if you specify an out of range year, it will—I believe, I will look at the spec in a second, but roll over to the previous one. Correct me if I’m wrong on that, people. So, yeah, we had a spurious check for out of range. It turns out we actually have to—that concept doesn’t make sense in this particular context. And this shows up for handling the imperial regnal calendar. + +BAN: Okay, just to say our only remaining last step from September was the creation of test262 for this proposal. It’s actually pretty nice because we’ve extended—there’s a lot of, how do I put it? We’ve taken essentially the majority of tests or all of the tests that previously existed for the ISO8601 calendar and for all the calendars which those tests make sense, we’ve added them for those calendars. Yeah, in the last month or so, we’ve done a whole ton of test and I just want two thank PFC and JMN from Igalia for putting in a ton of work on that. Okay, thank you. But, so, the thing I’d like to ask for is consensus on these two normative changes. One while we mad to introduce a spurious check for out of range, and two, we’re aligning ourselves with CLDR, we’re removing era aliases that don’t currently exist. + +DLM: Before you ask for consensus, there’s a small queue. Shane? + +SFC: Yeah, hi, thanks, Ben, and thanks for all the work you’ve done doing on this, especially in test262. There’s a number of open issues that are in the Stage 3 milestone that I wanted to get your thoughts on to see if you think that these are also going to be in scope for work that we’re going to do before we get to Stage 3. The first is a new issue—these are not in any particular order, but the first is a new issue that just got raised a couple of days ago based on the comprehensive testing, [issue 96](https://github.com/tc39/proposal-intl-era-monthcode/issues/96), the title is spec issue in NonISODateSurpasses. I invented this issue and it appears to be related to PR69, which this committee approved PR69 under the understanding it was an editorial change, and it turns out this was a case that where the behavior changed slightly across PR69, meaning that the resulting behavior that’s currently in the specification is not the behavior that this committee approved for Stage 2.7. Meaning that it should be presented to committee as a normative change if you want to proceed with that behavior. It seems to suggest based on your presentation on slide, I think it was slide 6, you specifically said addition ECMA402 when adding years in lunar solar calendars, which is the topic of issue number 96. Does this imply that you intend to propose that the behavior that is currently in the repository, which is not the Stage 2.7 behavior, is the behavior that we want to approve for Stage 3, or is this something that you think that we should bring back to committee again, and basically what’s your plan on moving forward with that issue? + +BAN: That’s a good question. I have been out sick for the last two days, so I haven’t been participating in the discussion on this. Yeah, if PFC were here, I would defer to him on this. + +SFC: That’s fine. I think I’ll move on to the next queue item. [Issue 57](https://github.com/tc39/proposal-intl-era-monthcode/issues/57), yeah, so this is another issue that my colleague Manish opened a little while ago, which is basically doing the same thing to challenge the resolve fields as we did the calendar date add and calendar date, and make the prose into algorithmic specification steps. And I haven’t seen any recent activity on this issue. Do you believe that this issue is, like—is this in your plan to address before we get to Stage 3, or do you feel that this is a change that you’d rather be addressing later? And I know probably your response the that, BAN, is what do you think, SFC? But I wanted to get your, like—I wanted to get a sense of what you see as the, like, person who has been spending the most time on this proposal. Is this on your radar? + +BAN: It is. Let me think. My understanding is, and this understanding might be wrong, is that this would ultimately be an editorial change. Is that correct? + +SFC: Well, it’s an editorial change except that given the experience we had with PR69, it’s probably best to have it hammered out, because, like, it’s an editorial change but it’s a difficult editorial change that could raise other issues. + +BAN: Yeah, this is a difficult one. + +SFC: So I just wanted to throw that out there. If you need more time to think about, that that’s fine. I can go to the next agenda item. This one’s a little more specific and concrete. [Issue 29](https://github.com/tc39/proposal-intl-era-monthcode/issues/29), which is the Hijri calendars one, we reached a kind of complex consensus in TG2 about how to deal with the Hijri calendars and I think an be a more lease found issues where it also—it interacts not only with Temporal and Intl datetime format, but also Intl display names, and it’s a fairly intricate change. I think the change ally is going to end up being maybe not actually that many lines of spec text, but it’s intricate change in the sense that it touches many different components, and this is definitely something where I want to make sure engines agree and are conformant. I wonder, what’s the progress on issue 29? I think, like, on this slide, slide 6, you have a bullet point that says special handling for CLDR Hijri calendar IDs. Does that mean this issue is resolved? And what are your plans on making sure the issue is fully resolved and closing the issue? + +BAN: All right, this is the new fallback logic for this. + +SFC: I didn't mean to put you on the spot for these. I’m sorry. My intent was more just to clarify, like, are—do we feel that we’re at a state where issues like—or issue number 29 is resolved, or is there still work to do on issue 29? + +BAN: I believe it’s resolved. I have to admit, I haven’t looked at it in at least a month. + +SFC: All right. I think just for Stage 3 readiness, which it sounds like we’re keeping that for January for other reasons, but I think since we are buying ourselves some time, it would be good that when we come back for Stage 3, then we have this issue—like, we have it resolved to make sure that all the ducks are in a line to make sure that this is done. + +SFC: I have another one. [Issue 60](https://github.com/tc39/proposal-intl-era-monthcode/issues/60), which is to provide guidance, so you also had this in your presentation. Slide, which one was this? I think it was on slide 4. I think you mentioned on slide 4, expanded range for selection of reference years. So the expanded range of selection for reference years covers, like, all of the major leap months in the Chinese calendar, but there’s still a few exceptions, and Manish noted those in this issue, this issue was number 60, issue 60. There’s still a few examples of Chinese calendar dates that are not covered by the reference year algorithm. And then there’s four choices on how to proceed here. And it’s not clear that we have—the currently what’s in the specifications basically option 1, which is implementation defined, so if the user requests a—if the user requests a month day that is not covered by the reference year algorithm, then it’s implementation defined behavior about what happens with that. This is something where I’m interested in the feedback from other committee members who implemented Temporal or are working on implementing Temporal, whether or not we’re okay with that being implementation defined or whether we want to consider hardening the specification around that? If you’re not prepared to answer that question now, that’s fine, but I think this is feedback we should definitely get and land before we get to Stage 3. + +BAN: I was working on the assumption on that one that it would remain implementation defined. But, yes, I’ll reach out to other committee members related to that, and if anyone would like to jump in, that would be great. + +SFC: Cool, cool. There’s a couple other issues that amber opens, which are also I believe worth looking at. I think one of them looks like a spec bug. [Issue 87](https://github.com/tc39/proposal-intl-era-monthcode/issues/87) looks like a spec bug. [Issue 90](https://github.com/tc39/proposal-intl-era-monthcode/issues/90) is almost duplicate of the aforementioned issue about rewriting calendar resolve fields. I think it would be resolved if we did the calendar resolve fields refactoring. [Issue 91](https://github.com/tc39/proposal-intl-era-monthcode/issues/91) is very closely related to the Islamic calendar, to the Hijri calendar fallback algorithm. [Issue 92](https://github.com/tc39/proposal-intl-era-monthcode/issues/92) looks like an editorial issue. There’s one more editorial issue in [93](https://github.com/tc39/proposal-intl-era-monthcode/issues/93). [Issue 94](https://github.com/tc39/proposal-intl-era-monthcode/issues/94) is an interesting one, which is actually a question that we should also get feedback from implementers on. Issue 94 is the question of whether or not implementations are per it mitted to ship calendars that are not in the list of available calendars. Current three specification appears to allow that. And I think that we should be more clear on that, and use the language, for example, that is found on the numbering systems table in ECMA402 in order to make sure that the available calendars are extensible, unless the committee feels that we actually don’t want to allow that. Because this could open up cases where, for example, some browser, like tries to implement Islamic RGSA and others don’t and that creates an incompatibility, so maybe we don’t want that list to be extended. I believe that’s the last issue that is still open. I wanted to sort of highlight those, and it would be good to get our ducks in a line for Stage 3. Some of the issues are old and some of them are very, very new. It’s not really any—it’s fine, it’s just, you know, especially since we’re buying ourselves time, I think actually the fact that you put this on the agenda for Stage 3 actually made people open these issues because they looked at it more closely and found these issues, so I think given that we’re buying some time, I would like to make sure that these issues are resolved. + +BAN: I can give some feedback on the GitHub issues themselves since we do have the extra time. My understanding was that, and this is going just based on tests we’ve done recently. My understanding is issue 91, that what display names accepts depends on locale data. It essentially could be left implementation defined. So display names is in fact, like, allowed to return them. With regard to, which ones have I been looking at recently? Oh, yeah, with regards to whether or not additional calendars can be supported, that’s another one. Just in general that should be implementation defined, and that’s my understand, and I will be discussing with other committee members on that one. + +DLM: Sorry, guys, just maybe we should move to the normative changes, and your consensus for those, since there’s a possibility we’ll run out of time. And I think this conversation, while valuable, is mostly between the two of you, so it might be best to take it to TG2. + +SFC: I was just about to say that same thing. I made my comment longer than I normally would in plenary because we have a big timebox, but I agree TG2 is a better venue for these in the weeds questions. + +DLM: Ben, would you like to ask for consensus for the normative changes? Maybe you should bring them back up to remind us. It’s been a while since we've seen them. + +BAN: Let me reshare my screen. Okay. So the first normative change (72) is simply to align with CLDR. The era at least is that we previously allowed for, and CLDR is no longer going to be including, and we’re going to remove from the relevant tables those aliases for ARS. And again, this is simply to align with CLDR. + +BAN: And the second is required to make the—well, it’s particularly required to make the Japanese imperial calendar work correctly. We’d had checks for whether or not in era year is out of range. That—it’s not necessary and does not make sense, especially in the context of the Japanese imperial regnal calendar. + +DLM: You have support on the queue from SFC and CDA. Shane, did you want to speak? + +SFC: Yeah, I support both of these changes. I can give a little more context if anyone has questions, but that’s not really necessary, I suppose. I support them. + +DLM: Yeah, I also support these normative changes. + +### Speaker's Summary of Key Points + +* Consensus reached on two normative changes + * Align with CLDR on era alias + * Remove inappropriate out-of-bounds checks for eras that had previously broken the Japanese Imperial calendar + +### Conclusion + +* Review open issues and return to next plenary + +## Amount Stage 1 update + +Presenter: Ben Allen (BAN) + +* [proposal](https://github.com/tc39/proposal-amount) +* [slides](https://notes.igalia.com/p/tc39-november-2025-amount) + +BAN: Okay, so this is our Stage 1 update for amount. There’s been a significant amount of conversation about Amount specifically on our numerics channel. And in the numerics meetings I’ll refer to that later on in this presentation. But so for reminder for people who haven’t been thinking about amount for a few months, so our idea more an amount is—was going to be a mathematical value tagged with an optional end unit precision. So, yeah, and intentionally with a very, very small API. So not something working with arithmetic. Simply you can tag an amount with a different unit and you can update the precision. + +BAN: (Slide 3) So since last time, amount has been a very frequent topic of conversation. in the biweekly TC39 JS numerics call, if you like thinking about numbers in JavaScript, these combine. And in breakout session on Monday, I was out sick unfortunately and wasn’t able to attend that, so I’ll defer to colleagues on details here. But in the breakout session Monday, there was—we spent a lot of time talking about how amount is both an Intl thing as well as not an Intl thing. It’s kind of a numeric thing, but it opportunity have arithmetic, so what’s up with that? + +BAN: (Slide 4) Okay, so historic—the sort of history of this is one year ago, actually, in Tokyo, amount, which was then named Measure, got to Stage 1. And at that time, Amount, then named Measure, supported unit conversion. So the idea was this was something that was initially split off of this smart units proposal. Since it was an press observation of the proposal when the smart units proposal related to localizing measurements based on the specific rules for each locale for localizing that type of measurement. So what does that mean? It means that there’s some measurements that in some locales most notably, but not exclusively, locales that use a mixture of the imperial system and the metric system. There’s some locales where if you’re measuring certain types of things, you’ll use a different measurement system. And the sort of most straightforward one is in a lot of the commonwealth countries, Canada is sort of like the leading example for this because Canada kind of has the most complex mixture of measurement systems. If you’re, for example, measuring the height of a person, you’re not going to do that in centimeters or meters, even though in those locales, typically you do those measurements using the metric system. If you’re measuring the height of a person, you’re going to give it in feet and inches. So smart unit proposal was to improve—the idea was to improve localization by accounting for that, being able to tag something as a person’s height and then say, ah, okay, if we’re in Canada, we want to format this as feet and inches. Okay, doing that requires—would require a lot of arithmetic. And we realized, hey, a lot of the stuff that’s necessary to implement this involves things that kind of transcend internationalization, that transcend 402 and could be very useful in the context of 262. Long story short, at that time, amount—I’m going to start saying, at that time, amount definitely supported unit conversion. So doing arithmetic with our numbers. Okay. In response to feedback, we ended up, and this is when it was renamed from Amount to Measure, and the result of response to feedback, we paired the proposal way down and renamed it and focused on handling digit strings and precision and breaking off units and not—specifically not including anything arithmetic on numbers. And we’re building on EAO’s trailing zero proposal too with regards to precision. + +BAN: (Slide 5) Okay, so relatedly, there’s moment ebb tunnel around the `` HTML proposal. This is—including last week at TPAC, in which unit conversion is a crucial part. There’s this thing going on at the level of at HTML that sort of reflects the state of the original proposal. And we’re kind of thinking of returning to our route, and maybe we should do some unit conversion. + +BAN: (Slide 6) So what would we like to be able to do? We would like to convert an amount with a unit to another amount, give it a new unit. This raises a lot of questions that we talked about a fair amount literally a year ago in literally the same place. What units make sense to incorporate? Obviously we don’t want to depend on unstable data. So initial focus could be on the SI units, so meter, gram, and so forth. And then adding some additional units, for example, those relevant for CSS. I’ll skip over that. + +BAN: (Slide 7) And this, again, returns to the original motivation for if smart units proposal. You can also include other standardized conversions, so meters to feet or meters to feet and inches in the context of person heights. This could be included following CLDR, which has fairly extensive data on units and unit conversion. And it follows an IST, which in turn follows the international bureau of weights and measures. I love anything that involves thinking through, like, four different layers of standards organizations. So there’s a lot of prior art on this. I started working on this in the context of internationalization where the CLDR units, like, seem like the appropriate thing. But, again, amount is something that is useful outside just the context of internationalization. + +BAN: (Slide 6) And I want to flip back a slide for a second. Units are relevant for CSS. Like, definitely something I want to consider. + +BAN: (Slide 8) So here's our proposed data model. As in the verse of the amount proposal that we last discussed several months ago, I believe at the last plenary, we decided to have amount store mathematical values, like, honest just mathematical values or as the result of a lot of discussion, mathematical values plus everything that can be represented using a JavaScript number. So we have this concept of an Intl mathematical value, the names, since this is going to be in a context of internationalization, Intl mathematical value is not ideal, so that would have to change, which would be a mathematical value plus not-a-number plus the infinities plus negative zero. So we have a Temporal style static constructor that takes numbers, BigInts and decimal digit strings. We’d have toString/toLocaleString for rendering the thing, dot with to update an amount with a new unit in precision and convert to, which is new since we’re reconstraining the idea of unit conversions, which would convert an amount to another amount with the same unit. And this would be implemented using the Intl unit protocol, which I believe is currently at Stage 0. + +BAN: (Slide 9) So we believe that the sketch of Amount is in scope for 262. This isn’t just about presenting numbers in different locales. It’s something that is useful outside of the cop text of internationalization, and if we had it in the context of internationalization only, people would end up wanting to use it for non-internationalization related purposes, so question for the committee is in a worthwhile direction we want to go in? And would people be on board with this vision of amount? + +BAN: (Slide 10) So now I’m going to open up to discussion. This is something that there’s been a lot of discussion sort of back channel discussion and in the numerics meeting about. And I’m anticipating a very large number of questions. + +DLM: Okay, thank you. First up would be EAO. + +EAO: Hi. So quite a lot part of the reason why we are here this week asking the question of whether it would make more sense for amount to include unit conversion already at this stage is the conversation that went—that happened at TPAC last week when I and Tantek co-chaired [a breakout session there](https://www.w3.org/events/meetings/126c9a01-9cbb-47d2-a5c9-7cc17dde0b58/) on the HTML amount proposal, which is in relatively early stages, but it did end up getting quite a bit of support as a thing, that I would dare say it has a decent likelihood of actually ending up in HTML as a thing. And so the HTML amount, there’s many details of that to be considered, effect leave it would be an element to would allow you at the very least to annotate a value as, hey, this is an amount, this is the numeric value that this is representing and these are the units that this is representing. And then provide at least for the possibility of flu some user interaction like clicking or long clicking or tapping on the amount for the host—the browser to provide a pop-up with converted values of that amount into other units that the user might be more comfortable or familiar with. And effectively, this is setting up the situation where we feel like there’s a significant source of interest in baking in the capability of doing unit conversion into the web platform in one way or another. And then the sense is that if the HTML spec effectively allows for unit conversion to happen, it would be really, really useful for the JavaScript amount to be able to support unit conversion as well to prevent developers from doing the thing that web developers seem to always do when the opportunity is there, of using a feature that is not meant—the HTML amount to do, to provide unit conversion, to do unit conversion in the way that we would like the JavaScript amount to be able to provide the unit conversion facilities. And effectively, we’re asking thus far, we’ve been presenting an amount that does not do unit conversion, but now that we can identify that there is an upcoming interest in unit conversion in the platform, should we not add that in as soon as possible rather than possibly later? And then, I mean, of course, we’ve not really prepared all of the details about what is exactly in scope for that unit conversion. Is it a subset just between the units that we currently support in Intl unit formatting or is it some other set of units that we are dealing with? These are valid questions, and the meta question is as you said first, do we include unit conversion at all first or do we first add an amount that does not do unit conversion, that makes sense just by itself and expand on it later or do we do it as a single bigger change to start with? + +DLM: Next up we have WH. + +WH: This presentation surprised me. I wish you’d put a link to the slide show on the agenda before today. I had looked at the documents linked from the agenda, but the presentation went in a different direction. + +WH: I have mixed feelings about this. Right now I can’t tell what it is that’s being proposed. Unit conversions and unit display are very different things. Lumping them both into this class seems to be a recipe for a lot of confusion and a lot of problems. I’d like to see more clarity about which units are being proposed, how you intend to do the conversion, how you specify the precision of things. + +WH: I can’t tell any of that from the presentation. To give an example, let’s say you have 1 1/16 inches, and you convert that to metric. What should the answer be? If you’re writing a unit conversion library—and people will use it as such if you provide it—then the correct answer is 2.69875 centimeters. If you’re using this for display, then that’s probably a bit too much precision. I can’t tell whether this is intended to be something used for unit conversion or whether this is intended to be used only for display, in which case what do you do when people use it for unit conversion anyway? Also I can’t tell if you intend to actually support the SI units or just do a half-hearted attempt like what CLDR does, omitting important metric units such as joules. Can you provide more clarity on all of these questions? + +BAN: Yeah. One question that’s sort of—that I sort of want to address here is just sort of how these should be stored internally. So there’s been a lot of different discussion about how should this be stored internally, like, in the implementation side. Should this be stored internally as like a decimal string as the solution, or binary coded decimal as just numbers. So ultimately, like, we’re currently in the exploration phase for this, so it’s Stage 1, so that’s something we’re sort of—something we’re coming in here to get answers to. Yes, it is intended for unit conversion. If it were simply the old Intl smart units proposal, that’s about display. This is something that we think is useful outside of just the context of 402, specifically for unit conversion. And, yeah, with the question of, like, okay, so what units are we going to support, are we going to do just what CLDR supports? The answer is probably no. We want to include more than CLDR. But, again, we’re sort of at the exploration phase, and that’s something we’re looking for answers to rather than proposing a specific solution. + +WH: If I understand your answer correctly, then, yes, you intend to provide this as precise unit conversion, and without having to do the Intl-like things? + +BAN: Right. + +WH: So you do intend to provide functionality such as, for example, you have watts and you want horsepower or you have meters and you want light years, and it will give you the precise answer? + +BAN: But, again, with the question of, like, what specific units are supported remaining open. + +WH: So the other question about scope is that this—if I understand your answer correctly, this would include the major metric units of length, volume, … + +BAN: Yes, yes. + +WH: … energy, force, power, temperature? + +BAN: Yes. I mean, absolutely including the SI units. That is sort of the bread and butter for this. + +WH: Yeah, yes, because CLDR is very half-hearted about it, so they select—they include only a few. + +BAN: Yeah. + +WH: Okay. + +BAN: Simply CLDR is not the plan. + +WH: Okay. So this answers the question. My response to that is that’s a good direction which I’d like to see explored. I don’t think putting everything into an amount with a precision makes sense. I think that mathematical unit conversion should be something that could be used independently of specifying internationalized amounts and precisions, so this seems like it would be two interconnected classes of proposals. + +BAN: That’s good feedback. Thank you for that. + +DLM: Next up we have Shane. + +SFC: I thought EAO was on the queue before me, but I think maybe we had the same sort of topic. I do think this question is something we should pursue further. I think that from my perspective, the goal of the unit conversion in amount should very, very, very closely align with the goal of unit conversion in HTML. And the goal, which is oriented towards units designed for human display, for human readable units intended for display, and I think that those are healthy constraints that we should use when designing the exact semantics. And this is still a Stage 1 proposal and the exact semantics are probably things we’ll spend a bit of time offline figuring out exactly how to word them and phrase them in the spec. + +DLM: Okay. A reminder that we have under nine minutes left. Next is EAO. + +EAO: I think I’m in alignment with SFC and just wanted to express it maybe a little bit differently. We do not have a clear understanding. We have not asked for a clear mapping of what it is exactly that what units might be included in a unit conversion amount because we’ve not needed to ask this question before because we’ve left it out of scope so far. But specifically, I would like to underline any what we’re looking—what we’re seeing is that we’re going into a situation where we may have unit conversion to some extent being supported in the web platform, and, therefore, the capabilities of that unit conversion are setting up an effective minimum bar of what we ought to provide in JavaScript to provide a better API so that the HTML API would not get abused. Whether the powers of the JavaScript API go beyond the units we currently have through CLDR and go to much greater precision and other factors are concerns we ought to consider if we are of the opinion that this is a direction we ought to go to with this initial proposal. + +DLM: Next up, KG. + +KG: You were asking for feedback about general direction, and if you think this is more worth doing than the previous iteration of the proposal. And as one of the people who is most skeptical about the need for a first class Amount type in the language, under the previous presentation, I do think that adding unit conversion facilities to amount would be enough reason for it to exist as a first class type, yes. Obviously don’t put unit conversion on it just so that you have an excuse to add the type to the language, but if unit conversion is something that we collectively think is worth doing, worth providing anyway, then this is a fine way to go about providing it. + +DLM: CHU? + +CHU: Yeah, so I give the proposal a look and I can only add from a developer’s perspective that it looks good to me. I see many use cases for that, and I can also only second that what Eemeli said, that considering the relation to the HTML API, this will happen if—so it will get abused by developers, so I think it’s worthwhile to have this going forward. And I mean, at this stage, we can explore other questions of course. + +OFR: Thanks for the presentation and also for kind of opening up the discussion again. I think that’s a good outcome. Yeah, I want to just add that it would be good to also come maybe back with a bit of a road map and with thoughts of what will come next, what you intend to build on top of it, if there are such things, and how it, like, interacts with other proposals that we might have in flight. I don’t know, I’m thinking about decimal as one thing or, yeah—so I think it would be good to know a bit more, like, the bigger picture, and especially also now because the shape of the proposal is changing, yeah, to basically understand what you have in mind, what, like, the bigger problem space that you’re working on. If there is such a thing. Yeah. + +BAN: I mean, it genuinely is tightly related to a lot of different proposals. For example, like, okay, the question of, like, how are we storing things? Well, like, building on top of Decimal is absolutely one of the options. And with regards to the proposal building off of Amount that I’ve been involved with is smart units. You know, it’s the thing that amount came out, and, yeah, yeah, I just want to say in general, it’s really really great to hear this feedback. The sort of long arc of amount over the course of the last year has been starting with a fairly large proposal and winnowing it down, and then it seems like we’re heading back up to the sweet spot, the stuff that we should cover, especially because we have the new motivation of the HTML amount, so, yeah, I just want to say in general, this has been really wonderful feed back on the whole. + +DLM: We have a point of order. We have aren’t three minutes left. OFR? + +OFR: Yeah, I think splitting proposals is like great, but what is important is that then, like, the delegates are very—like, the other delegates are well aware of what is it a part of, and so—so it’s not that we’re, like, talking about tiny things, but actually don’t know—forget what the bigger picture was in the first place, so I think that is just important. + +EAO: One way, OFR, to answer that question, we don’t have a single road map. We have multiple individuals with multiple source obvious interest. And personally for me, the road map, become on top of an amount with unit conversion is relatively shortage and in the JavaScript space, the only really, I think, necessary next step that I see from there is the consideration of whether to add support for usage and so this is specifically considering whether to support and how to support unit conversion that takes into account the locale information. So, for example, knowing that you have a height in meters and you’re—you know, you have a mass in kilograms, and you are formatting it to British audience and you want to—and you’re expressing something about baking, you use one type of unit, or if you’re referring to the weight of a person, you use another set of units. And this information, whether this is supported and represented, I think should happen, maybe even as a part of the amount that does unit conversion, but that’s, like, it for my road map. But there are other people involved in this obviously interested in decimal and other concerns that have further road maps, so it’s not necessarily about providing you with a road map. Maybe we ought to provide you—no, like actually a road map, this is my path, BAN's path, and this is SFC's path, and they’re hopefully all in alignment. + +DLM: You have the next topic as well. + +EAO: So, yeah, specifically going back to the question that we asked here, just noting that we’ve not really heard anyone say that they might have a preference for first having an amount that is a simple amount that does not do any unit conversion, but rather we’ve had a couple of voices in support of even now initially baking in. Okay, KG? + +KG: Yeah. I mean, I’ve said this in previous meeting, but I don’t think it makes sense to have a first class amount type that is just a unit carrier, because consumers of those values should be consuming those values through the public named methods anyway, and at that point, there’s no advantage to having something in the language. And we’ll be able to transparently upgrade those things in the future if the consumers go first, as long as the first class type uses the same property names as the consumers we’re expecting, then nothing changes. Yeah, I just—we shouldn’t add a thing that is just a bag of properties. There’s no reason for that to exist. + +DLM: Okay. And with that, we are at time. + +### Speaker's Summary of Key Points + +* Significant plenary support for returning to a model for Amount proposal that supports arithmetic and unit conversion +* Need to consider what units are included + +### Conclusion + +* Research appropriate units to include +* Develop roadmap for Amount in relation to associated proposals + +## Intl Energy Units for Stage 1 + +Presenter: Nicolò Ribaudo (NRO) + +* [proposal](https://github.com/johanrd/proposal-intl-energy-units) +* No slides presented + +NRO: So Intl designed this proposal about adding energy units to NumberFormat. Going for Stage 1. Apologies I don’t have slides, but the read-me is, like, very comprehensive. A bit of context, `Intl.NumberFormat` supports, like, specifying units since some years ago, and, like, it will do local comment formatting of the unit. It uses CLDR data, but it does not use all of the units that CLDR has because there are many, and they would raise, like, increasing the browser size unnecessarily if people are not going to use them. So originally we just included some subset of those units. There are some issues that just users like web developers report to do asking for more units when they have specific use cases. And this proposal is coming from—so from developers asking for it. Specifically, when it comes to energy units like what is kilo and kilowatt, they’re very common, for example, when dealing with electric cars or when dealing with batteries or solar panels or even just electricity bills. And many of these things have, like, web UIs. This proposal is explicitly—this proposal is, like, energy units, but the idea is to add specifically watt, kilowatt, and kilowatt hour. There are—because it’s the three that CLDR provides to us, and that are most common for these specific use cases that have been mentioned. There are other potential units explored. Like, but during Stage 2 we will—when going to Stage 2 we will define whether we want to do just these three. And again, the reason for like focussing on the units for the use case is because we don’t want to add a bunch of extra units. Because they come with the specific version, which is again a lot of data. So yeah. I would like to go to Stage 1. I am presenting on behalf of BAN, but BAN is the champion. Does anybody have comments? + +SFC: Yeah. Thanks for the presentation. We discussed this at length in the TG2 call. I will just give a couple of the take aways from there. One of the questions was, there is—there is ten different issues where like gotten feedback from developers that units should be in there that are not currently there and a question I asked TG2 was, like, should we pursue a proposal that adds multiple units including from different classes of units or should we focus on adding like one or very small number of units at a time? And the—the temperature of the room in TG2 was that we should focus on adding small batches of units at a time. So given that, I think this proposal is a very good scope. There is a question in this README file about whether other units of energy should be included. And yeah, this list here. So there is—yeah. There’s a different use cases for different—for different units. The author of this README file proposed specifically the three that you saw up above. As the three to be included. And I think that the reasoning is quite sound. So but I wanted to open this as an opportunity for Mendel \[unintelligible] to provide additional feedback. Any of the three units proposed for conclusion are too niche tore included or any of these other units down here are—are useful enough that we should include them along with this batch of energy units. WH has an answer to that + +DLM: WH? + +WH: Yeah. This presentation is why I am really worried about the Amounts proposal direction. On this list I see that you are not even considering any SI units for energy. Kilowatt-hour is not an SI unit. A joule is. And so I see that supporting joules as energy units is not a priority. + +NRO: Kilowatts are commonly used for user interfaces + +WH: So are joules. I see those quite a bit. + +NRO: Given this proposal to Stage 1, I think, like, we consider feedback, but we are not setting down on which units are included right now. We will—want to have Stage 2. + +WH: My concern is about the problem area scope here: whether the goal is to support a consistent set of units or to dribble units into the spec, a few at a time. And I am not happy with the problem area scope of dribbling units a few at a time. + +CDA: Reply by BAN. + +BAN: Yeah. It looks like SFC and I got on the queue at the exact same time. It’s response to a very like specific user request. I believe that the person who wrote this explainer works for a company that does energy use forecasting, something like that. And they have like a very, very specific use for these specific units. This might be useful context for that. + +NRO: To clarify, it’s not just one user requesting this. This is one of the most (upvoted?) issues in the 402 repository. SFC? + +SFC: Yeah. My next two issues are kind of related. I will jump to the second one. Just do reiterate the question, I asked the question of TG2, do we want to pursue a holistic proposal that thinks about all the cases we want to support with units in `Intl.NumberFormat`. Now we have additional data and had this for five years now. This is a good time when we could take a step back. And take a holistic view of how we do units inle NumberFormat. I asked of this TG2. And I was the only person if the room who held that opinion. The rest of the people in the room held the opinion, proposals are different by use cases, different by users. And if there is a—a user with a specific use case, that we feel is, you know, broadly applicable to users of the we can platform, then we should pursue that proposal. And that is the nature of the proposal that is in front of committee now. It is to solve a specific user’s use case. Specific user, I mean specific class of users. Not for one user. That’s this not what we here for. A class of users we feel is compelling as a general purpose proposal in the web platform. So we feel that this—there’s a enough users where kilowatts, kilowatt hours and watts solve the use cases? Now, like I think we could come with another proposal later, perhaps. I think for example, under lower priority it says scientific applications separate domain. It could be the case. Come back with a proposal later, maybe as another dependency of the amount proposal to make sure that all SI-based units are included. Right. Intl for example format we feel this is important for some reason. And that could be a separate proposal to pursue. And I think that that’s the direction that TG2 preferred. If this committee prefers us to have a holistic proposal this is an excellent time to provide that feedback am absent of that we will continue on the path of having narrow proposals that solve specific problems one at a time. + +WH: I just find it disturbing that SI units are considered low priority here and, per the slide, that scientific applications are not use cases of interest this is willing to entertain. + +NRO: Sorry it’s not that we're ignoring scientific applications. Focussing on the proposal on one specific use case which is like consumer facing like battery energy related applications. Different proposal—the question here is, do we want—should we have a single proposal for everything or proposals focused on different things? There is a different proposal that whose goal is to simplify formatting of unit for sin scientific applications speaker + +SFC: Low priority, is because this proposal that is seeking Stage 1 is speaking to resolve use cases involving energy unit formatting for these use cases that are listed here. Energy consumption, electric vehicles. And joules are low priority for that use case. But it could be that we as committee believe that having all SI units in order to better support scientific cases are motivated, and like that would be a separate proposal. I want to add context that the heading low priority does not mean we this is low priority. It means they are not a priority for this specific use case which the one we asking for Stage 1 to pursue, explore. + +WH: Yeah. In this case, I don’t think that having a use case of units for a specific application such as electrical vehicles is a good problem area for Stage 1 proposal. Units in general would be a good problem area for a Stage 1 proposal. + +SFC: That’s excellent feedback. As exactly the type of feedback we should be getting at this point in time. + +MF: I just disagree with WH here. I think that it’s perfectly fine to focus on a narrow area that affects a lot of people. This proposal affects a large group of users. And we can always do follow ons. If we do a larger unit proposal, that just ends up having—risking one small part of it holding back all the other parts. This is much more likely to just flow nicely through the process like this. + +DLM: On the queue we have a + 1 to MF’s point from EAO. And next up is ACE. + +ACE: So this maybe is a dumb question. So are these CLDR values already something that is physically inside browsers because they have CLDR data? And if this expanded, that would be moving into territories you are browsers put this new data sources? I am not familiar enough with this domain. + +DLM: EAO? + +EAO: The key blocker we like not to do the work of getting all the data about how, for example, kilowatt hours or any other unit are localized in all the places, locales that we need to support. CLDR does that work. And that effectively limits had what we— + +ACE: Of the units. Those three are CLDR. But then we are saying, this might just be the first set and then we might grow no non-CLDR data. Like, how problematic would that growth area be? So it’s likely may always only be 3 + +EAO: If we find use cases and support, the easiest thing to do is to get the CLDR to add those unitses in and then we get support for them because they have to processes of annually and repeatedly pulling people from basically around the globe or how do you spell this thing? + +ACE: Thanks. Okay. Yeah. I guess another way of looking at this proposal is that pulling the the CLDR units and it’s not a generic units thing. If we think that’s the only way to progress forward in reality. Thank you + +SFC: Yeah. Just to answer—I think to answer EAO’s—sorry. ACE’s question. We need to add localizations for the units and that’s the cost of the proposal. The proposal is not free because I don’t think any engines currently ship the data for this. Except maybe Safari because Safari doesn’t ship the data. It just uses it from the operating system. It might already be on Safari. But at least for Firefox and Chrome that ship their own data, they would now have to start shipping translations for these. Each individual unit is not a lot of data. Probably less than a kilobyte for each unit across all locales, it’s not a lot of data. It starts to add up when you add a lot of units all at the same time. If you add a particular individual unit it’s small enough that it won’t set off any flags. Like, when you try to ship it and increase binary size. That’s one more reason why smaller proposals are easier to get through committee because the payload size they contribute to the browser engines is small enough that it doesn’t trigger any like additional like reviews or processes. + +WH: Okay. Given the dependency on CLDR, I now agree with limiting this to units which are in the CLDR. On the other hand, this goes back to the question I asked during the previous presentation, will unit conversions be dependent on CLDR support? And I hope the answer to that question remains no. + +DLM: That’s it for the queue I guess. Would you like to ask for Stage 1 NRO? + +NRO: Yeah. After this discussion, WH you are okay with the proposal proceeding to Stage 1? + +WH: I was never not okay with the proposal. I was supportive of it. I just disagreed with the scope. + +NRO: Sorry. I am confused. The scope, Stage 1. + +WH: I was disagreeing with the proposed limited scope of the proposal of just the three units. I was never against adding the units themselves. + +NRO: If the problem statement is extending Intl with like energy and power units for user facing applications, which right now this is a list of three unit, exact list of units will be narrowed down for Stage 2. We have consensus going to Stage 1 with this? + +WH: I support it. I always did. + +NRO: Any other comments in support + +DLM: I support this for Stage 1. And EAO does as well. SFC. MF has strong support. + +DLM: Anyone disagree with Stage 1? Okay. Congratulations. + +### Speaker's Summary of Key Points + +* The proposal introduces energy units used for formatting of EVs/batteries UIs to Intl.NumberFormat +* There was discussion about whether we should include just W, kW, kWh, or also other units such as J. + +### Conclusion + +* The proposal advanced to Stage 1 +* The list of units will be settled for stage 2 + +## `Object.getNonIndexStringProperties` for Stage 1 or 2 + +Presenter: Ruben Bridgewater (RBR) + +* [proposal](https://github.com/BridgeAR/array-get-non-index-string-properties) +* No slides presented + +RBR: First of all, I will actually not ask for an advancement. If the committee would not encourage me to do so. I want to give that as a—prenote on it. So like this is more of an update of it. I did further look into this. The major discussion when I proposed this last time was around the use case, and this is actually very difficult to pinpoint concrete sources of where this is used because it is not something to Google for. Like, for example, with the other proposals about objects like key links we just had, you know, that’s something I can search code for with a pattern. But this is not something that is possible like that. And where I do have use cases for validation. For testing. So any users that are using errors for example, or like they are wanting this in some parts of the code. That’s my personal perspective and I've seen that. It’s difficult to pinpoint sources. This is something I am going to invest a lot of time in and before I want to present this the next time. + +RBR: What else is there? An update. We discussed it being on—placed on an array. Instead of an object. And I did change this from array to object to align with an array-like-object input and TypedArrays. I removed the options back from the original proposal which is for enumerable and limited to enumerable ones as that is definitely—if it is used, that would be the common case as such from the two. + +RBR: What else was there in my notes. Yeah. My next steps are actually that I want to make a survey about usages and ask the committee if the survey would showcase that users are indeed interested in that. If that is a way for focussing with this proposal. + +DLM: There’s no one on the queue at the moment. Now we have MF. + +MF: It’s a very open and kind of leading question there. We have had mixed value from doing surveys—or looking at others who are doing surveys—within this committee. The methodology is very important and usually the methodology is not rigorous. When people run the surveys, the selection of the audience is also usually very poor and biased. I wouldn’t put much weight in a survey personally. That’s not going to really help convince me of much related to this proposal. I would be much more convinced by, you know, paving cow paths. + +RBR: What’s that? I don’t know that word. + +MF: It’s a term I guess we use here a lot. We—we see where people are already going. So like a cow path. A path where cows walk, we pave it so it’s nicer. We see existing usage and make it nice because that’s strong evidence that that is what people want to do. We give language support for those things + +RBR: When it comes to that, there’s actually a very difficult part because it’s a little bit after the chicken-egg problem. The current usage is very, very, very likely going to be much lower than if that API—if the API would exist members would probably use it because, especially for validation, it’s so expensive to do this at the moment. When you have a TypedArray or an Array. That people will often opt out of doing it no matter what they actually do care about. But it’s just like—a cost they cannot pay. So like by saying we need to see this in the wild is like—we won’t because it is currently too expensive to do this. + +MF: I am not saying they need to literally write a polyfill for something you are using and doing that. They have to have the exact need for it already there. And we are providing that bridge. + +RBR: Okay. And that’s something I can work with. I understand, for example, speaking with, for example, as a said use analysis in the testing and validation area. When I speak with the maintainers of the libraries, getting their feedback about them being interested in having a—functionality, they would use it afterwards, is that what you anticipate? + +MF: Yes. That’s the kind of thing I am talking about. Like, people who have existing code that can point you to the place where they say they would use that thing instead of what they do currently. + +ACE: So continuing and also in agreement with MF, surveys are hard to get right. Particularly, if you ask the survey do you think you might use this? People will generally yes, because it’s an easy answer. Something like, this wouldn’t be like it’s not asking them please rewrite your entire library around this concept. It’s a utility. People’s gut reaction is probably. If you showed me a survey, everyone we asked say I didn’t, probably. I wouldn’t be convinced. I would be very unsurprised. The only thing that surprised me was if people said no because generally people don’t say no, it's a more socially expensive answer. Because you have to justify no. What I would like to see is, yes, and why exactly here is in our library where I would rewrite it. This is what it would look like. I would want—that’s a lot more work unfortunately, work is what a committee has to do, even for such a small proposal. I’ve had similar proposals very small and 99% of the time was researching and trying to do static analysis, trying to hand read libraries set up Zoom calls with people. I know it’s a lot of work for you, but personally, I really appreciate going to a yes-no question. + +RBR: Yes. Thank you. + +CHU: The way I see now, so there—for me a clear, clear need for this. I can relate that if you like what you did in the other proposal, we have this problem and this benefits the ecosystem. But I have a feeling like just adding something that might be useful, I am not sure about. And then I agree that you cannot do this in a survey to say, would you think this is useful? Of course people might think—always might think they are useful. But the thing is, yeah. So there must be some justification to that. I would like it if there were more concrete cases where correctness is important. + +RBR: Mm-hmm. It is currently used for logging, for example. When you log, this will definitely happen. And there is a utility in a V8 internal message to do exactly this. I also like it’s also implemented in assert. Where it’s also used to do validation. And I know a lot of code like—like from the private code where validation looks for extra properties to not be accepted on Array or TypedArray. This would allow us to do, that’s pretty much the common use case + +CHU: I am pretty convinced that you need, you have a need for it and seen cases. But I think we need—we need more than that. I don’t know. Like, with—`Promise.withResolvers`, that is something that had plentiful examples. We need this for logging or I don’t know. At least for me. + +RBR: Like when it is generically needed for logging, I am not—when you say need, it’s also confusing. It is already implemented in node. Using internal methods. It’s not really about node needing it. Or me needing it because it is already there. No matter what, it’s about allowing generic logging libraries to do this at the moment we are not printing this information, and for example, especially when you have a drop in replacement for `util.inspect`, pretty much `console.log` in a browser, you will not do this because it is too expensive to calculate this. But you have an interest in showing it. + +DLM: Would you go back to the queue. KG? + +KG: Yeah. I guess I am mostly seconding what ACE said, which is it’s not enough to know would people use it. That doesn’t tell us much. We have to know what they would use it for and then in addition, we have to be convinced that the things these people would use it for are worth supporting, worth adding features to the language for. And the use cases that I have heard so far have not been convincing to me. In particular, logging and assert use cases are very far from convincing to me. The assert use case is almost purely something that you will be doing in node or other server runtimes. It’s a pretty unusual thing to do on the web. And I don't think we should be adding things to JavaScript that are not useful on the web, at minimum. The logging, why are you logging these objects that have these additional properties? I don’t think that is a case that is like—the only reason to care about that case is because you think that people are going to be giving you these objects. And you should just not care if you are given these objects in the first place. So those cases are not convincing to me. The kind of data convincing to me, you find a bunch of people who have a use case where they use this and that use case is something that would be worth adding to the web, which is a pretty high bar. + +JHD: So I am in the queue. I don’t agree that these aren’t things you do on the web. Nothing you do in node, error logging happens on the web. There are multiple very profitable businesses, some in this room, that operate that way. Being able to know that the thing you are giving, the array you are given is possibly a RegExp or a template object or a communication channel are important things to figure out. So it’s very much not a node only concern. And as I mentioned with Temporal objects and match objects, the language produces arrays for which this API would not give you an empty list. And it’s—you know obviously for the cases it’s highly unlikely it would be prohibitively performant to `Object.key` on the array in the first place. But the category of objects that this API is for, is something the language has. And as far as trying to get code to not hand you this stuff in the first place, that’s what this lets you do. Without this, you can’t throw an error and instruct those callers not to give you these objects. + +DLM: In the queue, a + 1 from CHU. That’s to Calvin’s point. And then KB again. + +KG: It’s not about categories of objects. It’s about code patterns. I think you should not be writing code where \[inaudible] + +JHD: You’re cutting out a little bit. But I hear what you are saying. That is certainly a coding pattern and it’s okay that an individual doesn’t like that pattern. But— + +JHD: Sorry. You cut out a bit. We missed most of your comments. + +KG: Sorry. I don’t think you should write code that cares if it’s handed an Array versus a RegExp match object. If you expect an array, operate on the argument as an array, don’t try to check if it is a RegExp match object. I can’t imagine cases where that would matter. We shouldn’t be encouraging people to do the sort of validation where it will throw in that case. + +JHD: Okay. So my reply to that is, opinions on coding styles are valid to have, but you know, there’s lots of proposals in this committee that I think you shouldn’t be writing code to need them. But that’s not a valid reason to stop those people from doing that. + +KG: That’s a perfectly valid reason to stop those people from doing that. That’s what we are for, as a committee. + +JHD: Okay. Fair. I would say there’s nuance in it. And the simple describing the thing that you have like describing on object for logging purpose is a valid use case regardless you think the—for example, I believe that nobody should ever write sparse arrays and that anything that produces an `Array.from` another should densify it and sparse arrays are bad, et cetera. Sparse arrays exist and code on the web and off the web needs to be able to differentiate at times between sparse and dense arrays. So + +KG: I am not convinced of that claim. + +JHD: I am saying negative 0, for example, exists. And the—it’s total legit to say nobody should ever produce a negative 0 or want to. But it’s a thing that exists. And it’s a thing that therefore needs to be identifiable. It is currently. We don’t need a proposal to identify negative 0. We have `Object.is` now. But the—one’s distaste for a category of object is not—does not preclude the need to identify that category of object. + +KG: Sorry. Yeah. That’s why my title for this queue item is not about the category of objects. This for me is not about whether you should use these objects, it's about whether you need to write code which identifies these objects. + +JHD: What I am telling you is, there is a need for every kind of thing in the language to identify it it + +KG: I am not convinced of this claim. + +DLM: At this point we go to the queue + +MAH: We do have a use case where this may be helpful. More specifically, if we find that there are properties on a TypedArray, we might want to provide a diagnostics, but what these properties are, we can find there are properties on TypedArrayses, on accounts, which I mentioned yesterday. I am—this is a really narrow use case really. But that is—we have a library that does that today. And that does provide the diagnostics of the properties that are found. And we would use this most likely to provide that diagnostic. But that was the question regarding the use cases + +RBR: Yeah. I would like to come back to KG as well. About what was discussed because the user should do something or should not do something, well, we do have to face the reality that they do. And that’s something we cannot just ignore. Now, am I happy about everything that is possible with the language? Absolutely not. But do I have to acknowledge that it exists and have to work with what I have? Absolutely yes. So taking that into account, as a—like validation, I need to do the work. Do I want to? No. Of course not. Yeah. But I will do it because I want to be correct. Do I want to log this? Well, no. By default, it’s extra work to do this, and I still do it, even if it’s only a few keys and I have that extra method. It’s extra CPU cycles for something I expect not to exist in the first place. I am totally with you about that it should not happen. But like even the language itself provides objects or arrays that behave differently. Now, saying that this shouldn’t exist is confusing for me, therefore. + +KG: I don’t mean to say that these things shouldn’t exist. I mean to say that consumers which are expecting an array, should operate on their arguments as an array and should not care if there are additional properties. + +RBR: We don’t know what this is used for. Like, that’s something I cannot tell. You know? Like… + +JHD: Logging is a use case where you are not expecting an array. You are expecting anything. You need to describe it. + +KG: Yes. I recognize that if this function exists then people who are writing logging utilities specifically, would want to log the additional properties. I don’t have a problem with people making that choice if this feature existed in the language. I am not convinced that making it easier to log certain unusual objects is in itself sufficient reason to add something to the language. I grant that use case. I am not convinced that use case is by itself enough to add something to the language. + +RBR: So actually, it’s also even preventing accidental keys, for example. That’s also for the validation aspect. Like when you create objects people are using dynamic key creation. In this case you want to validate what you have. To prevent any of that, you need to do it. In this case, anything that is the validation part, you have to also check for these extra keys. + +KG: I have definitely validated that things were like arrays of the shape that I expected and not also validated whether they were sparse or had those extra keys. Just saying you need it to do in validation is clearly false in general. There are many times you validate things where you don’t care about this. Perhaps there are many cases where you do validation where you do care about this, I can be convinced that there are sufficiently many such cases to add this to the language. But you've got to present them to me. + +MAH: I just did. Our use case is a validation that some object is an array or TypedArray. And we do not want to allow extra properties. We have our library. It is used. + +DLM: Okay. We have a point of order. 5 minutes left and we should go back to the queue. WH has been waiting a while to make his point + +WH: I fully support MAH's position here. + +DLM: And ACE? + +ACE: Just a clarifying question. In the—this is a Stage 2 thing. It references like is array index like it’s a spec operation. But I can’t see anything in the spec of its array index. There is an issue you are saying, should we have that? Like, my understanding of integer index keys depends. For TypedArray, 2 to the 53 for arrays and objects it’s 2 to the 32—1. So just exactly what we think integer index here is + +RBR: Yeah. So that is definitely something to consider. And because we need to handle this. In this case, should normally just behave as if it’s an array, you expect it to be of the range of the array as index. So everything on top is an extra separate key. And for a TypedArray, it’s full length, whatever it is. + +ACE: You would look up the length property to decide whether or not it’s— + +RBR: No. On the array, lengths could be very big. But effectively, it’s outside of the allowed range from the spec. So as far as I know. I didn’t check that for a while. But like on a TypedArray, you just cannot do that. That’s what I meant + +ACE: A TypedArray can have a larger integer index. Maybe it can’t because of allocating that. + +RBR: Yes. It’s up to the size of the maximum size + +ACE: It would detect that it's a typed array and switch its behavior? + +RBR: Yes. Correct. + +ACE: I think it's an important part of the API, how it’s detecting if it’s just a fixed algorithm that works the same for every object. Like proxy. Versus whether or not it’s switching behavior. So yeah, thank you for clarifying. + +MAH: This is all Stage 2 concerns anyway. But one option is to rely on the array semantics which I think is this strict definition of what is numerical index property. That just means you have one potential extra property you might find on the TypedArray and the code has to deal with it. Just options. I don’t have have a horse in this race. + +DLM: We have limited time available. RBR asking for stage advancement today? + +RBR: I don't think that makes sense at all, so no. + +DLM: The queue is currently empty. + +RBR: Asking committee—is anyone convinced I should ask today? + +ACE: I think you have enough to ask for Stage 1. I appreciate the conserveism. Not rushing proposals, but I would encourage you to ask. Sorry if that gets you shut down, but I think you should ask. + +DLM: CDA agrees. Do you want to speak, Chris. Chris agrees. People would like you to ask + +DLM: + 1 from WH + +JHD: Just have on the notes that KG’s concerns would block do Stage 2 + +DLM: + 1 from JSL. Mathieu. Stage 1 from Chris and + 1 DJM. + +CDA: Hold on. Does anyone object to Stage 1? + +KG: I am not going to object although I am unconvinced of the motivation. To advance to Stage 2, you have to make a good case for the motivation. MAH mentioned the use case they have. Perhaps writing out why that use case is something that you think is common enough to warrant this feature—writing exactly what the use case is, because I don’t understand the context, writing that out and making the case for why this is something you expect to come up enough to warrant a feature in the language would help. Generally, have motivation that isn’t just like "people want to do logging". Make the case for why it’s worth adding to the language in terms of, what is MAH’s use case, what are the logging and validation cases that make this common enough. + +RBR: I mean, there were a few people who brought up next to me personally, and have already mentioned about where they are using it or want to use it for. + +KG: The people on the committee are extremely unusual. Saying that there are two people in the committee who would do something doesn’t actually indicate much more than that there are two people in the entire world who would do something. That’s not enough reason in itself. Often, the things that we are doing are pretty common, so write them out and explain why you think this is a thing that normal people are doing and I am very willing to be convinced by that. But merely saying people on the committee have a use case is not in itself sufficient. + +DLM: Congratulations, you have Stage 1. + +### Conclusion + +* `Object.getNonIndexStringProperties` advances to Stage 1 + +## Decorators Status Update Request + +Presenter: Jonathan Kuperman (JKP) + +* [proposal](https://github.com/tc39/proposal-decorators) +* no slides + +CDA: Next up everyone’s favorite topic. John will lead us in decorators. + +JKP: Yeah. I don’t have a lot personally. I was really interested in the topics so JS had put an agenda item for yesterday we didn’t get to. Asking the committee for an update on decorators it’s been a while since we unofficial update. I know I saw some mentions in chat conversations. I don’t have much of a plan, but I would have to hear if anybody has any updates or insights on the proposal. What is going on with it or what is best for us to do going forward. + +CDA: Would anyone like to volunteer any insights about the status of decorators? Nicolo? + +NRO: Yeah. Just very not statistically relevant information, it never happened for the proposal. People like mentioned on social media, asking me, what is going on with decorators. It happened twice, but never happened to me with another proposal. + +CDA: CHU also would like an update on decorators. + +OFR: Okay. Yeah. It’s not really a big update. So what I can say from the V8 side is that I am currently looking at the patches that were submitted by LFP from Microsoft. And he has made some changes and fixes and we’re still in discussions. These patches are a very straightforward implementation of the proposal. And it looks like they might not give us a performance we need. So what is likely going to happen is I will evaluate the feasibility of an actual efficient implementation later, and so for V8 it would be important to have a version that is, yeah, at least significantly faster than the polyfills. Yeah. Other than that, I think it’s still quite open. What you can expect from the V8 side is that we will come back with updates. Progress updates and an estimate of the complexity once we know—if I know more. And I will also come back if we encounter blocking concerns in the implementation. + +OFR: Then the second thing maybe that was the chatter that was mentioned. I had a very interesting discussion with JHD yesterday about decorators. And what he actually mentioned is that they didn’t go through Stage 2.7, which I was not aware of. Because that didn’t exist at that point. And that actually made me look at Test262 coverage. And it turns out we have almost no tests and the tests are in open pull request. That was unexpected. The pull request was from last year. And I also ran the PR tests through babel and some of them failed. And yeah. So there’s a bunch of things I guess that need to happen. I guess that’s all that I have + +CDA: I am curious what you were going to say, are you looking for help? + +OFR: Help for what + +CDA: Anything. + +OFR: I might come back with yeah. + +CDA: Thank you. I appreciate the update. There is a reply from Nicolo. + +NRO: Yes. For the test, somebody needs to deeply learn the proposal to compare with the implementation to figure out if the tests are wrong or not. Then let’s just do something somebody needs to do and check the tests have been written, running them through babel as a way to validate them. So somebody would also need to check that there isn’t some babel back carried over to the tests where it doesn’t match the spec. And I am sure the author of the tests did a good job, but somebody needs to review it. + +CZW: Yeah. I think the proposal list refers to an issue that marks that there are several tests done. But I think the Test262 actual coverage is quite low. There are a few test cases for decorators in Test262, but I think the—given the proposal size, I think the test coverage is pretty not satisfactory. + +CDA: There is a reply from Mathieu. + +MAH: I hate to do this, to this proposal, but does that mean we need to put the proposal in the 2.7 stage because it is lacking tests? + +NRO: Yeah. I have opinions about this. In the past, I also asked around to test 2.7. The reason given was that from just privacy conversations with people, Stage 3, we—when Stage 2.7, we said not look back at proposals, we sent it back a signal—we know stating Stage 2.7, it’s no test. The proposal is moving backwards. Maybe we should do it. At least browsers should be aware that the tests are not merged. In writing implementation, relying on Test262, they are running 15 tests. They shouldn’t assume the limitation is correct. But yeah if we decide—first of all, not to do. We should be very careful about external messaging. + +CDA: Yeah. I agree with NRO's comments. We only have a few minutes. I would like to get everybody on the queue to be able to speak. So folks could be brief… OFR? + +OFR: Yeah. Just a quick addition, I did not actually look at what these tests are doing. I just ran them. Yeah. + +JKP: Yeah. I think NRO covered a lot ever—I guess I have the same external fear, especially because this made it to 3 before. It’s not like we—yeah. Not that we skipped a step although we clearly did. The point though is very important that we—it seems—I was not aware of this. We need to focus on the Test262 coverage. I absolutely agree with that. I am a little bit scared just because of Nick—I heard a lot of people asking about the status of us. I am worried about the external implications if we demote the stage. I am not sure + +KM: A summary of the position of, like, the JSC team at Apple is—the consensus is that—our status hadn’t changed. We probably would not implement this until both of the other browsers implement it. So that yeah. Just a recap of that, I guess. Yeah. + +DLM: Yeah. First off, I think it’s great that you are reviewing the pull requests and the implementation. This has been at Stage 3 for a long time. It isn’t proceeding and we can’t really move it to a lower stage without implementation feedback. We have a partial implementation, but that isn't a priority for us, and like KM said, we probably will not do that unless both V8 and JSC ship the implementations. + +CDA: There’s a reply from—question from John. + +JKP: Sorry to jump on. Are you both saying that you won’t go until the other one goes? Is that what just happened? + +DLM: I believe so, yes + +JKP: Thank you. + +JHD: I was just saying, I had no idea of the status for the decorators. We will definitely be taking a look at the PR at least at the next meeting. And if someone wants to send—so anybody who is interested in seeing decorators move along should definitely add tests. Either make another PR or post links on PR or something and we will take a look at that. The other thing that I didn’t think to put on the acute, we two browsers stalemate each other, is it possible either of JSC or SpiderMonkey to ship a flag implementation sooner so that we can like get both Safari and Firefox to have a flagged implementation and then you could agree doting to unflag it. Is that something—that a possible resolution to the stalemate? + +DLM: I guess I will answer that. We are not prioritizing finishing the implementation work. So… + +JHD: If somebody else did the work, would you merge it or not? + +DLM: We have to—it would depend + +JHD: It theory + +CDA: All right. We have a minute and a half left. MF + +MF: I would like to discourage future plenary agenda items of this sort: "hey, what is the update on this thing?". Not only because I don’t think it’s the best use of committee time, but also because I think that that is actually not the most effective way to get your answer. I think in private conversations with interested parties you might get a more informative answer than you get here in plenary where any comments could be seen as a public commitment from that company. Let’s not do that anymore. + +CDA: I don’t totally disagree with your comment there, but I actually thought this—we had some good information come out of this today. But I think your point is fair. + +ACE: Yeah. I agree with you in general. But I do think—this is an exceptional case. Like, we shouldn’t do big proposals like Temporal again. But Temporal was exceptional in more ways than one. Something in Stage 3 for so long, this was the exact right thing to do, I think it’s really—I again have had lots of people ask me what is happening with decorators and things. The community should see on record like yes. I email people, I am pleased this is on a public record + +CDA: I was going to say before in terms of the public statement aspect: the folks that spoke today can remove those comments from the notes if they don’t want them to be public. I would hope they are able to remain. We are now cutting into lunch. I will read KM’s comments as low priority for us too. I don’t know what to say, I want a public answer. On this proposal, it was leading to negative speculation today in my opinion. There is a celebratory emoji. We are back at the top of the hour. + +### Speaker's Summary of Key Points + +* Discussion on Decorators took place. People are still excited to use them, browsers are still unwilling to be the first to ship them. + +### Conclusion + +* No major decisions were made. + +## Class composition: Past, present, and future + +Presenter: Lea Verou (LVU) + +* [slides](https://webplatform.design/projects/class-composition/talk/) +* [explainer](https://github.com/webplatformco/project-class-composition) + +CDA: All right, you know what time it is, time for notes. We are looking for two individuals to help out with the notes. Thank you, John. One more person to help with the notes, please, for this session. Maybe somebody—oh, SFC, thank you so much. Where is our presenter? Lea, whenever you’re ready. + +LVU: Okay. So these are in the agenda as separate issues, first the class composition open discussion, and then the class spread syntax and class fields introspection proposals, but these slides are for all three, as class spread syntax and fields introspection came out of this exploration. I don’t think they solve everything, the hope is that they might be an easy step forwards. The way I’ve structured it is first the problem statement, use cases that I’m trying to solve, then looking at what other languages are doing to handle class composition beyond single inheritance, what are the userland patterns, looking at some existing Stage 1+ proposals, where they are—how do they relate. Then a few considerations, design principles about the design space, and then the two proposals I mentioned. I imagine most people here are already familiar with the literature around multiple inheritance on a high level and its use cases. I did notice that these main categories that I’m going to talk more about in a bit. The only one that is not explained later is transparent composition, being able to pull code from multiple sources without it having be reflected in a way that can be introspected from the outside. Sometimes that’s not desirable. + +LVU: So class modularity is often there’s a case where you have huge classes with huge APIs and you want to modularize that for the same reason you want to modularize anything else. And this is a real example from the Prism code base where for V2 where we modularized its methods. It’s syntax highlighting library. We wanted to move the methods to separate modules to manage the code better, but that means we have to import them and write glue code for all of them. There is more egregious example that was shared with me yesterday, and I linked to it here, where this Babel class is basically pulled together from multiple modules and then has to write a ton of glue code. And they have their own helpers that fudge with the prototype as well. There’s a lot of good stuff in there. Then as I mentioned earlier, in Color.js we want to offer two flavors of the API. There’s an object oriented version where you create and manipulate Color objects. It has nicer DX, but it’s not efficient for a lot of the things that people want to do with it. Some color handling use cases are performance sensitive, e.g. manipulating thousands or millions of colors, so we also have a procedural, tree-shakable API, where people can just directly import functions and pass object literals around instead of Color instances. To do this, we not only need to handle both within each function, but also write a bunch of glue code as well to add them to the class. + +LVU: Then, there’s also the fundamental sort of more philosophical issue of identity versus traits and behaviors. It could be argued that these are fundamentally different and you should be able to handle them differently. There’s the philosophical argument that inheritance should be around identity, and traits should not pollute the inheritance chain. That is not a view shared by everyone, but it is a popular view. For example, in the web platform right now, we have the `EventTarget` class. And it could be argued that you never describe the identity of something as "this thing can produce events, and listen to events". That’s a capability. It’s not an identity. Which is evident when you look at its direct subclasses, which have pretty much nothing in common. And it creates the very real problem that if you have a class that’s already inheriting from something else, you cannot also make it an EventTarget. We keep stumbling on this in the web platform as well if we want to make something an EventTarget post org and it’s not inheriting from something that’s an event target. + +LVU: Very brief overview around composition, syntaxes around languages. Oh, and I just remembered, one thing I wanted to mention, I did not around a slide for, so I mentioned transparent composition, and I’ve had discussion where people are like, but the inheritance chain, who cares about it, who reads it, who actually does anything with it. In the web platform, there’s the `HTMLMediaElement` class, and then there’s the `HTMLAudioElement` and `HTMLVideoElement` classes that inherent from it. Totally fine. You could, a that a media element is an identity. Perfectly fine use of inheritance. But here is the thing, you have `HTMLImageElement` that directly inherits from `HTMLElement`. And you often have animated images that you want to be able to have playback control for. So one of the ideas discussed at some point at WHATWG was, what if we could make `HTMLImageElement` inherent from `HTMLMediaElement`, and then we get all this nice API for controlling playback, which would also be nicely consistent with the other two elements. But we can’t do that because at this point, authors might be depending on the inheritance chain of `HTMLImageElement`! In many cases, that would be an acceptable breaking change, but for something of that scale, you just can’t. + +LVU: So I took a brief view of how different languages deal with this problem. I will not claim that I have deep knowledge of all of them. Basically, there’s very few that do full on multiple inheritance, notably Python, C++ and Eiffel. Eiffel is kind of unusual but it has some interesting patterns, which is why I included it. Most others separate inheritance and have a separate mechanism for importing behavior from multiple things. So interfaces started by providing a contract that classes had to implement. + +CDA: Real quick, Lea, sorry to interrupt you. I’m only asking this because your presentation, I believe, is extensive. Would you prefer to get through the entire presentation before taking questions or would you want to take them during when they’re timely? It’s completely up to you. + +LVU: I guess it depends on what they’re about, because if they’re about something I’m about to say, then, hmm. + +CDA: No pressure. + +LVU: Sure, let’s do that. Let’s… + +JHD: Yeah, you said—you talked about really big classes, and you mentioned the one in Babel, and it feels like an anti-pattern to me and we shouldn’t be trying to encourage it. That it would be better to, like—you know, if you have so many classes—so many methods in your class that you need to spread them across multiple files, then I guess my code review response to that would be maybe you should have multiple classes or multiple functions or whatever. Obviously you can do whatever you want, but I don’t know if I like the idea of encouraging that pattern. + +CDA: There’s a reply from Jake. + +JAD: Yeah, just that, I mean, I agree. But also there are cases where it happens and it seems okay. Like, if, for example, the window class in the browser is a class because you can have multiple instances of them across iframes and that’s at the root class of a platform, and, you know, we keep adding to it. + +?: Sure. + +JHD: Yeah. I mean, it’s clear that it happens, but that’s not, like, as we’ve heard even again—against my own proposal in this meeting, just because something happens doesn’t mean it we should support it in the language or encourage it in the language. + +CDA: Michael? + +MF: Yeah, I also think this is a weird motivation. Like, people write huge classes, sure. But other languages with classes don’t have a way to take those methods out from the class declaration themselves and they just put it there, and they live with it and it’s fine. If you have a huge class, you have a huge file. Why does it make it any better to try to extract those? I don’t get it. + +CDA: Nicolo. + +NRO: For why we do it in Babel, it just makes it easier to find stuff. You look at list of files and know exactly where’s the file for methods that deal with comparing things, so you know that those methods are all going to be there, and it’s just less to figure out where they are. + +CDA: Ron. + +RBN: Just want to make note that there are languages that do have ways of handling in type of behavior with classes. Even though we look at some interface in C# and Java which allows you to have default implementations, V sharp has for even since 1.0, partial classes which allow you to break all large class implementation across multiple files. They still can interact and deal with private state and the like. But the main reason for this is primarily to break down big chunks of functionality that are related to make it easier to review, easier to manage for something that is a—still a single unit, if you were to again look at something like the window class and in DOM or any of the other large classes, document in DOM, that every now and then, you do end up needing to have something that is big that has functionality that’s brought all together so you don’t kind of having hundreds of little functions all over the place that aren’t related that are hard to rationalize. So having a kind of single cohesive way helps and also being able to break that up into ways that’s easier to maintain is also helpful. + +CDA: Waldemar. + +WH: One of the coolest ways I’ve seen of dealing with this is in Swift which has type extensions, which I haven’t seen a lot of in other languages. This lets you add methods and protocol compliance functionality to an existing class from outside the class definition. It’s not just textual inclusion—it’s properly modularized. It’s a very neat way of solving that problem. + +CDA: Christian? Oh, I’m sorry, Christian says shouldn’t we let Lea continue her presentation instead of nerding about lengthy classes. I plus one this. Please continue, Lea. + +LVU: No, this was really useful! I missed partial classes in C#, and they would have been incredibly relevant. I was hoping that something like this might come out of this discussion as well. Because the landscape is so vast that it’s very easy to miss things. + +LVU: So interfaces are usually a separate chain with different precedence rules. Methods are framed as default implementations, which has some implications around precedence that I’m going to talk about later. Then you have mix ins, which can have very different semantics depending on the language. In some languages, they’re basically macros, in others they affect the inheritance chain. It seems to be kind of a catchall for partial behavior. And traits seem to be kind of a more structured way to add in partial behavior. Rust is interesting here because you can do it post-hoc, afterwards, and this is actually the only way to do inheritance in Rust, which seems very strange to me. And then there is Haskell typeclasses, which seem to be kind of their own thing. I do not feel qualified to discuss them, but I wanted to mention them because I’m sure there are many people here who are. And should we—is there a queue or should…? Yes. Okay. Oh, yeah, and it was—I seen the queue that Rust can extend other Rust traits. That’s important—that’s an important design difference as well. In some cases, these can have their own inheritance chain, in other cases, they can’t do that. + +LVU: So in the previous examples, I was trying to keep them minimal because there were many different languages that I don’t imagine any of us is familiar with all of them. Going forwards, I’m going to use this example, which hopefully is a little bit more pragmatic. And basically in an equilateral class and inheriting from triangle and using methods from regular polygon. So the very prominent pattern today, especially in the web components world is subclass factories. You have a function that returns a class that takes the super class as a parameter. That does have a lot of advantages. It’s basically piggybacking on all the existing mechanisms of single inheritance, super works, can have private members. However, it does affect the inheritance chain, which doesn’t feel appropriate for some use cases, like where you’re importing this tiny trait, this, tiny mix-in that just adds this little thing and now your inheritance chain is different than it used to be. The inheritance chain becomes completely meaningless because it doesn’t represent anything anymore. It breaks `instanceof` because every time this is called, you get a new class. And you also need to deduplicate mixins because your mixins might also be including mixins and you don’t want to apply them twice in most cases. So usually you add a Symbol on each mixin to help you figure out what has been included, which is very hacky. And also the mixin class needs to be aware, you need to design your mix-in class in that way. You can’t just design a regular class and then have others use it as a mixin. Which I’m sure some people would argue is an advantage. But it does have some downsides as well. For example, I’m sure many of you are familiar with Lit Element. Even though in web components, mixins done through subclass factories is the standard way to do mix-ins, `LitElement` *itself* is not implemented as a mixin, but is just a class. Recently, we were discussing how could we do declarative custom elements in the web platform, and one of the ideas that was floated is what if the syntax was generating a custom element class that authors can then extend and do things to it, because you cannot do everything declaratively. The idea is simple things would be easy and declarative, and people can layer JS on top of it. And a counterargument was, but then they cannot use Lit Element. If you could use Lit Element as a mixin and it didn’t have to be designed with that in mind, that would not be a problem. + +LVU: The delegation pattern is really common as well where you basically create an object of another class and you use it internally. Sometimes the object is aware of your host class, other times it isn’t. Sometimes you have this dual linking, other times you don’t. There’s a lot to like. It has a completely separate state. It has its own inheritance chain. You can have multiple of them. You can even have the same one twice, which is rare, but it does happen. Because it’s a separate object, it also avoids conflicts. The mixin class does not need to be aware that it’s a mixin class, you can just use any class. The big, big downside is you have to write glue code yourself. There are no conveniences for it. The entire API surface needs to be done manually, you don’t have API surface added by this. It lives on a separate object. And the delegation pattern is actually the only way where you can add behaviors to web components in the web platform. Through this `ElementInternals` object, you attach this `ElementInternals` object to your element and it provides all these things that you then have to write your own API methods. And this highlights a big problem with this glue code. It’s not just that it’s tedious. Because you could argue that, yeah, you run it—you write it once, you’re done. It is also that it’s not future proof. When the web platform adds a new method for form controls, the web author cannot benefit from it until they go back and add it manually to their new components. Prototype mutations are very common pattern. Everybody does it slightly differently. Lots of userland libraries around this. Very flexible, completely transparent if you want it to be transparent. You don’t have to leave any trail behind. Can’t have private members because you’re basically going around classes and you can’t have `instanceof` checks kind of by design. And then mutations directly on instances, which I think is how TraitsJS used to work. Which is very inefficient, but affords maximum flexibility. And there’s a bunch of proposals trying to solve this. This is not the first time this has been discussed, by far. First class protocols is one that is often cited around, like, solving all the problems. Basically, you define this protocol, and then you—as long as you’re defining a certain Symbol that depends on it, actually, is the person who did first class protocols here? I should not be talking about his proposal. + +CDA: The TraitsJS guy is also on the call. Just so you know. + +LVU: Okay. Well, maybe—okay, well, let me know if I say anything that’s incorrect! And then all the methods from the protocol are imported behind that Symbol. Like, get area will not be imported as a get area method. It will be imported as a regular polygon get area Symbol. The huge advantage of this is that you avoid conflicts. Also, a big advantage is that it can be applied to classes that already exist. Some people think that this is a disadvantage. I’ve been in discussions where monkey patching is very much looked down on. Like, there are kind of two camps here. I think they’re valid use cases where you literally cannot control the class reference. So personally, I consider it an advantage. It avoids conflicts. What I don’t like personally is that it duplicates author intent, like, my understanding is, and please correct me if that’s not the case, so you need to specify a certain Symbol, like, in this case, for example, sides, but, like, I think you need to actually specify one of the Symbols from the protocol in your class before you call implement, right? + +MF: So a protocol defines required fields and provided fields. So if you a have all of the required fields, you implement the protocol via either the syntax or via the imperative API, and it gives you all of the provided fields by installing. + +(MF/LVU): Yeah, what I’m not sure about is can you not have required New Zealand ???. + +LVU: Yes. Well, that doesn’t apply then. I thought you always had to have required fields. + +MF: None is a special case of some. + +LVU: Then I guess the only issue is with first class protocols is glue code. Because they’re so defensive in terms avoiding conflicts and you have to write all the same API surface yourself, even if you just want to use the exact same names, which is by far the common case. + +JHD: That’s not entirely accurate. The protocol can provide all the implementations. Like, the only—the only time you have to write code is when the protocol is, like, in this case, get—I don’t think you need `getArea`. You can delete the area of equilateral triangle and it would just work. And similarly, you don’t need `protocol.implement`. You can use the syntax and declaratively do it like extends the triangle implements regular polygon, something to that effect. + +LVU: How does it avoid conflicts if it just imports the actual methods. + +JHD: The Symbol parts don’t avoid is conflicts. Because—or is the method name then the Symbol? + +MF: The method name would be the Symbol name provided by the protocol. + +JHD: You’re right. You do need that one string method for the string thing. That’s true. + +LVU: Yeah, that was my understanding, that basically you import the methods as Symbols and then you have to write the API surface to connect them. + +JHD: There’s been an ask from me, and I hope—I think not just me, that there be a way to have string methods defined in protocols, which would then remove the need for that. + +LVU: Yeah, but because protocols are designed to make the Symbol use case easier, the string use case would be kind of like the outlier and would have— + +JHD: Yeah, the rationale for the ask is I want to describe existing protocols too, and two stringable is a protocol, thenable is a protocol. + +LVU: Absolutely. All of the protocols already in use would actually need string methods. + +JHD: Iterable, for example, doesn’t. But so, yeah, if you assume that that change is eventually made, then eventually a protocol would be able to define it such that you would need nothing except implements regular polygon to get everything you want. + +LVU: Oh. + +JHD: Which feels very ergonomic to me. + +LVU: It depends, because there’s—there has also been criticism around ergonomics. + +JHD: I never heard any ergonomics complaints about this proposal, other than from people who would prefer mixins which is another proposal that’s conflicting. I’d love to hear about what those ergonomics criticisms are. + +LVU: I can look them up again. + +CDA: Just a quick, I am rather enjoying this, but just quick time check. We’re about almost 30 minutes into the timebox. + +LVU: Yes, I’m almost done. Keep in mind the slot is for all of the proposals as well. And then there’s Maximally Minimal Mixins. Which is also Stage 1. It’s basically trying to make the existing subclass factories idea declarative to solve some of its problems, and it has a lot of the pros and cons of subclass factories as well. And then—and the thing that often comes up in these discussions is decorators, even though they’re not directly related to multiple inheritance. I mean, something like this looks wonderful, right? So I can see the appeal. But my understanding is that given how the current decorators proposal works, you can implement this with one of these two patterns, either you can return a class, a new class that extends the class that is passed in, which is kind of a little bit like subclass factories, just with a nicer API to the outside world, or you could actually muck with its prototype, which is also similar to existing patterns. So in some ways, they let you make the existing patterns nicer, but it’s still essentially these two patterns. + +LVU: And this is a nice, natural break for the queue, I think, because the next part is about the design space considerations and principles. + +CDA: You mentioned Rust traits before, but Shane, did you want to talk about that? Can we get a microphone to Shane, please. Thank you. + +SFC: Yeah, you already stated this, but, yeah, Rust traits can extend other—you asked, like, how do you do class composition in Rust? You can extend traits and also have default impls, so like a trait can have a bunch of functions that are implemented. So, like, the trait system is the whole inheritance system in Rust. It’s just a little different. That’s all. + +LVU: So there’s no, like, explicit— + +SFC: There’s several people here who write a lot of Rust code, and I’m one of them. + +GCL: Rust does not have inheritance. It uses a different thing called composition. Traits can require that when they are implemented on something, that thing also has to implement another trait. And through that, that that trait also, say you have, what is the word? A reference to something through that trait, instead of through a concrete type, it will also allow you to use all of the methods that it has specified. But they do not themselves form a high hierarchy in the way you might expect with classical inheritance. + +CDA: Mark, I know you have end of message there on the queue, but can I ask you to talk about that. + +MM: Sure. So we’ve got this Symbol called has instance, and if an object implements a method whose name is that Symbol, then when you do a—let’s say you do an X instance of Y, and Y has or inherits such a method, then instead of just walking the prototype chain of Y to see if you match the dot prototype of X, is that right? Am I getting this right? Yeah, I think so. Instead, it first checks if there is a has—you know, has instance Symbol named method, and if so, it invokes that method with X being bound to this, and I’m sorry, with Y being bound to this, and with X as the argument. So the only reason I mention all of this is that the reason that was introduced into the language is we recognized that you might want an instance of that’s more intuitive and reflects the semantics of your program rather than just directly reflecting how you implemented the abstractions. So that was the hook for escaping exposing implementation choices that don’t reflect the overall semantics. And the subclass factory, you could extend the subclass factory pattern or you could provide a subclass factory abstraction mechanism that bundles in the use of instance of to, so to speak, repair the behavior of instance of when used with classes that were made with subclass factories. Is that—yeah, subclass factories, yes. And whether that’s a good idea or not, I can argue both ways. But the topic’s there, so the lack of instance of is less strong a point against subclass factories. That’s all. + +CDA: Lea? + +LVU: I wanted to reply that at least when comes to subclass factories as a userland pattern, you can argue that, yes, you can work it out with this limitation with `hasInstance`, and yes, I should have mentioned that. But you should not need to write code for basic things to work—they should work by default. + +MM: I agree, having to write `hasInstance` every time you write a subclass factory is certainly inconvenient and hazard prone, and that’s why I also mentioned you could have a subclass factory abstraction mechanism, basically a subclass factory factory, and then of course, that leads to a different spiral of complexity. So I’m just tossing it out there. It’s not a—you know, it’s not a killer argument for anything. It just—it’s just saying that the subclass factory direction does not necessarily suffer from breaking instance of. + +LVU: And I’m assuming the actual declarative version would just have this baked in? + +MM: I’m not—I did not know that we had a declarative proposal for mixins. Mixins based on subclass factories. I did not know that. I’ll need to take a look on that. While I’ve got you, just a quick history note, which is before EMCAScript 6, which introduced classes, before that, we had a prototype inheritance that was used both to emulate classes and also to do prototype oriented programming, which died. And we also had objects as closures. You’d have exactly the instance performance pent. And I wrote the first few class proposals for ECMA 6, the first of which was intended provide both syntactic sugar for objects as closures and give the engine enough weight, enough guarantees to be able to implement it as efficiently as classes. And then traits grew out an extension of that that was still assuming engine support to make it efficient. So, yes, the objects disclosure pattern and the TraitsJS library are all unfeasibly inefficient unless the language supports them. At which point they can be as efficient as classes. + +CDA: That’s it for the queue. + +LVU: All right. So some thoughts and other observations around the design space here. First, it seems that most use cases require both API surface and logic, so it’s important to have abstractions that do actually allow you to add API surface without having to write It all manually. Second, not everybody’s comfortable, not every use case is okay with the—with the pollution of the inheritance chain, so there should be a way to avoid that. We definitely don’t want to have to mutate instances, so it needs to be efficient. And it needs to support encapsulation. This could have been a nice-to-have, but there are cases where we might want the browser to be able to provide certain mixins, partials, whatever you want to call them, to be used in author classes and the author classes should not be able to use them without having access to the implementation details of the browser classes. In terms of nice to haves, it would be nice if you can introspect whether a certain class is using a certain mixin,`instanceof` would be nice. We already have the priority of constituencies that says authors over implementors over spec editors over theoretical purity. I was happy to hear that TC39 also adopts the same priority of constituencies. I would argue that can actually generalize this to basically consumers over producers. The same arguments apply. And if you think of it that way, I would argue that essentially the host class—the author of the host class is a consumer of mixins, so in terms of designing an API, the ergonomics on that side should matter more than the ergonomics for the mixin author, and then you have the rest of the priority of constituencies unchanged. I would also propose that, as a design principle, avoid having the inclusion syntax in the class body rather than the prelude if the order is not actually significant. There are some programming languages where you can include the mixin anywhere in the class body and it’s just hoisted. But most hoisting causes author confusion. There are valid reasons for it in some cases. e.g. import declarations are also hoisted and I think that’s great. But I don't think this is one of them. And there’s no reason to do it: if the syntax has specific timing, just include it in the prelude. PHP traits, for example, do this properly. You include them in the class, and the order is actually significant. + +LVU: In these discussions, the diamond problem comes up a lot. Like, if you look at this diagram, what happens when you call `getArea` if `getArea` is defined in both triangle and regular polygon? What happens if it’s defined in `Shape` and, well, in `RegularPolygon`? There’s all these questions. A lot of the time when people talk about the diamond problem, they’re not actually talking about the diamond problem and they’re talking about conflict resolution, method resolution order, that sort of thing, which you don’t actually need a diamond to stumble on that problem even if you just had triangle and regular polygon without shape, you would still have this question. It might be easier to answer, but these issues still arise. + +LVU: In JavaScript, because we don’t have stateful subinstances, like, for example, C++, the diamond problem is a little bit more contained. We don’t have it to the same degree, because you can’t argue that what properties will this shape subinstance have and that sort of thing. Because we don’t actually have that. But we do still have the issue of avoiding duplicate method calls, like, we don’t want the `Shape` constructor to be called twice, for example. And then, again—and then there’s resolution precedence, conflict resolution with anything that adds API surface. In single inheritance, it’s very easy, predictable known semantics, and subclass overrides superclass. With multiple inheritance, it’s not so easy because what does `super` mean? There are multiple strategies and not all of them are mutually exclusive. Most languages employ multiple of them. As I mentioned earlier for and `super` refers to the parent and then have different chains for the partials, whether you call them interfaces, traits, mixins and I’m going to say partial to encompass all of them, and then `super` still does the predictable thing. You have linearization algorithms, I think C3, which was started by Python (I think?). Basically you take the graph of parents and you have an algorithm that orders them, and then you resolve conflicts based on that order. In most of them, the order that you specify the mixins in is significant. And there’s often to some degree or within a limited scope, a last one wins policy as well in addition to other factors like scoping and proximity. Many languages, error for certain or all conflicts, for example Java which I’ll discuss in more detail shortly. In some cases, you can also rename the conflicting dependency when you import it. And you could conceivably automatically compose as a default conflict resolution behavior. I have not seen any languages that do that, but I have seen userland libraries that do, I think even TraitsJS did this? The return values when you have multiple functions with the same name, the return value was the first non-undefined return value. If it wasn’t TraitsJS it was some other userland library. Could imagine a mechanism like that where there’s a default disambiguation that composes all of them rather than one overriding the others. Especially since in some use case, you intentionally want to have multiple functions with the same name because you’re basically adding side effects to lifecycle hooks, web components do this a lot. Web components have certain methods that are life cycle hooks and called at certain points, like connectedCallback, for example. + +CDA: Sorry, we have a couple of questions. + +LVU: Yes. + +CDA: On the queue. Nicolo. + +NRO: Can you explain what is a stateful subinstance. I never heard that term, and other delegates also didn’t. + +LVU: So it’s—with the caveat that it has been a long time since I wrote any C++ so this and I don’t remember it at all, I came across this while doing research for this, but my understanding is that basically in C++, when you create an instance of a class that has a parent, then you’re essentially creating like a full-on instance of the parent as well with its fields that can have different values, like everything, and it’s just sort of contained in your instance, and then you can do this virtual inheritance thing, which basically says, like, if multiple classes are importing this class, then it resolves it in a certain way that actually I don’t fully remember. But basically, like, in JavaScript, we don’t have this completely full subinstance that you have in that language. Does that answer the question? + +NRO: Really sorry, do you mean like in—you can have, like, a field full, but then a subinstance as a different—sees a different field. + +LVU: And super.foo could be different. Yes, that’s my understanding. Again, feel free to correct me if that’s not the case. + +CDA: MM says, I don’t remember traits JS having that. + +LVU: Okay. It must be another library. + +MM: I know it’s a message, and I’m going to jump in, because I also can contribute to the previous thing. The—you know, we can understand each class and an inheritance chain as contributing to three namespaces. There’s the things to be put on the prototype, well, actually four namespaces if you count for statics on the class, but I don’t want to worry about that right now. Things put on the prototype, public fields, ie, fields named with strings or Symbols, and then private fields. Which for—for which you have to—they have to stay strictly encapsulated, you have to be within the lexical scope to see them. So JavaScript does have subinstances in that—in the sense that you’re talking about even with single inheritance, because every class in the inheritance chain contributes to each of those namespaces. And the—you know, with the prototypes, you can get overriding with the public properties you can get overriding. But with the private fields, you can’t get any conflicts because visibility the based on lexical scope. + +CDA: Just a quick time check. We have ten minutes left in the hour. + +LVU: Okay. I’m going to go through this super fast. I singled out these two languages here. Java does multiple inheritance via interfaces, which follows the pattern of "single inheritance chain plus this separate thing". Which has a side effect, because interface implementations are framed as a default implementation, anything in the inheritance chain has precedence over everything in interfaces. Which I don’t personally think is a good idea. Like, something that is immediately provided by the interface you import could have lower precedence than a super class eight classes above you. If a conflict comes up between different interfaces, it forces the author to disambiguate otherwise it’s an error, and as a result, super references only the parent and you have a different version of super, which is `interface.super`, to reference the interface. To do the same thing for interface. Obviously the same syntax wouldn’t work but I do think some kind of mechanism for doing this sort of thing would be very useful. + +LVU: Eiffel allows you to rename certain specific members as you import the traits. So by default, as you import the class, everything is imported with the specified name. But you can actually rename it. And the really nice thing is all its internal references are also rewritten. Everything still works. You don’t get errors or broken references when the class’ internal methods are calling that method. I suspect that’s not doable in JS, but I just wanted to flag it because it’s such an interesting design. I suspect some of the most hairy issues might be around should post-hoc composition be desirable, should that be a requirement, should that be something we avoid on purpose? Like someone mentioned, being able to extend the class after it’s being defined, many languages support a way to do that. Even if they don’t support it by default, they support some way to do it, like Python `__bases__`. And another issue, should the mixin class need to opt-in and be defined different than regular classes so it has to be defined that way? Or should it just be a regular class you import? Then what happens with private members? Should you be able to import private members in any way? What happens with naming conflicts? Is it explicit, do authors have to disambiguate every time no? Do we just do a reasonable thing and authors can override it if it doesn’t work for them, which would be my preference, a good conflict resolution algorithm that does the right thing in like, 90% of cases and for the cases where it doesn’t work, authors can manually disambiguate. I don’t like forcing the manual effort in advance because it might not be what they need but they'd still have to spend that effort 100% of the time. + +LVU: Also you, you don’t always know what methods a class you’re importing might contain. And you might upgrade your NPM package and suddenly you have errors that you didn’t know you wouldn’t have before. And opponent are like, well, the errors are make you notice and otherwise you might miss it and then function composition, again, should we run all the functions and pick all the return—what return is through something reasonable or implicit, we page precedence about which function wins, and if authors want composition, they can dot themselves. So perhaps I wonder if one way to make progress is thats seems that there are two different categories of use cases. There's the loosely coupled use cases where both the mix-in and the host class are defined by different people. Sometimes there’s even three groups, the host class author, the mix in author, and the person adding the mix in to the class, which might all be completely different. For example, I may want to import a browser provided mixin and add it to lit element, even though I haven’t written lit element. Things like that. + +LVU: But there’s also the tightly coupled use cases where you are maintaining all parts involved, and you’re just doing it for modularization, for code reuse, and in these cases, you usually can get away without sophisticated conflict management and post hoc application becomes less important because you can go to your class definition and modify it. It does seem that these have different characteristics. So maybe—and it does seem that a lot of the debates are around loosely coupled use cases, even whether they should be possible at all for some of them. Whether going where as the tightly coupled use cases don’t seem to bring up a lot of controversy. So I wonder if a path forwards might be to add certain high level primitives to make the tightly coupled use cases easier and explore what low level primitives would make the user-land helpers easier for the loosely coupled use case, make them less painful, and later—and we can later come up with a higher level API. And that’s how the class spread syntax came by. It’s designed for the tightly coupled use cases, and the fields introspection one is to make the loosely coupled use cases easier. But also if both of them go forwards, fields introspection can explain part of the spread syntax rather than having it be magic. That was it for the first part. + +CDA: All right on the queue we had JHD. No new forms of hoisting ever, please. And then we have WH. + +WH: Linearization goes way back. In Common Lisp, the CLOS had linearization, which combined with multiple dispatch made for some really interesting behaviors. It makes me reluctant to do anything which deals with linearization any more. It mostly worked. + +CDA: Ashley? + +ACE: It’s only somewhat related in that the reason maybe why someone is trying to compose multiple classes in the first a place, if they’re doing that just because they want something to have a certain method, then the other proposals in that space are like the pipeline and the bind operator. So then that just—getting that on the record, I think they are on the, like, outer orbit of this space as well. + +CDA: Nothing else on the queue. Oh, Michael? + +MF: Okay, so I do like your framing—the way you differentiated that there really are two kinds of problem spaces with the tightly coupled and loosely coupled use case. I do agree with that. On the tightly coupled use cases, I’m not—I don’t find them terribly convincing. Like, they don’t feel like they’re in as much of a need for us to take action. The—you know, subclass factories didn’t seem like such a bad approach, like, the downsides to them don’t seem so bad. Also for what I mentioned before of, like, just trying to take a class declaration and split it into multiple parts that you own just because you find it nicer to be in files, like, yeah, I guess that’s like something you can aesthetically prefer, but it’s not like there’s some strong need here. I’m not—I don’t find it super compelling. On the loosely coupled use cases side, though, that as you mentioned, is a much harder space. And I am looking forward to seeing the rest of your presentation, which you say is going to be talking about that more. But in that space, we need to absolutely reject any solutions that have the conflicts problem that you’re talk about. You know, you mentioned conflicts and said how you would prefer there to be like a conflict resolution strategy built in that works most of the time. I think that’s way down-playing the seriousness of those conflicts. Having a library upgrade and having it work is actuality the scary part, not having it not work, right? Because having it work means it did some kind of conflict resolution and picked one for you and you don’t know what that is. You didn’t make that decision yourself. I don’t want to go any further with this comment. I’ve not seen the rest, but I just wanted to, like, put that as that’s how I’m feeling at this moment. + +CDA: Okay. Lea? + +LVU: It was actually a new topic not a reply. I wanted to say, there are basically two ways to go about this problem. It seems extremely heavyweight to add a separate property resolution mechanism, usually the discussion becomes around how can we have nicer sugar that desugars into the existing primitives. There is always that option as well, though. I suspect it would be a nonstarter, but it does come up sometimes. + +CDA: All right. I know there’s still a couple of topics on the queue. It would be great if we can get to this them but we’re now into the next hour. We should probably move on to your proposal topics. + +LVU: Which is again me. So, class spread syntax. And that came out of that exploration, it’s not intended to solve everything, but I was thinking are there any low hanging fruits here? Any easy quick wins? As much of something can be a quick win in standards… + +### Speaker's Summary of Key Points + +* There is generally a lot of interest in these problems, even if there isn't consensus on the specifics +* Some skepticism around whether new solutions are necessary +* First class protocols might be able to solve these problems with a few tweaks + +### Conclusion + +Let's keep working on this. + +## Class spread syntax for Stage 1 + +Presenter: Lea Verou (LVU) + +* [Proposal](https://github.com/LeaVerou/proposal-class-spread) +* [Slides](https://webplatform.design/projects/class-composition/talk/#class-spread-syntax) + +LVU: The core idea is for other types of structured objects, such as arrays, iterables, objects, we already have a version of the spread syntax and it doesn’t work identically across them. There is presence precedence for that. In object you can spread undefined and arrays you can’t do that or empty array and things like that. There are differences. So I was thinking if we do end up adding multiple primitives for class partials, what would a low level partial look like? What would that basically makes it easier to just low level pull in methods without affecting the inheritance chain, without even having observable effects. And the spread syntax is something that we already have in other parts of the language, so it comes with certain semantics already attached to it. So hopefully—the hope is that that manages expectations from authors. And I’m thinking for the use cases—for it to work for its use cases you basically need to copy by descriptor, not by value. That is a departure from how object spread works. But as I mentioned already like there’s already differences between the existing spread syntaxes that we have. And the hope is that because spread syntax is low level in other objects like when you’re spreading two objects, we don’t do any particular sophisticated conflict duplication. If you have duplicate keys, the last one overrides the previous ones. I hope that manages expectations around that. And the idea is because it’s order sensitive, authors can always override things by adding things after it. So the core idea is that basically any—you can take any class and spread it into an any other class with the syntax. It would be order sensitive. So if you want to override certain threads from the mixin class, you add them after. And the class that you’re spreading does not have to know it’s being spread. + +LVU: But also a lot of—many use cases benefit from spreading actual objects, that are not classes. You should not have to define a class wrapper around them. For example, the use cases around modularizing a class definition into separate files. So ideally you should also be able to spread objects. And you should be able to spread both static and instance members from the same objects—from the same objects. So the current proposal involves like you can use a prototype property to specify what the instance methods are, which kind of makes it a little lower level, little closer to the userland helpers around this. Use cases, we’ve already seen most of them but it does also enable dynamically API surface because the object doesn’t have to be fixed. You can be generating it right there in the class definition. So the class modularity use case that I presented earlier becomes as short as this. And it means that adding a new method does not have to be added in multiple places. It can just be imported and spread and you can have a file or something and just spread them all. And then the procedural case where you have functions that you want to be usable as functions or methods, that also becomes a lot simpler. You can use it to dynamically generate the API surface for other patterns like when you’re using the delegation pattern including element internals and the form associated case that we saw earlier or even when writing glue code for first class protocols assuming we don’t have the string thing. Like, you can actually use it together with other patterns to generate the glue code. It will not be as nicely typed in that case probably. But that’s okay. Not everything is. We have many other things in the language that aren't. + +LVU: In some cases, you might even want to dynamically generate API surface to make repetitive code more DRY like Babel was doing. The same Babel file has this code that adds certain methods to the prototype that they’re just dynamically generating because there’s a bunch of them. And yes it can also serve for very rudimentary mix-ins. It is not great for mixins. But it does mean that simple things are easy, it does not pollute the inheritance chain and is completely transparent. If you don’t want to expose that the mixin is there to the outside world to the consumers of your class, you can. Even `super`, works just in a different way than it works with subclass factories. I think that is actually a very useful way as well. So in subclass factories, super refers to the class with all the mix-ins before your mix-in already applied which means you don’t quite know what you’re getting. Super could be anything depending on how many other mix-ins are also applied and you just have to be okay with that whereas when you sign methods through assignment as well, super still works, but it points to the superclass of the original class. But in many cases, that will also be a superclass—that will also be apparent in ancestor class of the host class as well. Like, in web components, for example, you could write your mix-ins to extend `HTMLElement` that every web component extends as well and apply to the web component, `super` will work and it will just point to the HTMLElement which is kind of more predictable. But it also means you don’t get private members. Private members would just break. You don’t get the dynamic super that some people might like about subclass factories. You don’t get introspection. Once it’s spread it’s gone. There’s no way to distinguish. You can’t do post-hoc application and conflict resolution is not pretty. Like, there are no abstractions to deal with it. This is not meant to be the begin all and end all of class composition. This is for specific use cases. It plugs a gap and meant to be the low level feature and doesn’t have bells and whistles but I think it serves a useful purpose for these use cases. It doesn’t have the inheritance chain pollution of subclass factories and it does add API surface. One design decision that I struggled with a bit in the first version of this proposal, I was branching based on whether `Object.prototype` was there. If you had something that was spreading the object. If not, it was spreading the object. And importing a bunch of methods and spreading to the class but less predictable and kind of weird and kind of magic. And I think just having to specify a dummy object literal with the prototype property is probably clearer and more predictable. And there’s also the other question where if you’re spreading the class that defines fields and your class also defines fields, then if you do completely naive low level everything overrides everything semantics, then the field—then the class field also override your field. That seems that is almost never desirable. I can’t think of any use cases where you actually want this. So maybe there might be value in not having completely naive ordering semantics. Maybe fields would be different and they would always override. I don’t know. + +LVU: So that was it about class spread. Is it a good problem space to work on, I guess? + +CDA: All right. Lots of items in the queue. WH. + +WH: I think we lost sight of what APIs are used for, which is abstraction. An abstraction is a contract between the class or abstraction author and its users about which lets the author of the abstraction change the internals or things inside the abstraction without breaking users. Abstractions are key to the language. Adding features to the language which break abstraction can be very damaging. Here I see this proposal break abstraction of all existing classes in a number of different ways. If you have an existing class and you want to add a private field to it, you can usually just do it without breaking users. But if any of your users happen to use class spreding on your class then you’ll break them. So now there’s an internal refactoring that class authors could do before this is added to the language that they can’t do after this is added to the language even if they never use it. Another thing that you might often want to do as a class author is to add an extra method. Now, I’m not talking about things like `Array.prototype` that are heavily monkey-patched—I’m talking about just regular classes. Usually it’s a transparent operation and nothing bad happens if a class adds a new method. But if this is added to the language, then that becomes a significant risk of being a breaking operation for every class, because somebody could be using it in a spread. So I see this as negatively affecting abstraction for code which doesn’t use this feature. And I understand what this is trying to do, but I think there are safer ways of doing it. This one seems particularly dangerous. + +LVU: I wanted to reply that it seems to me that that ship sailed. It doesn’t expose any class implementation details that are not already exposed with one exception that is public fields that I will argue in the next proposal I think there is a way to expose them any way independently of class spread. Aside from that, you can already have helpers that modify the prototype and do all these things. + +WH: I think that missed the point of what I just said. The queue is long so I don’t want to dwell on it; let’s continue. + +ACE: The thing is the fact that we’re encouraging people to spread other classes, the class never said "I’m spreadable". I think it’s like—it’s designed to be spreadable and should declare it’s spreadable or otherwise people will raise an issue, I tried to spread the class into mine and didn’t work. You just say I never intended the class to be spreadable in the first place. + +MAH: So I think my concerns are very much related. There’s a lot of things classes can do. They have a constructor behavior, they can declare public or private fields, all those things, and I do not understand what the semantics of those class features would be when you start spreading a class. So my feedback here is really for the specific class spreading approach, you’re bringing forward, I don’t see how it can work really in the general sense of using a class as the source of the thing that you spread. + +LVU: Should I—yeah, this is my bad. This is actually mentioned in the explainer and I just realized I forgot to put it in the slides. The idea is the constructor would not be spread. That is why you need to be able to port the fields separately. But the constructor itself would be basically ignored. Otherwise, in most cases, you would end up with very weird results. Private fields would not—like, private fields you would basically the actual fields would not be ported. If you have methods that refer to them, you would basically get the same result as you get today when you try to assign a method from a class' prototype to another class and it’s referencing a private field: you just get an error. Like, if you want to use class spread, don’t do that. You kind of have a similar issue with proxies today. If you proxy a class with private fields you also have problems. It’s not ideal. I don’t see any other way forward. If we say that private fields are all supported, that would never fly. And I don’t think it’s possible to port them and have them resolve to a different thing. Just making them not work just seems to be the reasonable thing. What else was there? Oh, and the idea is that this is low level enough that superclass methods are not ported. You can spread the superclass separately if you want them to be ported. But it seems that making that explicit would prevent surprises. But that’s an open design decision. Like, I don’t know if that’s the right way. + +MAH: Right. So I mean, I will restate my concern here is that a class doesn’t seem to be the right source for this. This is what Ashley and WH I think just mentioned. Classes have a lot of other things that they—what they implement is not compatible with being the source of a spread. It sound ss like the only part of a class that is acceptable is basically a method, basically the behavior that is completely stateless. or that is using the state of the thing that is being spread into which seems like application which is another proposal that was mentioned in the related realm here. + +CDA: I moved Nicola’s topic up because I think it’s appropriate because we only have just over ten minutes left for this topic. + +NRO: I think the discussion like what happens to the field or to the superclass is all great discussions to maybe have. It’s a little bit too much detail for Stage 1. The Stage 1 should pretty much open to different shapes of the solution. + +MAH: Can I ask classification on what exactly is the problem statement for Stage 1? + +JHD: Queue item if I can go to it. + +CDA: JHD. + +JHD: Thank you. It seems like you’ve listed some of the problems that this is attempting to solve. One of them is mixins. I actively diswant that solve. Mixins are bad, I don’t want them. Don’t want affordance for them in the language, they shouldn’t do that. As far as the other cases like polymorphism and stuff I thought we don’t like that as an ecosystem generally and it causes performance issues when they are polymorphic like engines and there was decades of that and makes the TypeScript types or the real or conceptual type definitions more confusing of things. Beyond the things I just mentioned that I’m not interested in solving, I wouldn’t want that to be part of the Stage 1 proposal, what are the other things that you think to you this is solving? What is the problem statement beyond mixins and polymorphism to Stage 1? + +LVU: Add to the queue or just reply? + +CDA: Just reply. + +LVU: Okay. It’s basically the use cases of the problems that I listed here, I think if you agree that some of them might be worth solving but not all of them, then that seems to me it’s still within Stage 1. But I mean, I don’t know. Like, if you think that objects being spreadable, for example, would be okay for modularity but maybe we shouldn’t be spreading classes for some of the concerns that were mentioned, like, maybe future evolution of the proposal would only include objects. If the class part is too controversial. So basically class modularity, polymorphism you mentioned the issues with polymorphism with the signatures and that doesn’t apply to the kind of polymorphism I was referring to with two versions of the API and sharing logic and that you can do in the efficient way and you can do it makes the functions polymorphic and there are way to make the functions polymorphic and the procedural version of the API are performance sensitive we don’t do the polymorphism in the functions and import the functions and then wrap them for the objects-oriented version that doesn’t have as much performance issues, performance considerations to keep the procedural one very fast. + +JHD: And I wanted to—you mentioned object spread. The presented motivation for the feature and the use of it in like JSX before that was not for mixing functions together, it was for merging data. So obviously because functions can be data, there are properties on objects and spread functions, that’s not what it is for. It is for mixing info together. And so the existence of object spreading doesn’t I think justify the existence of spreading like class static and prototype functions from one to another. I think that needs its own justification. + +LVU: Regardless of what object spreading was designed for, it is very widely used for spreading functions which as you also point out can be data. And another use case is also the whole thing around dynamically generating API surface, which presumably like the delegation pattern is in very wide use both from browser native APIs and platform native APIs and author APIs and it makes—it comes with all these advantages except the issue that you have to manually write all the code and helps make that more palatable and if you use the delegation to make it easier without mix-ins, maybe you don’t have to use mix-ins for all of these things. + +CDA: We have just a few minutes. I will ask everyone on the queue to please be brief. Mark? + +MM: Can you return to the code example of using spread with the triangle example. This one. So in this one—regular polygon. If I have an instance of an equal lateral triangle instance of regular polygon and understand the semantics of the class spread you’re proposing the answer will be false, correct? + +LVU: Yes. Can I answer to that? + +CDA: Yes. + +LVU: Yes. Like I said, yes. So ideally the polygon case you want multiple inheritance. Perhaps it’s not a good case to demonstrate that. I think the Prism example is better. + +MM: Could you should that example? + +LVU: Which was around class modularity. But basically in the polygon example, polygon is spread as a mixin. Ideally agree it should not be a mixin. It is the identity of the object. Since we don’t have multiple inheritance, it can be used for that as well. Otherwise, you can’t have—like, since we don’t have multiple inheritance, there’s no primitive in the language that will do this. + +MM: Can you go back to the pros and cons for subclass factory. + +LVU: Yes. + +CDA: We have less than five minutes now. + +MM: I will just make my—so no instance of checks. That’s with regard to the mixed in class and the object spread has the same problem. This is not an advantage of object spread over— + +?: Yes. + +?: Okay, good. That was the point I wanted to make. Thank you. + +?: Thanks. + +LVU: There are use cases where you want it to be transparent where you don’t want to expose where a certain part of the API is coming from, and I should have put that here as well. + +CDA: Okay. EAO? + +EAO: So looking at this, what I’m struggling to understand if you go to the prism example, this one, yes, the capability of doing the thing on the right is already in the language in that if you leave the body of the prism class completely empty and add a new line `Object.assign` for `prism.prototype` and second argument methods would that be doing the thing you’re looking to do? + +LVU: No. You want to copy by descriptor. You could argue made we need the version of `Object.Assign` (`Object extend()`?) that does copy the descriptors. There is that. Even if that, then you have the class definition to places which doesn’t have good ergonomics. If you do it completely imperatively, the hope is—if you look at the first example, I don’t have to repeat the functions. I have to repeat the signatures. If you look at the source code there’s JSDOC and to get types you have to duplicate that part as well. My hope is that if class spread syntax becomes a thing, languages like TypeScript might also be able to read that and produce proper typing without having to do all the song and dance. + +CDA: I know there’s still a number of items on the queue. We don’t have time. If you’re wanting to call for a consensus to advance, you should do that now. + +MM: I’m sorry. I still need clarification on what the problem statement is which is the thing that we’re approving for Stage 1. + +LVU: Improve the ergonomics of code sharing across multiple classes. + +MM: So a possible answer, just want to make sure I’m understanding the problem statement, a possible answer of the investigation might be people should use subclass factory; is that correct. + +LVU: Improve ergonomics of class sharing that doesn’t pollute the inheritance chain. + +MM: Giving the discussion of instance right now, I don’t understand what you’re saying about polluting the inheritance chain. Seems like the subclass factory is properly putting taxonomy into the inheritance chain that makes it more expressive. + +LVU: Yes. You’re right. It was a bad example. If in the polygon example, yes, absolutely. If you could have instance of regular polygon work, that would actually be a good thing. But in the prism example and just using it for modularity you don’t want to have the separate e.g. PrismMethods class showing up in the inheritance chain to let you modularize the methods. It's an implementation detail. And inheritance chain is part of the public API and not a field and method, but it is exposed. You don’t always want to expose it. In subclass factories, the problem is that you do still expose that inheritance chain but meaningless because you’re getting the override every time unless it has `hasInstance` in all of that. + +MM: Right. Okay. So just in terms of asking for Stage 1, I will just give you my reaction. The first point of what you said you want to investigate before I challenged it where it would include taking a look at existing patterns with the possibility of saying, well, just use, you know, this pattern if you have this problem as a possible answer to the investigation, I would approve that for Stage 1. I don’t feel strongly that any of these mechanisms that you have shown are an improvement over what you can write in user code today. On those grounds if the problem statement necessarily involves things like class spread, then I just find it implausible, not necessarily saying I’m blocking, but if it was the more general problem statement, I would certainly support Stage 1. + +LVU: I don’t think it needs to involve class spread as long as it satisfies those two requirements. I think those two requirements are essential to the problem statement. Otherwise, we already have ways to solve the problem. + +MM: Well, we already have ways is exactly the point that I’m making. I want you to proceed with the investigation with the possible answer being that the ways we have already got dominate the ways the possible additions to the language. + +CDA: All right, we are a couple minutes past time now. Mark, I mean, I guess, this is also a question for the entire committee, do we have a good understanding of the problem statement that we would be asking to advance? + +???: No. + +JHD: Well, Lea said earlier and I will paraphrase to get it right exploring ways to make it easier to, you know, share code across classes with some other caveats, is that essentially right? + +LVU: Yes + +JHD: So assuming that’s the problem statement, personally I’m okay with that going for Stage 1. But it wouldn’t—I would not ever want anything remote mix-in to be the solution. But I have no idea what a solution would be because the way I share code across classes is either inheritance or separate functions that I import and call and that’s okay. + +CDA: Matthew? + +MAH: I’m just trying to—general question. Are there any Stage 1 proposals with a similar problem statement already and whether that can be combined or do we need a new proposal here? And more question for the committee, do we feel there are existing proposals where this is overlapping already. + +JHD: I think the existing mix-in proposal whose champion not returned with it is not part of TC39 anymore could certainly—we could certainly withdraw that in exchange for this one since Lea is going to continue exploring it. That would be fine. + +CDA: I’m noting on the queue all of the things people are saying. And given the time and that we’re now nearly five minutes past time, I think—I mean, Lea the next topic is yours. Up to you whether it can be fruitful to continue this topic to see if we can come up with a succinct problem statement and ask to advance that or punt for now and move to your next proposal? + +LVU: I quite like what JHD suggested because ultimately what I want to do is not specifically the class spread syntax. I want to solve the main problem around mix-ins. But it seems that there should be something more concrete. So there is something more concrete there. But honestly I just think the main premise is that I don’t think the existing mechanisms in the language are sufficient because they have different pros and cons and they might be perfectly sufficient for some use cases, but not others. So I think there’s still a gap. And I just—the main thing is that I think there should be a new language feature or more to fill that gap. I don’t know what that looks like. It may look like spread. I don’t think—it definitely wouldn’t be plugged completely by spread even if spread goes forward. I’m not married to spread. The main thing is I want the problems to be solved. The main thing is I do see that—I think there are problems there. So I guess if you think that there are no problems and the existing using length methods and the existing languages are perfectly sufficient, let’s not. But if you do think they’re not sufficient and just don’t like class spread, I personally would be totally happy to explore other solutions. I just don’t think that existing methods are enough. + +AKI: Sorry. We had a point of order for the last five minutes for a replacement note taker. + +CDA: Yes. Okay. We have several problems now. Who is the other current note taker right now? Shane. We need another notetaker. Who among us can help out? Thank you Justin. All right. I don’t know if this would be sufficient to—you know, I note WH’s comment and understand the problem statement and again LVU we’re eating into your next proposal topic time. I think, you know, we can put pen to paper on what JHD paraphrased or whatever and flash that up and ask to advance based on that and, again, I don’t know if that’s enough to assuage the concerns here, but let’s at least give it a whirl. + +JHD: I put it on the queue so everyone can see the phrasing would be. I see Ashley’s clarifying question in general— + +ACE: Can I ask my clarifying question? Lea mentioned not tied to the spread syntax the name for the proposal is class spread syntax, if we’re also deciding what the problem name is, I would rather we also—if we do get Stage 1 and the problem space is not—is wider than spread syntax, it shouldn’t be called class syntax. + +JHD: Generally refine the problem statement as part of the Stage 1 transition the proposal is also renamed to match. + +LVU: Yes. I think we would do that here. + +CDA: Okay. So calling for consensus to advance to Stage 1 based on the following problem statement that is exploring ways to improve sharing code across classes. + +MM: Okay. Exploring, with that as the problem statement, I support Stage 1. + +CDA: Okay. Mark supports. Do we have any other voices of support? MAH is +1. But would like all related proposals to get a group call together. Okay, I think that’s a good idea. Support from JHD. Let’s mark mix-ins as withdrawn as well. Do we have any objections to Stage 1? + +CM: Yes. + +CDA: We do. + +CM: I find the articulation that JHD has tried to come up with which is I think well intentioned sufficiently vague that I’m just nervous, because the stuff that has been presented feels like here is a whole panoply of power tools for amplifying chaos. I’m unconvinced we will not go further down the road until I see a more articulate vision of what direction this proposal is trying to go. And I think the framing that JHD presented I think is something I could get behind, but I’m not convince this is going in that direction based on the presentation I just saw. + +CDA: Okay. + +WH: I second that. + +CDA: All right. So this proposal in the current shape of it does not advance to Stage 1. We will be moving to the next topic. + +### Speaker's Summary of Key Points + +* There is a need to clarify the problem statement +* Mixed views on whether class modularity is a problem worth solving. Some delegates feel large classes are unavoidable and modularity helps manage them, others feel that large classes are an antipattern and/or that existing language features are sufficient +* Some concerns around whether exposing private fields through class spreading violates abstraction + +### Conclusion + +Class spread syntax remains at Stage 0. + +## Class field introspection for Stage 1 + +Presenter: Lea Verou (LVU) + +* [Proposal](https://github.com/LeaVerou/proposal-class-field-introspection) +* [Slides](https://webplatform.design/projects/class-composition/talk/#class-field-introspection) + +LVU: So the next topic is class field introspection which is somewhat related but it’s independent. The core idea is that public fields are a part of the class API surface. In other languages, there’s not even the distinction that we have around methods and accessors go on the prototype but public fields are handled in the instance and feels like a bit of an implementation detail. Yes, it does have observable side effects, but it’s kind of nonsensical to hang data properties on the prototype so that is what we have. And public static fields can already be introspected by just looking at the properties of the constructor, but there is no way to introspect instance fields, and you could argue that you could just create an instance but creating an instance is not side effect free. So it can be argued that since fields are basically incorporated into the constructor, they’re just as much an internal detail as the constructor’s actual logic. However, in practice, the decision between using a field or an accessor is somewhat incidental. Like, do you need to run code when something is being read or said? Then you use an accessor possibly paired with another—usually paired with another property to store the actual value. Otherwise, if you don’t need any of that, you use a field. But today the accessor version of this can be introspected by just looking at the prototype, but the field version of this cannot be. And also it means if you start with the field version and then you switch to an accessor or vice versa, then your class goes from I can introspect these fields to—I can’t now anymore. Also there are even cases where people are defining or assigning functions to fields for certain good reasons like maybe they want to dynamically assign a different implementation based on some factor, it happens. It’s not great, it’s not performant but it does happen. One can be introspected and the other cannot. + +LVU: But why would you want to do that? For one, there’s a lot of userland helpers that do what class spread is doing by attaching things on the prototype, and they can import accessors and methods but can’t look at fields and they can’t port over fields. Also all sort of debugging tools. A lot of meta programming use cases need to be able to know what the shape of the class is, and right now there is no good way to expose the complete shape of the class. And based on incidental things, parts of the class shape are hidden today. So this is kind of a strawman just to get the conversation going of what something like that could look like. Basically you could have a Symbol method that possibly returns a frozen array of objects with non-writable, non-configurable properties and argue maybe it should be instead a function that you call in returns in array because then you don’t have to freeze it. I think that there might be—like, down the line, there might be cases where we want to make some of them—some of these mutable to some degree. Like, maybe we want to allow adding new ones later. Maybe we want to allow changing something. Like, I’m not proposing that we want to do this now. But I can sort of see it happening. And if we end up having a method that just returns an array, then we would have to add like a you bunch of methods for every possible mutation. The other concern is this might be too much detail at this point but I was having conversation with the V8 implementer the other day and I realized initializers should be lazily evaluated, you shouldn’t have to produce all the functions from the get-go for every possible class, like, that would be slow. And if you read the data structure, you might not need all of them. Like, you could have an accessor there that just computes the value, creates the function when it’s actually called. And I think even if initializer can’t possibly be exposed for performance reasons, I think even just knowing the names that exist can be useful for some use cases. Although it does cut down the set quite a lot. You can’t import—you can’t add behavior to classes without knowing like what you’re initializing to. But at least for things like dev tools and you can generate UI around this. And you could argue that—I can see arguments about exposing private fields. You can argue they can be obtained already. But it seems much easier to just not expose private fields. And I don’t see any use cases for wanting to know except perhaps dev tools. Okay. That was short. So the problem statement is figuring out a way to expose more details about the public fields in the class. What the details are is TBD and how to expose them is TDB and this is just a strawman but basically the core idea is public fields are API and API should be introspectable. + +JHD: Public fields are not actually the API and they are sugar for what will be the API potentially. You can have a public field callfoo and constructor can delete this.foo and that’s not in any way part of the API. And in particular they’re just sugar for like `Object.defineProperty` I guess, but otherwise it would be this dot foo equals in the constructor. Don’t introspect what it does in the class. Outside of source text, the context of a function and class syntax is sugar for making a function and a prototype. So you have an object and you have—you have two objects basically to introspect. If you know there’s no side effects you can substantiate it and learn more about it. You can’t learn what the function is going to do before you call it in the programmatic way and refactor things and potentially expand the API. I’m sort of if I can understand the desire to have an idea of what an instance’s shape will be without constructing one but the fields aren’t the shape. + +NRO: So I disagree with JHD here. I think we should encourage the class shape to be defined statically and better for engines and people reading the code and so I think it’s fine if moving forward we design APIs that say this is the class shape even if you cannot change the object that is not the public contract that the user—the developer using and reading your code will see. + +JHD: I think that can be reasonable for the names of the fields maybe but not their values for sure. + +LVU: So what is the API method to declare a data property that doesn’t need to run any code and is exposed to consumers of the class? + +JHD: `Object.defineProperty()` in the constructor and this comma and the name of the data property and then a descriptor whose value is the thing you want. + +LVU: That’s completely imperative. We could never introspect that. + +JHD: Correct. + +LVU: What is the declarative way? + +JHD: There isn’t. + +JHD: I’m open to exploring that personally. But fields are not the shape of the instance. Whether they should be or not is the separate discussion. But fields are just sugar. Whether you write them in the constructor or imperatively in the class body is up to you and doesn’t change the API of your object. + +RPR: Is there actually a disagreement here? I think you might be saying the same things. + +MAH: So in my opinion, public properties like that are a part of the API of the object. However, if we’re going to do this, I want to find a solution that is—that basically allows any way of declaring those fields, of those fields appearing on your object to support any of those. I don’t want something where if you refactor from the constructor install fields to class declared fields for that to be different. So we need to find the solution that basically if you want to do a declaration of the API as a field, however the field is, whether it’s accessor or whether field and installed by the structure or the class structure, it all needs to—it’s still a part of the API. + +RPR: Ron? + +RBN: Just wanted to say that public fields are introspectable and field decorators and decorator proposals so we already have one way that we—it will hopefully eventually get to that does have a way of looking at information about the field declaration. We just don’t have that reified in some way to be reachable outside of the class. And I do think that’s unfortunate that we don’t have any type of introspection even if nonmutable form of introspection for fields. But public fields give you the ability to attach meta data and the like so there is kind of a way to get to them at some point but requires explicit opt-in by annotating fields with decorators to make that useful. + +LVU: I added myself to the queue to say if you add the decorator to the field, you already know the field exists, and you cannot into spec field in the class decorator the last time I checked unless that changed. + +RBN: My point is we are already with the field decorator field giving you the way to look at the field declaration that we already give to everything else. So we have kind of this half way of getting some of the information that’s there so we—it’s not that we can’t do this, it’s just that we have chosen not to so far. + +LVU: With decorators get access to meta data around private fields as well that you probably don’t want to expose to the outside world but in terms of the API shape, I think that makes sense. + +RPR: Halfway through the time box. Still quite a few to get through. Consider if the questions are Stage 1 relevant. Matthew? + +MAH: Yeah. I fully object to private fields or initializers being exposed to this. This is not part of the API of the object. Nobody outside—this is an implementer detail and nobody outside of the object should be able to glean that information unless made explicitly available by the class implementation. + +RPR: Just to clarify, are you objecting only to private field initializers or all of them? + +MAH: Objecting to private fields and field initializers. + +RPR: Just the private field initializers or all field initializers? + +MAH: All field initializers. + +RPR: Okay. Matthew? + +MAG: Thank you for clarifying. That’s a problem this meeting. Why do you want the initializer function to be clear? I don’t understand it. As an engine implementer I would certainly block on exposing them because they’re synthetically generating functions and I freak out at the idea of just being like, hey, you can stamp this weird synthetic function on to anything. But like I want to understand why you want them. + +LVU: For use cases around porting things from one class to the other basically use cases similar to class spread you need the initializers as well because otherwise you have no way to port the fields over either. Use cases like dev tools that you don’t need the initializers and for cases where you do—for class decorators, I suppose you could get away without having the initializers as well. So it’s mainly for like the case of porting fields from one class to the other. So as I said, I think there is less value without the initializers but there is some. Like, I don’t think it’s a complete killer if we can’t do initializers. The problem space at this point is should we expose something about public fields? Are public fields part of the API and should we expose something, some of their details? It is not about the specifics. The specifics are just there for discussion. Yeah. + +RPR: Okay. Back to Matthew H. + +MAH: All right. So I think I need a clarification on the use cases here. I do not actually understand why it’s—why do we need to know which public fields are available and it does feel like some of the use case seem to be about some kind of interaction about shape that is expected. In which case is there any way for the class to have a protocol based interaction or something where they can explicitly say this is the field you’re supposed to you’re if you’re not already expecting a sufficient shape? So I suppose clarification on the problem—on the why automatic discoverable is necessary? + +LVU: Should I— + +RPR: If you would like to reply, please. + +LVU: Oh, okay. It’s basically for the same reason that we expose all other parts of the class API for the same reason that all these metaprogramming use cases need access to these things. Like, the argument is that we can already do this if you just happen to define your fields in a different way and it should be—it should not matter how you defined them. But basically the use cases that were already mentioned were around sharing code. From one class to another. Anything around displaying a class API details or wrapping them, doing something with them, you might want to have the explainer actually has a lot more use cases, so let me try to find that part. (CHANGE WRITER) + +LVU: Right, if you have a userland helper, for example, where you want to generate accessors to implement the delegation pattern, basically what I showed in class spread, but without the spread. Like, you can still do this with an actual function that—where you pass the class. But if you can’t introspect the actual fields of the class that you’re delegating to, then you can’t wrap them in class that you’re defining the accessors. Hmm? + +JRL: Can you make it larger please? + +?: The font. + +LVU: Oh, yes, yes. So, like, the element internals use case that I showed earlier, like if you can’t see that labels form and validity are there, then you also—you can’t wrap them. Although, I mean in, that case, those would actually be accessors. But just translate this point to an actual user class. + +RPR: Mark Miller. + +MM: So I want to return to the issue of abstraction and keeping a very strong distinction between the provider of the abstraction and the consumers of the abstraction. And ideally, implementation details remain only visible to the provider and are hidden—and are hidable from the consumer. Decorators enable introspection in a lot or—for a lot of this information, but it’s from inside the provider. Ie, you have to have—you know, you have to opt in by syntax as the definition of the class to give the decorator access to the classes’ internals. The protocol, explicit protocol that Mathiu broughten, up, lets you provide an explicit API for if you want to call it ex-trospection, and your accessor case interesting because the mechanism you’re proposing is one that enables code outside the class for a class that has not opted into this thing at all, suddenly code outside the class can see more about the class, which very much breaks the normal programming understanding, programmer understanding of what is a transparent refactor. Whereas, the accessor looking at the field from within the same class hierarchy, or actually from within the same class is actually introspection, which as a problem is fine, but the mechanism being used exposes those implementation details. That’s it. + +LVU: Do classes opt into having their prototype exposed? + +MM: The prototype is a very good point. They do not, and your criticism in the previous presentation of the exposure of the prototype chain itself being the leaking of mechanism that was stated by the programmer purely as part of the means of providing the abstraction, the fact that prototype chain is visible, does violate that principle. And it’s unfortunate. But I don’t—to the extent possible, I don’t want to add more violations to that. + +RPR: Okay, we’re coming up on time. I think probably the next two queue topics are essential to getting there, so Lea says I think the core point is whether you consider public fields API or not. Ruben? + +RBR: So I have a different view about myself when I proposed my first proposal here. And in this case, it’s make the problem statement as clear as possible. Like, a lot of the wording that was used is, for example, it can be useful for some things or you might want to and, like, without providing the very complete things. When you use you might want to, you did show something after a while, you know? Like, even though I didn’t follow it completely in that moment, but, like, I’m still struggling to really understand that aspect. Like, what is—what you want to achieve? Actually, when it comes to introspection that I can think about, I do know two ways of seeing that, and one is actually to call string on the class, where I see all these fields. So it is exposed to such. I know everything. I can parse this, and I have the information that you want. On the other hand, I also have a debugger protocol, for example, in V8, where I can also see even prior fields, and I can do that at run time. I can initialize all that. So I’m not sure what we gain, anything in addition from what we have, I don’t understand. + +LVU: Can I answer? + +RPR: Yes. + +LVU: So that was actually mentioned. It was part of the motivation around, like, you could argue exposing private fields as Weller because they’re already visible. The initializers are already visible. It’s just really hard. Because you don’t want to have to include a parser. + +RBR: I believe it is intended to be hard. You know, I believe that’s a positive thing and not a negative thing. + +LVU: I guess that boils down to whether you consider public fields API or not, whether you consider that they should be visible or not. I don’t understand—like, why do we even have private fields if public fields are also an implementation detail? Why do we have private methods in the prototype never should have been exposed? It seems to me that we already have hiding mechanisms for these. I’m not arguing exposing the list of private fields, even though I wouldn’t object to it either. I don’t think you should ever have to parse JavaScript code. Like, I think, you might disagree, that every time authors have to manually parse `function.toString()` output, that indicates a gap in the language. + +RPR: Okay, given the time, Lea, would you like to give the shortest statement of the problem domain? I think that might help before we ask for stage 1. + +LVU: Should we have a—the problem statement as in, like, what we’re trying to do in—for example, should we have a way to expose metadata not—what metadata those would be is TBD. Should we have a way to expose some metadata about public fields, about class public fields? + +RPR: Okay. + +LVU: Yeah. + +RPR: All right. So we’re going to pause with the queue for now because of time. And so we’re now asking for Stage 1. + +MAH: I suppose it’s a clarifying question. Do we want to expose that metadata implicitly or explicitly? Do you want to specify some automatic behavior of doing that or do you want to specify a synchronization point on how classes can opt in into doing this? + +LVU: I think the whole point is for classes to not have to opt into it, otherwise there’s already existing mechanisms that they can expose data to the outside world, so I think the utility would be far diminished if they had to opt in, because it cannot be relied on to be available in all cases. + +MAH: Okay. + +RPR: Yeah. All right. So we have support for Stage 1 from Chris. Do we have any other support? I’m not seeing anything in the room or on the queue. Okay, I think, Mark, you have objections? + +MM: Yeah, so the objections come down to two things. One is that decorators already satisfy the problem as stated. And they do it from inside the provider code, not from outside a class that is not opted in. And with regard to doing it from the outside, the refactoring hazard is real, which is right now, there’s a tremendous amount of code that dates from before we had declarative public fields that just creates the fields by assignment in the constructor. And over time, people refactor that code to use a public field declaration instead, which is a good thing that should be smooth and should not affect the public API of the class so that it’s—there’s no hazard in doing the refactoring. So I think any kind of automatic introspection should be only from the inside, not from the outside. + +RPR: Okay, and Stephen points out that Lea has clarified the problem domain is only from outside. All right, Gus. + +MM: So as something from the outside, I object because of the refactoring hazard. + +GCL: Yeah, I agree with everything Mark said. I also want to add that I think there is definitely a—at least one problem space I’m hearing here that could definitely be explored more, is sort of how do we let code stably document itself in a way that is, you know, accessible to other code. Like, it seems like that is a thing that people are talking about and that people want, and it seems like something that is worth potentially exploring. I think it’s also pretty clear that that is not exactly what is being explored in this proposal, so for that reason, I would also block Stage 1 on the current problem statement as stated. + +RPR: All right. And JSL is also blocking—or also objecting on the basis of the problem statement. and agreeing with the other objectors. + +MAH: I want to be clear, I would be in support of exploring a way of documenting as well explicitly. + +RPR: Okay. All right. I think that wraps things up for now. So thank you, Lea, for the afternoon session on classes. We’re going to a break now. This will be for ten minutes and resuming at 20 past 3. + +### Speaker's Summary of Key Points + +* There's a fair bit of support for a mechanism that allows classes to explicitly define their public fields declaratively, +* No consensus around whether regular public fields are part of the class's public API +* There are objections towards exposing field initializers publicly, even for public fields + +### Conclusion + +Public fields introspection remains at Stage 0. + +## Continuation: Declarations in Conditionals for Stage 2 + +Presenter: Devin Rousso (DRO) + +DRO: Okay, so rather than continue on the queue, which was humungoginormous, I have been chatting with a number of people about a potential, maybe not middle ground solution, but an alternate idea that in some way kicks the can down the road, but that’s maybe the pessimistic way of looking at it. In my mind, it leaves open the opportunity for this decision to be made when there’s a more compelling reason to do so. To be clear, not that the reasons that exist today aren’t compelling, but they are very contentious and it seems like there’s more than one opinion compared to some feature that strongly says that it needs to be one way or the other. What I mean by that is, for example, when this was first proposed in 2019, the using syntax didn’t exist, and I think that that is a pretty strong argument as to why it should be in the if to keep the lifetime small, and realize that’s not something everybody shares. I’m thinking in the maybe next year or two or further than that, something comes along that really needs it to be in one way or the other, as opposed to the reasons and rationales we have today. So what if instead we made it where you put and into an if, you end of sort of poisoning at parse time that variable in the else? So at parse, you get a syntax error. This way it’s neither exposed or not exposed in the else, unless you were to declare your own variables in of the else, either through another if or just through some other declaration of it. The reference here in this case is due to TDZ. The idea being if you’re trying to use the data from the if, you’re not allowed to do that. It throws a syntax error so it hopefully prevents developers from actually trying to do that one way or the other and leaves the door open for us to make this decision in the future. Again, I think there’s a lot of value in the if. My understanding from most of what I’ve seen it seems like everybody agrees that exposing the feature in the if is very valuable and nice to have for a myriad of reasons, and the else is the contentious bit and harder to come down on one way or another. And perhaps this is a way to get the if without the else. If that makes sense. To be clear, I’m not looking for stage advancement. I understand there’s more work that needs to be done on the spec. That’s my bad. I’m trying to see if there’s a path forward here that doesn’t involve trying to convince one side or the other. Is there anybody that has any strong thoughts about this one way or the other? + +CDA: Jordan? + +JHD: Yeah, why a parse error instead of just making it a TDZ variable in the else? + +DRO: Certainly we could make it a reference error as well. I was just thinking it being a parse error helps you notice that you’ve done the wrong thing quicker, as opposed to having to wait for it. Maybe someone accidentally did this in some code that doesn’t run very often as such they won’t see the fact that they’ve done this bad thing until they happen to test that code path. With parse you know at the very beginning that this is a problem. + +JHD: Makes sense. + +CDA: Gus? + +GCL: I was—yes, this sounds okay. I just wanted to say in, like full transparency that in the future, if we ever—like, I don’t see myself ever agreeing to weaken this, so it would effectively still just be the same as not having it at all, which is—yeah. + +DRO: That’s fair. I don’t know how to respond to that really other than that’s fair. I think one of the things that I kind of like about this as well is that there’s probably going to be lots of opinions that people will have on ESLint or prettier or whatever you should or shouldn’t use the else in the same way there’s rules about not doing variable shadowing. I imagine there’s people, who even if we did it expose it in the else, you shouldn’t do this as a matter of course for maybe some reason, and I bet you there’s people that would have no problem with that. So I do think that this tries to again leave the door open as much as possible. If in fact that is your stance, I suppose we can tackle that in the future. + +RPR: Ashley? + +ACE: Yeah, I quite like this being just an immediate syntax error. That sounds like TDZ’s, she’s presented before on the performance implications of TDZ. This seems perfect for a syntax error, considering even a bunch of room, let’s call ourselves experts and pat ourselves on the back, the fact that between us we can have different gut reactions and instincts and the other languages we’re exposition to, I think Mark calls it the principle of least surprise, maybe I’m misquoting someone else, this seems like the least surprising thing and immediately, there’s no ambiguity, yeah, I just think—and taking a hard stance on this rather than letting the community decide is just going to end up with a, like, I don’t know which community I’m currently in when I read in GitHub repo, am I in the community that likes this, have community that is tolling to ban this and I might be surprised. + +RPR: Waldemar. + +WH: How would this interact with `var`? + +DRO: In what sense? + +WH: If the declaration is a `var`? + +DRO: As in the data variable, is in the if var data? + +RPR: Yeah. + +WH: Yeah. There’s a couple things going on. So if instead of `let data` you had `var data`, and the other thing about what happens if—let’s tackle this one first. + +DRO: So, yeah, I was not expecting there to be var in this proposal, so it was just let const and using, so you could not do if var. That was—that’s how I presented this from the get-go. Sorry, from when it was in 2019. + +RPR: Gus? oh, Jake. + +JAD: Oh, sorry. The question is do—WH, when you’re saying what about var, do you mean var within the conditional or var within the else body? + +WH: Possibly both. I’m just pondering various cases. I haven’t seen this before, so I’m trying various cases to see if this works or not. I haven’t convinced myself one way or the other yet. + +DRO: As far as in the else, my thinking was that even in the case of something like shadowing, so, for example, the bottom left example, you would still get the syntax error, because, for example, if we decided that hypothetically in the future, the variable is only exposed in the if, then you would get one behavior, whereas if in if future, it’s exposed in the else, you get a different behavior. Even if you have a variable in the outer scope, the fact that you’re opting into this production means that it is effectively poisoned even if you have a variable on the outside that’s shadowed. + +WH: Yes, that’s the correct way of doing it. + +DRO: As far as in the bottom right example, where instead of let data is var data equals enter, that’s a great question. I hadn’t really thought about that. But I would imagine that that would be fine. I would think that that maybe is okay, but I’d have to think about that. + +RPR: Okay, Gus, I think it’s been clarified that var is not in this proposal. + +GCL: I was going to say if similar very was in this proposal, I would be okay with it being visible in the else, but not LetOrConst, just to expand on my position. + +RPR: Ten minutes clarifying. Markm clarifies he uses the principle of least surprise a lot, but did not come up with it. Justin. + +JRL: I don’t think we need to do anything. This seems like case for linting. It’s already very popular to shadow the ESLint rule. If you have two datas and you’re function with and one of them shadows, you’re going to get surprise, so don’t do that. This is a very simple we don’t need to do anything. + +RPR: Steven? + +SHS: I just wanted to point to some other language precedent where food is good in the binding and else and \[inaudible] and took a condition and using the variable and do something different. + +RPR: Ashley? + +ACE: Like Justin, this isn’t shadowing, this is where does the scope start and end. It’s— + +JRL: Absolutely shadowing. You’re shadowing the outer data in the—sorry. It’s absolutely shadowing. You’re shadowing the outer data in the else condition or the if condition. If you don’t— + +ACE: It’s not—you’re shadowing regardless. The conversation is what is the extent of the shadow. + +RPR: I think that there might be confusion here. Justin, you’re saying that the bottom right one should not be a syntax error? + +JRL: Bottom right? + +RPR: The bottom right example. The one with the—oh, sorry. + +JRL: Bottom left information yes, correct. Bottom left should not be a syntax error. It should refer to the outer data. The only reason this is confusing is because you shadowed it in your if statement. That is already a very frequent linter rule that says don’t have two datas in your function scope. + +DRO: The reason why that needs to be a syntax error is because we are not making a decision at this point as to whether the if statement is exposed in the else or not. So, again, there’s two parts to this proposal. There’s the one bit which is we’re allowing you to create let data inside of an if statement and there’s the second part which is contentious bit I’m sort of trying to sidestep to decide for the future, which is whether or not that identifier, that variable is available in the else as well. If it is, then this—the shadowing doesn’t apply. Because you would get the value if, if it opportunity expose in the else, then you would get the shadowing. So because we’re not making a decision at this point, my hope about whether or not is the exposed in the else, have a question and a possible difference in behavior with regards to shadowing, so it has to be a syntax error to avoid that. + +JRL: I understand. The case here only crops up if you do shadowing and shadowing is already something that is discouraged. + +ACE: This is shadowing regardless in this proposal is shadowing. It’s creating like a scope a wasn’t—it’s like moving the scope to a place that wasn’t there before. + +JRL: Shadowing because you have two let datas within your function body. If you don’t have two let datas, will you never run into this case. + +JHD: That’s not what the linter rule checks. Every ESLinter rule allows the bottom example because it’s normal JavaScript, except for the declaration part. + +JRL: No. That is not the way that ESLint is implemented. + +RPR: I think we’re going quite deep on this. Maybe we could come up to the next topic. Which is Kevin. + +KG: Sorry. This is mostly meant as a response to the go item. Which what happened to that? + +RPR: Oh, apology, we skipped Steven. Would someone— + +SHS: No, I just—I made my point. I said that go exposes the else and then we moved on to go back to the previous question. + +KG: Yeah, I’ve put this example in the issue tracker and in Matrix a couple of times, but to reiterate, Rust has changed its behavior for when things are dropped in a way that makes dropping happen before the else, and I think that that is an interaction in is relevant to us for `using` declarations, and I think `using` declarations are one of the main reasons to want this proposal at all. And the other behavior, Rust’s old behavior before they changed it, repeatedly caused bugs in practice. I think that’s the strongest possible evidence that you could get that semantics is undesirable. + +RPR: Andreu? + +ABO: Yeah, so I was wondering, like, the fact that you—like, in this case, you would throw a SyntaxError if the variable is referenced from the `else`, it doesn’t mean that the variable binding is not accessible. You could have a closure that is created in the condition and that gets passed to something, and that could be used in the else. Like, I’m just pointing that out as something that could happen and that wouldn’t be prevented by the syntax error. + +RPR: Waldemar? + +WH: If you have a `using` inside the `if` header, how long does it live? + +KG: So that’s the thing that I was just talking about, which I have an extremely strong opinion about, which is that it lives to the end of the if, and if the `if` is not taken, it is disposed before the else. Rust used to have it dispose after the `else`, and that caused a lot of bugs. So has to be disposed before the `else` in the case that you are taking the `else`. Otherwise it lives to the end of the `if` block. + +WH: So it seems like it dictates the answer to the question of what the scope of it is. + +KG: That’s my opinion, yes. + +WH: It can never be in the scope of the `else`. + +KG: That is the point I was trying to make, yeah. + +RPR: And LVU says, I’m fine with exposing it in the else. I’m not—I’m fine with not exposing it and using the other one, but doing neither seems very weird. Ron? + +RBN: So this is—this binding visible is with else is something we discussed in the pattern matching proposal as well with relation to the is infix operator that everybody is discussion in relation to this on day one. The issue is that not having it—not having is binding visible to the else is a huge refactoring hazard if your if condition needs to become negate if for any reason, you have to completely rewrite the entire body of code the move the declaration out of the because it makes it no longer valid in the else. So it’s a complete barrier to refactoring, which makes it a problem, and I would much rather, as much as there’s potentially some value, here I’d much Rath ban using in a declaration conditional if that’s the problem than have else—have the binding not be visible to else because it’s more of a stumbling block for every user than just those using statements. + +RPR: Nicolo. + +NRO: Yeah, like, you need the refactor in the case, but you need the just move the variable declaration, and maybe if you’re using using, you need to block around it. Yes, you need to change the code and you’re refactoring anyway, and it’s not something difficult to do, move the variable. + +RPR: Kevin? + +KG: I was just going to say the same thing Nicolo did. And to Ron’s point of maybe you should ban `using`. I think this proposal is mainly motivated by interaction with `using`. There’s not that much value for declarations other than `using`. And the interaction with `using` is extremely valuable. The things it lets you write are very annoying to write otherwise. I wouldn’t want this proposal to go forward without `using` because it’s the point of the proposal. + +RPR: Last 30 seconds. Back to Waldemar. + +WH: I have experience with languages which do it both ways and haven’t found the refactoring hazards to be a problem in the languages which exclude the `else` clause from the scope. + +RPR: All right. + +RBN: Speaking of other languages, I’ll mention that the C# also allows visibility in the else, and only time it restricts it is through static analysis of types. It doesn’t restrict it sin am thetically, so you can negate your condition and the—if you have a condition or pattern matching that initializes the variable, that’s visible in the if and you negate the condition, it becomes no longer visible in the if and only in else and that’s due to static type analysis, not due to what it would actually be doing at run time if that were a dynamic language. + +RPR: Right. Thank you. So we’re at time. I’ll just read out the last simple messages. + +MM: says agree with Justin that the lower left else refers to the outer data. And SHS says another crazy idea, ban the else in this case. Laughter in the room. Thank you. Thank you, DRO. + +### Speaker's Summary of Key Points + +* An attempt to avoid answering the question of whether the variables should be exposed in the else. + +### Conclusion + +* With the added support for the new using keyword, we have to answer this question now in order to know when to dispose. + +Next up we have another continuation, this will be the last item of the meeting for the remaining 20 minutes. And that is a continuation of the composites comparator choice with Ashley. + +## Continuation: Composites comparator choice + +Presenter: Ashley Claymore (ACE) + +ACE: Great. So yesterday I mentioned I was excited by a three word alliteration, so you can just imagine my joy right now. I think everyone had a really good time last night. Hopefully that tint mange out everything I said yesterday, because we do not have time to cover it again. The—what I’d like to do is get some actual temperature checks, but non-binding, I have not presented, like, enough to—for people to be like, yes, 100% this is the right answer. So please answer when we get to the temperature checks. I’m purely saying biased on your gut feeling, and very much any interpretation of it is of the results will be these results could wildly change as more information comes to light. It’s a very, very weak temperature check. Why am I doing a temperature check? Working on a proposal is—takes a lot of time and energy. And it’s really useful to know how the kind of likelihood of that energy has in a return, so it’s really useful to get a sense of the committee’s feelings for things to know how much more energy to keep investing into things. So it’s really, really appreciated. + +ACE: So I’d kind of like to work in and out. Like, part of me wants to ask just the general, like, hey, how does everyone feel about composites? Side note, last night, we realized that sometimes I say "COMposites" and sometimes I say "comPOSites". And then we also realized what I could start saying is "composITES" so I might throw that into the mix if I want to spice things up. + +CDA: Do you want to do the temperature check now? + +ACE: So what I’d like to do is actually a temperature check on a narrow question, and then start going wider. + +CDA: Okay, before get to that, everyone must have TCQ up before we kick off the temperature check, because if you join after, will you not see the interface. So please, if you do not have TCQ open, do so now. You have 30 seconds. + +ACE: So the—I’ll come back to this. So the question I’d like to ask is, so based on what I’ve kind of shown yesterday and our discussions, if the proposal ended up going with interning, so, you know, this is a thought experiment, you’re not saying yes, we should do interning, it’s if we found ourselves in the situation where we were doing interning of objects, would your preference be to throw when you’re putting a leaky composite into, like, a WeakSet, WeakMap, weak ref? So this—to be clear, not all composites have this, it’s just particular composites when they don’t contain things that are themselves valid. + +CDA: Okay, the temp check is up. We will give it, I don’t know, 30 seconds. + +WH: Explain polarity? + +ACE: Positive is: yes, my preference is to throw. Unconvinced is: I would rather not throw. + +CDA: Do you care if people select more than one option? + +ACE: I’d ideally like not to. + +CDA: Please only choose one. You can select all of them if you want to. That’s been enough time. + +ACE: Yeah, great. + +CDA: You’ve got 17 strong positive, two positive, three indifferent, and one unconvinced. + +**If we intern, should we throw on leaky weakmap insertion?** + +![Temperature Check | Strong Positive ❤️: 17, Positive 👍:2, Following 👀: 4, Confused ❓: 0, Indifferent 🤷: 3, Unconvinced 😕: 1][temp-check-1] + +ACE: Okay, Thanks. If someone could snapshot that in the notes, and you said it out loud. + +CDA: That’s why I said it out loud. Rob has a screen shot. + +ACE: So great, I think that matches what I was hearing yesterday. Which, yeah, Pleasantly surprised me. I thought it would be a bit more mixed. But I appreciate this. None of this is binding. So, yeah, zooming out a little, so there is like a wider conversation that I—I know RBN and others started raising it, and I shamefully kind of shot it down because I didn’t want the design space to block too much yet, but I do want that conversation to happen at some point. But if we again imagine that we are doing composites as I’ve presented them in my April talk and my yesterday talk, where they aren’t introducing new Symbol protocols, they are these, like, hard coded in the language equality things so that they can be 100% reliable, no, like, user code interaction, so I presented two possible menus. There’s design space within the two, but out of those two, are you leaning towards interning? So strong positive would be yes, I’m leaning towards interning, I want this cost of construction time at the benefit of it’s just, like, stricter equality every else else in the language. There’s no, like, API-base equality that we pick and choose where it lands. Unconvinced is no with what you’ve shown so far, and again, I don’t think I’ve shown more than enough to actually make a decision here. + +MAH: raised an issue yesterday that I was only showing interning of an object with three properties. Let’s see what happens when you add a lot more properties. So just based on what you’ve seen so far. + +GCL: Interning is positive, + +ACE: yeah. Are you positive about exploring interning. + +CDA: I’m going to give it— + +CDA: It’s not really a question. Ten seconds. All right. So you’ve got ten strong positive, four positive, four confused, four indifferent, two unconvinced. Let’s go to the queue. That’s sound like a you problem. It’s for that. Do you want to—you can—okay. Waldemar? + +WH: To understand this I had to make some assumptions. I’d like to check to make sure that my assumptions are correct. How would this interact with WeakMaps if we’re not doing interning? I would assume composites would still not be allowed within WeakMaps, right? + +ACE: So they can be. So if the way you can do it is, like, if the thing you have interpreted, because it’s a shallow intern, so if one of the values inside the composite is something with a lifetime like an object. + +WH: I’m not talking about that case. I’m talking about the case where you just have primitives inside the composite. + +ACE: Based on the prior temperature check, there was strong support for throwing. + +WH: That’s not what I’m asking. I’m not asking about the interning case. I’m specifically asking about the non-interning case. What happens when you stick a composite into a WeakMap, or is that not allowed? + +ACE: What I presented yesterday is that is non-interning case, they have—they act just like any other regular object. Each object has its own identity and its own lifetime, so the—like, I think the thing you would do is they just behave like regular objects in a WeakMap, but then—but if that— + +WH: Okay, but that seems weird because now a WeakMap would have a different notion of equality than a regular map? + +ACE: No, I agree. That’s my, like, gut feeling, but it’s within that design space. As I said, this is very hand wavy because the two options here are not like option A or option B. They’re design space A and design space B, which I appreciate makes the question hard to answer, which is why maybe just saying I’m unconvinced either way, because there’s not enough information is probably the best answer. + +WH: This is why I picked four out of the six options on the second poll. + +ACE: Yeah. + +WH: I don’t yet know what the thinking is on these questions. + +ACE: I think you answered that’s the right number to pick, then, for that case, because that’s telling me you need more information. + +WH: Yes. + +CDA: Jordan? + +JHD: So I do want to point out my discomfort over throwing only exists because I don’t have can be weakly held predicate in the language, and the arguments against it were well, if the value—if it changes value over time, it can cause web come pat risks and for some reason, try catching new WeakSet, or whatever, which does is exact same something just unergonomically wasn’t a concern. So I don’t know if, likes, the person who objected most strongly to it is now at different company, and I don’t know if that objection continues. But with such a predicate, I don’t really care as much if the—how—like, about the complexity of the definition of what things can be weakly held, because I don’t care. I just throw that predicate at it when I care. + +ACE: Yeah. So when we did Symbols as WeakMap keys, the conversation was one of the reasons we ended up picking the design was because yourself, Jordan, was convinced because there is a predicate—there is a non-throwing way of detecting registered Symbols, you say Symbol key for, and if that returns undefined, then it’s not a registered Symbol. It’s not like a one shot. You first have to go does it have type of Symbol and then ask that. And you could also imagine a design where composites has a similar-like composite or is— + +JHD: Sure. + +ACE: So is that in the space of, yes there, might not be a one shot predicate, but there is— + +JHD: I don’t think so, because I think the issue is for me is how difficult is it to explain or to write that helper? And every time we add that’s two things we now have to add, is an object or is a Symbol that’s not registered. Adding a third thing, I don’t like that. + +ACE: And the simplest thing is to try and catch. + +JHD: Right. But that’s—I would like a predicate that does that so, like, I don’t actually have to write try catch. + +ACE: Yeah, not for me to say if we can have that API. + +CDA: We have about five minutes left. Nicolo. + +NRO: Just backwards concern about the predicate, I do not believe—I believe at this point in language, basically we have cabbage collectible and that can be put in WeakMaps, and Symbols, and I don’t think we’d ever change the answer for existing things if we adjusted for new things it would decide if it’s new or false, and maybe if objection that there was a time does not apply anymore. + +JHD: And maybe so. And the value to me of having the predicate is also that we could change it, and if we did in the future, code would be using the predicate and not homegrown logic, so it wouldn’t break anyone. But I agree with you that we’re probably not going to change the answer for Symbols, and not for any currently existing objects, only for new things we introduce. + +CDA: MM says, I without draw my vote this round. That’s i t for the queue. + +ACE: Just one last thing, so yeah, as I’ve kept caveating through this, I want to present more information to the committee, so I said MAG asked to say—do a benchmark where I’m looking at more properties, I raised an issue on the proposal requesting that. + +WH: mentioned wanting more information. To WH, if you could—if you have time, if you could raise an issue of exactly the things you’d like me to present and explore, and to everyone, if there’s things you want me to research and come back to committee with, please put an issue on the thing rather than me trying to guess what you’d be interested in, because again, I really want to maximize the value of the time I spend on this proposal. It’s much appreciated. + +**Do we lean towards interning?** + +![Temperature Check | Strong Positive ❤️: 10, Positive 👍: 4, Following 👀: 1, Confused ❓: 4, Indifferent 🤷: 2, Unconvinced 😕: 2][temp-check-2] + +*Mark withdraws his vote; Waldemar had picked both positive and negative* + +MAH: For the record, MM's vote earlier was to—was negative. He withdrew the negative. So I think instead of two, we have one. + +WH: Well, the other one was me, and I voted both positive and negative because I wasn’t sure which interpretation of how WeakMaps would interact with composite keys if we were to go with the noninterning proposal was the intended one. That’s the question I asked earlier. + +CDA: Are there no more temp checks? Is that the last temp check? + +ACE: yeah. I decided I didn’t want to go too full on. This has been very helpful. + +CDA: I thought there would be one more. That’s sad. There’s nothing else on the queue. Does that bring the topic to conclusion, then, ACE? + +ACE: Yes, thank you very much. + +### Speaker's Summary of Key Points + +* We did two temperature checks. +* One on "should interned composites that would leak not be valid WeakMap keys?" +* One of "should composites be interned?" + +### Conclusion + +* Throwing for invalid Composite WeakMap keys got the most support. +* Interning composites got the most support. +* Next steps are to continue researching and return to plenary with more information + +## Meeting closing + +CDA: All right. Thus ends this edition of TC39 plenary. We did 20 hours of content in 16 hours of meeting time. I think that’s a record. That’s very efficient. And I think we had a lot of stage advancements as well. I don’t have the exact count, but… Yes. Please, could all the speakers do your duty, making Aki and ECMA proud by writing the summary and conclusion in the notes. It’s very important and appreciated by the community as well. People always want to know the status of proposals. Sorry? You’ve got 12 to write. + +???: I’m sorry, there’s 12 proposals. + +CDA: Yeah, at least 12 proposals advanced in this meeting, which is amazing. And I—yes, before we leave, because at the end of this, you are welcome to stay in the room for, you know, another hour until 5 or so on. But before we leave, we’d like to get a team photograph. I suggest on the stage. So I think we should do that, like, pretty much next. Yes. Thank you to our transcriptionist and transcriptionists who have also assisted us for this meeting. And the notetakers, do we have the list of the notetakers? + +???: Yes. And they shall be named and famed. + +RPR: Andreu, Ashley, Christian, Chengzhong, John, Jordan, Justin, James, Kevin, Mathiu. Michael, Ruben, and Shane. + +[temp-check-1]: data:image/png;base64,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 +[temp-check-2]: data:image/png;base64,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