diff --git a/meetings/2026-09/oct-01.md b/meetings/2026-09/oct-01.md new file mode 100644 index 00000000..fae27cda --- /dev/null +++ b/meetings/2026-09/oct-01.md @@ -0,0 +1,1143 @@ +# 116th TC39 Meeting + +Day Three—01 October 2026 + +**Attendees:** + +| Name | Abbreviation | Organization | +|---------------------|--------------|----------------------| +| Waldemar Horwat | WH | Invited Expert | +| Christian Ulbrich | CHU | Zalari | +| Danilo F Tedeschi | DFT | Google | +| Ross Kirsling | RKG | Sony | +| Yusuke Suzuki | YSZ | Apple | +| Keith Miller | KM | Apple | +| Istvan Sebestyen | IS | Ecma | +| Lea Verou | LVU | OpenJS Foundation | +| Ruben Bridgewater | RBR | Invited Expert | +| Ron Buckton | RBN | F5 | +| Chris de Almeida | CDA | IBM | +| Samina Husain | SHN | Ecma | +| Nikolaos Papaspyrou | NPU | Google | +| Luna Pfeiffer | LPR | Invited Expert | +| Jesse Alama | JMN | Igalia | +| Ashley Claymore | ACE | Bloomberg LP | +| Chip Morningstar | CM | Consensys | +| Guy Bedford | GB | Cloudflare | +| Jordan Harband | JHD | Socket, Inc | +| Justin Ridgewell | JRL | Google | +| Kevin Gibbons | KG | Invited Expert | +| Mathieu Hofman | MAH | Agoric | +| Mikhail Barash | MBH | University of Bergen | +| Michael Ficarra | MF | F5 | +| Mark S. Miller | MM | Agoric | +| Olivier Flückiger | OFR | Google | +| Oliver Medhurst | OMT | Invited Expert | +| Richard Gibson | RGN | Agoric | +| Rob Palmer | RPR | Bloomberg LP | +| Shane F Carr | SFC | Google | + +## ESM Phase Imports normative PRs for Module source identity and Non-injective source imports + +Presenter: Guy Bedford (GB) + +* [proposal](https://github.com/tc39/proposal-esm-phase-imports) +* [slides](https://docs.google.com/presentation/d/1vxa-GBXmsm0B4TjQMks05i1632gsXgJpVSFQeJeaV2Q/) + +GB: 2 PRs were presented in May, one was approved and one wasn’t. Sure. And the reason was that RBN brought up concerns about, the ability to have a cross-agent module identity which is something that shared structs, potentially could be interested in. So what I am bringing to this meeting is a PR 63, which is a normative alternative to the previous identity model presented, which introduces a refined concept of a global module identity. As well as an additional PR, which has not previously been discussed, allowing a form of weak source imports. So just to give the full refresher on the identity semantics, I'm not going through all the aspects of the proposal. But specifically honing in on these identity semantics that we're talking about. So these are JavaScript source phases which is the same object type that is expected for module declarations. + +GB: The source phase just gives us a way to have this object without the module declaration syntax, in a sense, for non-module declaration modules. And if you post the same module twice, across to a worker, you're going to get two separate module object identities. So we've got this module source object; it's underlying module source record, and then the kind of identity of that record. So they're two separate things. In this case, we have two separate modules that both have the same underlying module source. On a worker. And then the question is, what happens when you dynamically import this module source? And we designed early on that we wanted to have instance equality so that we could have a concept of cross-agent module identity. So if you transfer the same source multiple times, and you import it, you get the same module even though it's not in the URL registry. This is a source registry. So the way we did this in the specification was we defined a concept of source text equality. And we said, when you serialize the module record, you serialize the source text itself. As well as the URL and the host defined data. And then we defined this ModuleSourcesEqual operation. And then we said if there's already a module that has the same equality as this module, then that registry can be used. Sorry, then that instance can be used instead. + +GB: So it forms a sort of a module source registry alongside the usual URL keyed registry. So you can think of the registry as containing two separate maps. You've got the import URL registry, where you have these strong string keys. And in the source registry, where you have source keys. So and as I mentioned before, the same identity model applies for module declarations. So if you have a module declaration and post it across into a worker thread, and do the same thing, the same thing applies. Everything we're talking about here on the source phase also applies to module declarations. + +GB: So with module declarations, though, if you create two module declarations that both have exactly the same source text, and they come from exactly the same URL, there's this question of, well, are they going to just because their module source is equal according to the definition that we defined is true? Because they have the same source text down to whitespace, et cetera. And you end up in a situation here where we don't have a comprehensive identity model, right? So there's clearly what we talked about before when we discussed these cases with something like some kind of extra ID that gets associated with a module and the host does this. But it wasn't formally defined. And so this kind of gets messy without having a formal definition of the identity model. + +GB: But then just going back to the premise, why did we do this whole source text equality thing in the first place? Well, it was the only way we knew how to define a module identity across agents. And the use case in mind was the structs proposal when we did this. So when I presented it before, I said the structs proposal is has no interest in this. So we shouldn't be defining a semantic without a clear use case. And so we proposed in May to simplify equality and entirely remove this whole concept of cross-agent source equality. Replacing it just with the module identity of the thread local ModuleSource object. And that was PR 58. So a complete simplification, avoiding all of the complexity and if we did that, we would get these imports no longer equal. And the same would apply for module declarations. + +GB: So since RBN brought up that there is still interest in cross-agent equivalence relations of sources and structs derived from sources, we-- I'm presenting a new normative PR 63 to define a new concept of global module source identity. And so just to go through the identity models, we've talked about cross-agent source text and URL equality. Per-agent ModuleSource object identity. And then this is the third one, cross-agent opaque globally unique ModuleIdentity. And the way this works is we define a new opaque type as a ModuleIdentity which has a unique constructor. So you can recreate you can only uniquely create a ModuleIdentity. And it can only it's defined that it can only be set on modules that have the source text equality property. + +GB: So during transfer, you basically can only construct modules that have this property. And from an implementation perspective, you can think of it as either an atomic counter or a UUID, basically, associated with the ModuleSource. And when importing a ModuleSource, if a module with the same module identity already exists in the thread local or the dynamic import module registry, then that same shared instance is used. So with this, we can retain cross-agent identity. We have the ability to do this. And it solves for the module declaration case that was previously not possible. That was previously ill-defined. So two module declarations with unique with exactly the same source text and exactly the same URL, but now we can actually give them a separate identity because they both get a freshly minted identity. And they don't match incorrectly. So you have two separate modules. But if you transfer the same exact module, you get the same identity. + +GB: Briefly, talking about module GC. So what this actually does is right now in module, in the module system, every module that is imported, sits in rooted in a registry under a string that can never be GC'd because that's a strong reference. But with these module source imports, they are theoretically GC-able. Because the key is a ModuleSource, or ModuleIdentity, instead of a string. So you could say that if the ModuleSource is GC'd, it's no longer going to be available. And you could GC the instance. But now that we have ModuleIdentity, you could in theory have the ability to be able to dispose these instances. So how are we going to do that without resulting in cross-agent GC is the question. And so this is done by making the ModuleSource registry weak. So the expectations on the ModuleIdentity registry are weak expectations so the idea here is that if the agent itself has no own so just like we had in the other PR where the ModuleSource itself is the key, when we move the key to become the ModuleIdentity, we can say that a ModuleIdentity is only live in a given thread or agent when there are ModuleSource objects with references to that ModuleIdentity because that's the only way to semantically handle a ModuleIdentity. And so then if there's no module sources with references to that module identity, that source import can be GC'd from the module registry without it being a cross-agent GC situation. Obviously, import URL remains non-GC-able as we have today. Pending some way to pin that registry to a compartment or a registry store. But that now, under this change, makes import source well-defined in terms of its GC ability and in a way that supports thread local weak registries while having global module identity. And this is what is defined in PR 63. + +GB: Under this model, you could have a module posted to another thread wait a very long time and then post it again. And when you first import it, you would get a side effect. Later, if you don't have any references to anything, it could be GC'd. And if someone later transfers another module in with the same identity, the side effect would rerun. And that is the consequence of this concept of weak GC ability of the source registry. That you can have local clean-up. But that is basically the sort of the only implication that's worth being aware of in this model. So that cross-agent GC does not need to be defined. + +GB: So I'd like to stop there and invite discussion. If we're ready, for that in the notes. Because that was a lot of content. And yeah, it would be good to work through the queue briefly on that. + +RPR: Yeah. Thank you, Guy. So yeah, Kevin managed to get the bot up very early. So we are good for discussion. First is MM. + +MM: So I'm not sure I followed all that, but the thing I wanted to confirm is a module identity is unforgeable. That if you don't have the module, you can't synthesize something that tests as having the same identity as the module. Okay. + +GB: Correct. + +MM: And then the is there any precedent in post message in structured clone for transmitting an unforgeable identity between agents? + +GB: Not that I'm aware of. + +MM: Okay. All right. Me neither. So I think this is good. I'm I would just want the to alert the implementers that preserving unforgeable identity over post message is a new case that you might want to think about whether your implementations are ready for it. + +GB: And it is restricted to the agent cluster as well to caveat the identity. + +MM: Oh. Oh, that's interesting. Why is it restricted to the agent cluster? + +GB: The thinking is that if you're using something like so you would want it to be within the same security context of the application. And if you're implementing it something like with a-- I guess there's milestone implementation strategies. But restricting it to an agent cluster seemed to be the simplest way. Of ensuring that. But we could consider relaxing that if that seemed too strict. + +MM: Okay. I would like to relax that because the agent cluster semantically is about is very specifically about SharedArrayBuffers. + +GB: I see. + +MM: But if the implementers have a problem with relaxing that, then it's not something I insist on. But I certainly I don't think that the defining characteristic of agent cluster, which is SharedArrayBuffers, is relevant to this. + +GB: Interesting. I can post a follow-up issue on that. I think it doesn't affect the direct current normative change. But it is an important refinement that we should track. + +MM: Okay. Good. Thank you. + +RPR: KM. + +KM: When you talk about the GCing part, does it actually need to be a GC? Can these source modules can they refer to each other in a way that makes a cycle? Like what could it not just be a thread safe reference counted? + +GB: It could be. + +KM: They are like many wrappers that point to it or something in each worker or the main page. + +GB: Yeah. At the end of the day, they are straightforward references. They don't have, I guess a module source, it's fully serializable in itself. With module declarations, we do potentially have cycles between module sources. In transfer and things like that. So that maybe gets a little bit more complicated. I guess the cross-thread cases would kind of come up from a more of a perspective of just you would have to for the first time have cross-thread reference tracking. But it doesn't need to be cyclic necessarily. + +KM: I mean, without cycles, I don't think it's any worse than like SharedArrayBuffer, right? Because SharedArrayBuffer also needs something of like you have many wrappers and these different agents and they need to point to the same underlying data store. And you want to free that data when they all go away. For cycles, I guess I don't know. It might be solvable. I mean, I think for even like we at least for web assembly runtime types, those can be cyclic. And they're still reference counted today. And we just kind of do a cycle collection because they don't go away very often. So it's not like a huge deal to do that cycle collection. And I would expect probably a similar thing here might be okay. But I'm curious what other implementers think if that's something they would do or what their strategy is even for RTTs in Wasm. + +GB: It was OFR who originally raised this GC question as well. And yeah. + +OFR: Maybe I think you're right actually. So I think a reference count works here as well. But the weakness might have another advantage. Because actually, if we don't have the weakness, then if you like basically if you have one worker keeping the source and the module life and then or like basically if I send you a if I send you a source module and then you import it and then you don't need it anymore, but I still keep the source reference alive, then you also need to keep your module alive. Because I can still send it to you and then you have to import it and you're not allowed to run the code a second time. So basically one worker still using the module source will cause all the other workers to not be able to collect the module. So I think the weakness still has advantages. + +KM: All right. I guess on that, I suppose yeah, I see what you're saying kind of I have to think about it a little bit more. And I'm very “jet-lagged”. So I'm sure I'm not going to go over the very good solution. But it seems like there might be a solution in the form of like some sort of weak map from the source to the module in each record. And then the weak map record of the like the module source tracks it, if that makes sense, right? But like each agent has a weak map of the module source. To a module run. And so the actual module underlying backing modules can only die when the actual source dies. In your agent. + +GB: That's what's currently specified. + +KM: Okay. So I think that does that solve your problem then? I don't know if I explained that very well. Sorry. + +GB: So yeah. + +OFR: Sorry. So basically the thing that can happen is that we have that we have four objects, right? We have two workers. Each of them have a source module and the module. So it's four modules. And four objects in total. And then one worker stops using it. The other worker still keeps using the module. And that in turn keeps alive the source, right? Or just the worker keeps using this or keeps the source alive. And that causes the other worker to keep to have to keep its source alive because it could always be that it gets back the same source and then it has to instantiate the same module. And so if we make it weak per worker, then in that case, they can still individually decide, okay, I don't need it anymore. I can collect my module. That's the difference. + +RPR: I see. + +MAH: I don't actually understand why we keep talking about the module source here. Didn't we say that the only thing that matters is actually that module identity object? For the source, you don't need to keep the whole source around. Like you just need to keep the identity around to know if you've if that worker has seen it or not. + +GB: So the current. + +GB: There's no and that's what the presentation was saying, right? The module source object the one visible to user code is not is different no matter what. So even if you transfer it multiple times. + +GB: So the module source object is I guess the only way you get a handle to identity. And so if there's no module source objects in the local thread referencing the identity and you can clear it. But I guess the question there and maybe this is a question for implementers is whether the module source would be kept alive while there are artefacts of the module still executing. And how we define that reference to the module identity. That's something that might have to come from some level of implementation experience. As well. + +MAH: Yeah. So the reason I raised that is probably also related to RGN's point that's coming up. So I don't want to encroach too much on it. But I don't see why we need to collect module identity at all ever. It doesn't seem like an expensive as you mentioned, it can just be a UID. It's just like something you can keep around and in the storage of the worker. + +GB: We're talking about specifically the collection of the map from the module to the source. The instance for that source modules import, which is a distinct map from the URL map. And that's the one that is defined to be weak on the ID. + +MAH: I see. I see. Okay. Understood. + +GB: Unfortunately, I'm going to have to cut the queue short here. Can we just put this current queue on ice and I will just work through the second PR? And then we can continue discussion at the end and maybe it'll give some time to digest some of these concepts as well. All right. + +GB: Just quickly moving on to the second PR. And this is also a prerequisite to the weak identity. Which is non-injective source imports. I haven't presented this before because in previous discussions, it felt a little bit off-topic, but now it is very relevant in this discussion. So this was this is also kind of a little bit of a strange semantic that as I'm faced imports currently specifies. Which was the idea that when you transfer something to the worker and then you import it's you kind of expect that if you import the URL, you should still get that same module. And so the only way that we knew how to define this originally was via basically an injection from the source registry to the URL registry. Which obviously removes the weak aspect. And but it just seemed like… + +MM: What do you mean by what do you mean by injection? + +GB: I think I'm going to go into it in more detail. Let me finish the slides, and then I will-- we can do questions again after this one. So but if you do it in the reverse order, so if inside of the worker you first import that URL, you're going to initiate the loading pipeline. Sending out to the network to fetch the module. And you're going to get a module. Instance for that URL. But then if the same module was posted from a different thread, after you'd already imported it would not coalesce in the instance registry. So you would not have the same module. And this is kind of a strange situation because depending on the order, if you import first the one that's transferred and then the URL, it's defined itself under the URL that it came with because it carried its URL in its serialized data. But if you do it the other way around, it's not injected. And so you just had what was already loaded. + +GB: So there's kind of some non-determinism here or rather ordering so the reason for this is that we wanted to draw the equivalence of transferring a module that it should also be available at that URL. But and we did this by injecting into the URL a registry when there was not a URL already defined in the registry for that import. But it's order dependent. It only works for the top level import and not dependency. And it turns off the ability to do the GC stuff we just discussed. + +GB: And so the second PR that I have up is removing this URL injection behaviour. It's currently defined as a host requirement. And we just remove that host requirement. And that turns the source registry back into just being the straight weak registry. Under this, if you transfer a module and then after importing it, you import it from its URL, you're not going to get that same source coalescing across agents. But actually, with the current identity machinery, we actually now have a way to express that this could be made to work. So I've posted an issue for this. Formally speaking, this would be part of the HTML semantics and not TC39 semantics. Because of the nature of the division between what's in HTML and what's in ECMA 262. + +GB: But basically, you can say that with even without transferring a module identity, you could allow module identity to be treated as shared state again, I've said here within the agent cluster, but that I'll add the refinement for that. And you could upfront associate if you're able to communicate module identity earlier in the loading pipeline, it would be possible actually to have full coalescence of identity in this way. Because we formally have now defined identity and defined what it means to share identity. And this could be another way that identity could be associated. And as I say, this is for the HTML spec, not ECMA 262. But it's a really important design aspect that deeply affects module declarations as well. Because what it would mean is also so basically, with both of the two PRs that I presented today, this would be something that could be done in HTML. We're not deciding either way today, but it would be possible under this module identity model. + +GB: And with that model, you could actually just say that if you import the URL, you're going to get the same underlying module because you have we can know that they have the same underlying source identity based on sharing the source identity information in the background between these two, between these two separate agents. And that is then not order dependent. So you can import the source first and then the URL, you could import the URL and then the source and we would know that it's the same underlying identity. And the same would work for module declarations and also dependencies of module declarations. So for module declarations importing from a URL, you post the module declaration, you import the module declaration, and then you import the URL of the dependency of the module declaration, you're going to get full identity sharing, which is something we originally in the very early discussions it seemed very difficult to specify. But it's something that could fall out of this identity model. + +GB: Further, but it would need more work on the HTML side. So the next discussion there, that's the normative topics and then it'll be the actual seeking consensus on the normative items. So that's the main bit. + +RPR: So we only have 13 minutes. Would you like to resume the old queue or take new questions? There has not been any additions. + +GB: Yeah, let's pick up from the old queue with the extra context. Yeah. + +RPR: So I think that's KM next. + +KM: I don't know. Just didn't answer my question or not. But I think the fact that there is the actual source instantiation and that instantiation can refer to these creating possible cycles amongst itself, that might because the source I don't know if this is the source also then have to keep the module alive. I think that would then create backlinks to the instance yeah, to the instance from the shared ref counted source. So I think you would need a GC to actually collect these and I was wrong. That you could do with reference counting. I mean, you might be able to do it with a reference counted check cycles. + +KM: Still, which I mean, it's just basically a GC in and of itself. But I think it effectively requires a GC. Not necessarily a blocker, but yeah. + +GB: Formally under the weak registry semantic, so I guess there's two things that we're talking about from a GC perspective. The actual module source itself, as well as the instance and so just to clarify, are you talking about the GC of the source or the GC of the instance? + +KM: The GC of the source, which I mean, I guess, is now tied to the GC of the instance, right? Because I think we're saying that they're tied together. So because they're tied together, specifically from the source to the instance, then I think that entails that you can now have to handle cycles, right? Because your instances can point to each other and your instances can only and your sources maybe I'm wrong, but it seems like there's cycles. I don't know. I haven't thought hard enough about it. But I think for now, we should maybe just assume it's a GC. I don't know if we should we're not talking about it. + +GB: I appreciate you thinking about it. This is exactly the sort of contribution that's great. But just to caveat that from the original discussion, with the weak registry model, the source instancing is a local instancing model entirely. The new injective behaviour is talking about the URL registry where once you've imported a URL, it's always rooted in that URL key. And we're just allowing coalescence of the URL registry with the weak source registry. So we're sidestepping all of the GC stuff by just saying it's the weakness is thread local weakness. + +RPR: OFR? Ollie? + +OFR: I don't know. What this was referring to. But I think there was a question why would we ah, yeah, Matthew said why would we ever want to collect this identity? But I think you already mentioned that. Basically, as long as the identity is here, you can recreate the module without running the module code. So it's observable. So basically, having the identity reachable is what keeps the module itself alive. Yeah. + +RPR: Back to Keith. + +KM: Yeah. Also, even if it were just is that feedback from us or someone unmuted? Anyway, I think even if it were just the UUIDs, I think it's probably a poor form on our part to create non-lexical leaks of data. At least with modules themselves, the data is constrained by lexically what you have in your program. But I think it will probably be able to you can I mean, I guess you can eval more modules or something potentially actually, maybe you can't until this is the only way you can actually create modules dynamically at runtime. And so you might be able to dynamically leak. + +GB: Yeah, the path. And I think we would like to avoid that as a language design. Sorry. Eval of a module expression, if we supported module expressions, would be a path to constructing a structured clone is another way to create copies of source modules. Module source. Although they would share identity and do this. Is that just to try and understand your point further, Keith, are you saying that you have concerns with the global identity model so far as there is this yeah, maybe you can just clarify that. Maybe I didn't follow it all correctly. + +KM: Ah, sorry. I was replying to the… this is an outdated reply with OFR was also replying to MAH of saying leaking the identities is maybe okay because leaking a UUID. But I think it's one thing to leak something lexically effectively where it's a lexical thing in your program and you can't keep recreating them dynamically. It's probably worse that it's substantially worse to have that for something that is dynamic. + +GB: Got it. Thank you. + +RPR: RGN? + +RGN: Yeah. I'm thinking about the non-determinism inherent to GC and wondering whether you're intending the internal weak map to be subject to that because it seems like it's going to be a much worse experience if sometimes a collectible module source has been collected and sometimes it has not been. And wondering instead if we're wanting weak semantics that we might actually go farther than we usually go and _require_ collection, which obviously is easier if we're doing reference counting, but that way at least we get predictable behaviour. + +GB: Yeah, I'm hesitant to require collection, but I hear your concern. I think for implementations, most modules are not weak. So especially if we can do the URL coalescing stuff, the URL is still a way to root a module. And then you would avoid that case. But yeah, I don't know. I think the URL registry is the place where well-defined teardown could be defined. But yeah, I'd be hesitant to state that there should be deterministic properties here. I think just not relying on the fact that because there's only applies across transfer, right? So within a specific agent, you're only going to see this from the perspective of new transfers. And so whoever's orchestrating the transfer can make sure that they're holding within each agent what needs to be held. + +RGN: But the hazard I'm talking about is genuine in what's being proposed here, right? + +GB: That there's observable GC non-determinism. Yes. You're correct. + +RPR: Okay. Less than five minutes remaining. Three people on the queue. Matthew? + +MAH: Yeah, I think that answered my question. I wasn't sure I understood the weak semantics, but that's why I wanted to reseat that slide. But my concern is exactly the same as RGN's. If this is basically allowing user code to observe GC without the explicit weak ref and finalization registry power, that seems very dangerous. + +RPR: MM? + +MM: I pass. I don't need to ask this in real time. + +RPR: And KM? + +KM: I guess there's two parts of this. One is yeah, I'm very hesitant to mandate reference counting for things. I think that is just limits implementations in ways that I don't know that we really want to. And I also think that you're kind of stuck with GC anyway because the module itself, the fact that the instance is itself a GC object, and then it has the thing and it points to the reference counted data. And so you're not guaranteed the instance has the GC behaviour. And so therefore, the source has to have the GC behaviour. I think also a good example of this scenario kind of already exists with WebAssembly not instances modules, but `WebAssembly.compile`, you can post message those to other threads. And they have a GC wrapper on them in both threads. And I don't think it's been overwhelmingly problematic that those get garbage collected. In terms of determinism or anything. I've never seen anybody complain about it anyway. + +RGN: Okay. Well, setting aside the WebAssembly, which I'm not sure is subject to the same hazard. Being stuck with GC is not the concern. Being stuck with GC where sometimes you get one behaviour and sometimes you get another, based on the same source code, is the hazard that I'm concerned with. + +GB: I appreciate that. + +RPR: Two minutes left. + +GB: Yeah. + +GB: In the name of time, I'd like to just suggest a path forward from here. What I'm hearing is that there I haven't heard any major concerns with this concept of a global identity. And I think so Niccolo has reviewed the PR and we would like to be able to move forward with the identity model. But the concern that I'm hearing is the non-determinism from a GC perspective. And I agree that that is something that we should talk more about, but I don't want to rush that today. So what I would like to suggest is that we bring forward the module source identity PR for approval, but leave out the non-injective source imports one because if we retain source import injection they would always be rooted and they would be no non-deterministic GC behaviour. So we could get consensus on the global identity without the non-determinism. I believe. So if that sounds like a viable path to be able to at least make incremental progress today, unless anyone has any concerns about that. + +RPR: So MM says, "Please bring back to TG3." OFR? + +OFR: Yeah. I have a bit of a worry that down the line, the weakness will be a-- really will be a required thing. Where. Commented otherwise. So I'm a bit worried by this idea. I would have hoped that we can kind of agree that this is the goal. Especially also because the injection thing itself is actually also something that worries me for various reasons. So I was actually happy that it's being removed. So yeah. + +RPR: And then KM then asked 30 seconds. + +KM: Okay. I'll be quick. Yeah, I think there's already discussions, I think, around having global GCs in implementations for limited census for WASM. But none of that has finalized in any way. So I don't know that engines can certainly, if this proposal actually does require a global GC, I don't know that implement I guess we always speak for myself. JC can't, but I will I'm sorry. I think many other my understanding is other engines also would have not yet concluded fully that they want a global GC yet. And so if it requires that, then that might be a blocker. Going forward. + +RPR: Okay. So we're at the end of the time box. GB, would you like to just say a closing statement on where we've got to? + +GB: Sure. Yeah. I would like to see if I could seek consensus for the module source record global identity. If anyone wants to make an objection to this based on the GC non-determinism and the weak registry still being worked out, I will immediately accept that. But I will do all the follow-up discussions. So if one person wants to chime with an objection or otherwise, I will move straight to the summary. + +RPR: Okay. You've got a OFR, you've got plus one on this. End of message. And MAH, is this an objection? Okay. MAH says, "I like the identity concerned about weak non-determinism." And then from KM, is this an objection? + +KM: No objection. I just if I'm correct that it requires a global GC, I think that there's a chance that that may stall you in some ways. But I certainly think that this is the right way, assuming we have it. And it requires it, I suppose. + +GB: Okay. I will skip the other item assuming there are no objections. I will note that we are agreed with the overall direction of a global module identity. With the caveat that we still need to further work through the story around weak source registries and cross-agent GC or local non-determinism of the GC. And I will follow up on those topics appropriately. And I've noted Mark, Keith, and Ali's feedback. Thanks for the extra time. And I will end it there. + +RPR: Thank you, GB. Please do write the stand because I think this has been a nuanced conclusion. + +GB: Okay. I'll check that out. Thanks. + +### Speaker's Summary of Key Points + +* Presented normative PRs 63 and 62 +* PR 63 introduces global module identity to allow cross-agent source equivalence relations +* PR 62 stops module source imports defining their URL key into the module registry on import, which is non-deterministic + +### Conclusion + +* In discussion on global GC, it was determined that while it isn’t fully ruled out, it also can’t be assumed, aligning with the assumptions of the PRs as presented. +* Concerns were brought up though about the non-determinism of having local GC being observable via instance side effects due to module source transfer +* Approval was obtained for PR 63 defining global module identity, but without enabling the weak source registry for now. Further discussion will be followed-up separately with respect to these cross-agent GC semantics. + +## Reworking Cover and Supplemental Grammars + +Presenter: Mikhail Barash (MBH) + +* [proposal](https://mikbar-uib.github.io/ecma262/spec/cover-grammar/) +* [slides](https://docs.google.com/presentation/d/1cB-HL6pob5tHBJu4BCEv57d4BdJDP1oXO62Eb-ALVHo/edit?usp=sharing) + +RPR: Thank you. Okay. So we're running a little bit behind. We'll go to MBH with introducing the reworking cover and supplemental grammars. + +MBH: Okay. I would like to start with a recap of what cover grammars are. I would do it using this example. When we have an expression of this form, do we know whether this is a parenthesized expression or a parameter list of an arrow function? And we cannot know this unless we look at the token that will appear after the closing parenthesis. So if we use naive rules, this will mean that it's impossible for us to choose which rule to apply with only finite look-ahead. So for as a solution currently, the spec has cover grammars where for the two cases, which we are to disambiguate, we will introduce this cover nonterminal. That would accept both of the possible cases and potentially even more. And then later, when certain conditions are met, whatever this means, we will be able to reinterpret the cover non-terminal as either a parenthesized expression or an or as an arrow formal parameters. So this phrase here, “if certain conditions are met”, apparently this is not explicit what those conditions are in the specification, but an analysis of the rest of the grammar would give us an understanding that in this case, a certain token should not follow the closing parenthesis and in this case, a certain token should follow the closing parenthesis. And again, this is just an example of one cover grammar that the spec has. The spec has more than this. But I hope this is enough of a recap of what we are talking about. So the problem that the cover grammars are trying to solve is this one: how to select a correct rule to parse. And as we established, one approach is to use cover grammars, and one other possible approach is to use grammars with unbounded look-ahead. And that is what I will be talking about in today's presentation. + +MBH: I would like to mention that the first two items here are on specification-level. And implementations are free to implement the specification any way they want. The specification does not need to prescribe an implementation strategy. I will be talking more about this later. This is a summary of cover and supplemental grammars currently in the specification. So the first three here, I would call them explicit cover non-terminals. And then we have three implicit ones that are only serving as cover grammar in certain cases. + +MBH: I would also like to mention that this one, the third one from top, is a part of the living document, not yet of the specification document. So it's supposed to appear in the next release. And as we can see, the relevant sections in the specification where the cover grammars appear, those relevant sections are spread all across the document. I tried to map how this actually works in the spec. And what's essentially we can see from this informal graph is that the non-terminals and the rules of the cover grammar, they tie together different and sometimes even unrelated parts of the core grammar. And they do so in an entangled manner. I'm not going to try to explain every detail of this graph, though. But you can have an impression that it's not easy to understand what is going on with the cover grammars. + +MBH: We can identify issues with cover grammars. Mainly, it's reduced readability and writability of the specification. Reduced readability requires to basically read all of the mentions of a cover non-terminal to understand which cases it actually disambiguates. And there is no explicit explanation of how exactly it disambiguates those cases. Supplemental syntax appears arbitrarily far from the grammar rules that it affects. And the spec has vague formulations like under certain circumstances and so on. So similarly, this leads to reduced writability of the specification. And maybe one point I would like to particularly highlight here is that any modification of the grammar may introduce conflicts with the existing cover grammar. + +MBH: The goals of reworking the cover grammars are to improve readability and writability of the specification, and to enable a succinct specification of the grammar. We want to remove the supplemental syntax clauses. We want to reduce the amount of early errors clauses. And we also would like the grammar specification to be sort of self-contained or self-containable. In addition, we want to have some mechanized processing of a grammar which will enable us to establish correctness of the grammar and other properties of interest. + +MBH: Before explaining the approach that I have in mind, I just want to show you the before and after diagram. This is just a graph from before, the same topology, but just with removed non-terminal names. You can see that there are these edges across multiple different nodes. And what I want to have is something like this where thing is isolated. So each non-terminal can be read in isolation from the rest of the grammar. Let me show you an example of what I have in mind. So this is the current specification. We have this arrow parameters that can cover parenthesized expression and arrow parameter list. Okay. So this is a cover non-terminal and then somewhere else we have to sort of scroll to see that when processing an instance of this production, the interpretation of the cover non-terminal is refined using a different rule. And then in addition, we have the early errors which also says that this cover non-terminal must cover the really desired non-terminal. + +MBH: So this is a suggestion of how this would look like. Again, this is just a mathematical notation which I in a couple of slides will be reworked into a spec-friendly notation. So when we have here is that arrow parameters now can be arrow formal parameters, but only under the assumption that the look ahead can be parsed as arrow formal parameters. And an ensurer, which basically is the original cover non-terminal. And then we have this explicit disambiguator symbol that will tell us that this arrow formal parameters is actually the rule that we want here. + +MBH: The highlighted parts starting with this restriction here and this one and this one, they are of the same nature. These are some sort of restrictions on grammar rules. So if I read this rule again, ArrowParameters I want it to be ArrowFormalParameters, which is directly coming from the cover grammar from the supplemental syntax. And then I have this assumption, which is comprised of the original cover non-terminal and the disambiguator. And this now is explicit in the specification. This is how it would look like with the complete example. And just modifying this notation I would use a restriction of the form “assume” in front of the non-terminal that I want to have this non-terminal to be parsed as. So combining the two cases for this particular cover grammar non-terminal, in the original specification, this is now like that. + +MBH: We have primary expression which can be this cover non-terminal or arrow parameters which can be this cover non-terminal. And then supplemental syntax and early errors elsewhere in the specification. And if we use the suggested approach, then we have primary expression which is a parenthesized expression assuming that we have this primary assuming we have the parenthesized expression. And sure, and arrow parameters is arrow formal parameters assuming we have arrow formal parameters. And this ensures the same with the only difference of the disambiguator that this is not arrow and this is an arrow. + +MBH: I have reworked all the specification using this suggested approach. All of the supplemental syntax clauses, of which there are seven, they have been reworked. And also all the “must cover” phrases have been reworked. And current work in progress is reworking all the “covered by” phrases and fixing static semantics related to the rules which will be removed as a result of such a reworking. Let me briefly show the draft of the specification. So just as an example, let me just maybe show this one. Primary expression is now parenthesized expression which comes directly from the supplemental syntax. And then we have this assumption of applicability of this rule, which essentially is the look-ahead that we require here to be positive. And the look ahead itself is comprised, as I mentioned, of the original cover non-terminal and the disambiguator. As I mentioned, I've just only shown one example, but this has been done for all of the relevant cases in the specification. + +MBH: Now we have a detangled grammar where we can read a particular part of the specification without having to analyse where that cover non-terminal actually appears in other cases to fully understand what the disambiguators in the cases would be. I have presented this to the editor group in the beginning of September. And there were two questions that I asked. The first one: “is there a problem worth solving with respect to cover grammars and their readability and writability”, and the editor's position was “yes”. And the second question was: “is the suggested approach a feasible improvement for the described problem”? And the editor's position was also “yes”. + +MBH: The suggested specification changes are surgical. From the perspective of a specification reader or specification author, the underlying core grammar formalism remains the same. And we can establish the equivalence of the cover grammar approach and the suggested approach. Here is an outline of that equivalence argument. So whenever I have two cases, which I want to disambiguate, and the first one uses some X and the second one uses Y, then I would introduce this cover X and Y, and supplemental syntax and “must cover” phrases and “covered by” phrases. And in the suggested approach, I would still keep the X and Y in those two cases that I want to disambiguate. And I would add here assume XEnsurer and assume YEnsurer. And the XEnsurer and the YEnsurer, they would have this cover the original cover non-terminal and then the disambiguator for the X case and disambiguator for the Y case, respectively. The envelope here is essentially the original cover non-terminal. So to compare the cover grammars and the suggested approach, disambiguators are now explicit, cover non-terminal is required in both cases, but it probably could be a bit relaxed in the suggested approach. Importantly, the prose in the specification now is not required. The specification becomes completely declarative. And the last one is an argument about improved readability of the specification. + +RPR: So sorry, just point of order. Did the fuzziness on the is there any way to improve teams presentation quality? Okay. Please carry on. + +MBH: Yeah. Right. So if you think about how this could be incorporated into the current specification, then this could be either just syntactic sugar over the cover grammars, so this would be a specification level operation that results in cover non-terminals. Or, this could be an approach where a new grammar formalism would be defined and the spec would be free of any mention of the cover non-terminals. Even though these two approaches look distinct, they are both a notational change, because we can transform any of this to the original cover grammars as we have them now. So there are questions here about the existing implementations and how they implement cover grammars. I'll have a couple of slides about that later. And also a question about spec tooling compatibility if there are some tools that use the current approach of cover grammars in the specification to mechanically process the grammar, how this would affect them. We could think about the notation of the suggested formalism. I'm probably not going to go now through all of the points here, I just want to summarize the discussion from the editor call that a notation which is similar to what the spec already uses would be preferred. And something that is easily typable for grammarkdown. So this is the notation that I have currently been using. + +MBH: So we have this “assume” restriction in front of the rule. And if we have multiple restrictions, this is also possible. Even though currently this only appears in one case in the entire reworked grammar. This could be called as grammar assumptions. Talking about the implementations, I had a look into how the major engines and some others implement cover grammars. But I'm more sure about the engines that I presented here on the slide, in terms of how they handle cover non-terminals. So for this one, cover parentheses expression and error parameter list. And for the second one, call expression and async arrow head. There are basically two approaches roughly: either do re-parsing as the specification prescribes or parse the cover and then reuse the already obtained abstract syntax tree to transform it into a particular case depending on certain conditions. + +MBH: Well, there are certain conditions, I am essentially picking what is the next symbol in the input. For the third non-terminal here, an AwaitExpression and an AwaitUsingDeclarationHead, none of the engines presented on the slide essentially uses cover grammars. They just use lookaheads instead. And then for this, as I call it, implicit cover non-terminal LeftHandSideExpression, some of the engines use the approach that is similar to what I suggest. Meaning that they have some kind of unbounded lookahead if the left hand side is of a certain form and if there is this symbol that follows then perform that and that parsing. So if I were to summarize the findings from the previous two slides, then the implementations do use disambiguators which are currently implicit in the specification and I would like to suggest to have them explicit. This cover non-terminal is implemented by a lookahead. So essentially there is no cover grammar in the implementations. And for the left hand side expression, some of the engines use some sort of unbounded lookahead. So all of these are similar to how the suggested approach models these cases. Again, this is a summary. So for the first two: if the cover is followed by an arrow vs. if the cover is not followed by an arrow. The implementation essentially is directly the same. And then we have a similar specification in the suggested approach where we can explicitly see whether some disambiguator follows or not follows. For this one, this is almost the same. We need to have a look ahead. And then check whether we have an identifier after the keywords await using. And that's very similar to the suggested approach. And finally, for LeftHandSideExpression, there are many cases. I just give one example in some implementations. There is this: if the left hand side is of a certain shape, then select a particular rule. And that's exactly what again happens in the suggested approach. + +MBH: This is just some relevant discussions about cover grammars from previous meetings and other sources. I'm not going to go into them now. And I would like to summarize the suggested approach. Essentially, it is the same as the current approach. One can think about it as just another notation for the cover and supplemental grammars with improved readability and writability. Because we have the cover and the supplemental syntax now written together. And we have explicitly the disambiguator in each of the cases. The last point on this slide basically says that this is a sound grammar formalism with parsing algorithms, but this is irrelevant for our goal of reworking the spec as of now. So there is some more work to do here, to make sure that all of the “covered by” phrases can be safely removed and all of the static semantics can be modified and I'm currently working on those. + +MBH: So I would like to ask the committee the first question: “is there a problem worth solving with respect to cover grammars and their readability and writability”? I'm not sure what's the best way to do it. + +RPR: Do you like a poll? Or should we first of all start with some discussion? Maybe we could start some discussion. So you've built up quite a queue. WH has several questions to go into. Just having a look at that queue, do you want to go into that or should we try and shift? + +MBH: Well, maybe first question we could try to handle right now because it's independent on the solution. + +RPR: Please go ahead, WH. + +WH: Are you talking about the first question (Q1) on the slide or are you talking about my first queue item? + +MBH: I'm talking about the first question on the slide. Okay, sorry. I misinterpreted. So basically maybe we could ask if anyone objects to the fact that there is a problem worth solving. + +RPR: Looks like CM is going on the queue. MF says, I support this. End of message. Several people are typing. RGN says, plus one to improving cover grammars. And WH says, WH, would you like to talk about yours? + +WH: This question is too vague. Yes, cover grammars are annoying. But whether it's worth replacing them depends on what you're replacing them with. So I don't know how to answer Q1 in the abstract. + +RPR: Wait, it sounds like you're allowing the possibility that there might be something improved. + +WH: Yes, I'm definitely open to the possibility that there might be something better. + +RPR: MF? + +MF: Maybe we can just instead ask for an acknowledgement that there are usability issues from both the spec reader's perspectives and from delegates who author proposals when it comes to cover grammars. Can we ask for feedback on that statement? + +RPR: Should we start this with a poll then? Because I think you've rephrased the ask. + +MF: Well, I understand what WH is saying about this particular thing on the slide is it implies a particular solution—that you can't really answer it without a solution. But I think the thing that I just stated does not imply a solution. It's just acknowledging that we think cover grammars are not a great solution for our consumers. + +RPR: Okay, so can we acknowledge that cover grammars are not a great solution to our? + +MF: I don't want to step on MBH toes, but that was my suggestion. + +RPR: So you're happy with that, MBH? Okay, and RGN also agrees with MF wordings? I think WH you want to go into more details before answering that question? + +WH: Yes, the things I'm going to present might affect what folks’ positions on this question are. + +RPR: Okay. Well, just before we go into that, let's just read out the quick replies from other people. So CM says, without taking a position on the particulars, I want to applaud the effort to remove hair from the spec. + +RPR: And RKG says, agree that there is a problem worth solving. All right, are you happy to go through WH's details? + +RPR: All right. Please go ahead, WH. + +WH: Okay. I looked through this proposal quite carefully. As background for those of you who don't know, I originally came up with a lot of the formalisms that we use in the grammar. I'm the most familiar with why they are there and what they do. Before we introduced cover grammars and parameterized productions, I machine-validated how they would behave and what they're there for. And cover grammars are there for a specific reason, which was not in this presentation. So that's the background. + +WH: My first item is that, as a spec, we have a choice of either specifying the behaviour or specifying a particular parsing implement parsing strategy to get that behaviour. It's not a really strong feeling, but my preference is to keep the spec in the form of specifying the behaviour, not which parsing algorithm you should use to get to it. For grammars, there are a variety of parsing algorithms. This proposal mixes the two concerns. For disambiguation, it has both disambiguators in the grammar and as the explicit disambiguators. And those actually disagree with each other. This is a source of bugs—having two things in the spec which can get out of sync with each other. It's not a big deal, but I'm not really a fan of that. Next as I'm talking, can you go to the proposed spec and scroll to the AssignmentExpression rule? + +WH: My remaining four points are big ones. They are crucial. + +WH: For the 30 plus years that we've been doing this, we've had grammar invariants, which are there for readability. There are specific things which we choose not to do because they would be extremely damaging to readability. One of those things, which has occasionally come up before, is having negative rules: either negative parsing rules or ordered parsing rules, which are a form of negative parsing rules. The grammar as we have it now, with one exception which I will get into in a moment, has only positive rules. That is wonderful for readability and maintainability. If you only have positive rules, then when you extend a rule to cover something which is currently invalid syntax, when you add more options to a rule, then if the grammar still compiles, then you know that what you have is a purely additive change. As soon as you introduce negative rules, all of that breaks. To give a simple example, if you have a production which expands either to non-terminal A or, if A didn’t parse, to non-terminal B, that might seem like a nice shortcut, but it's toxic in the future to anybody who comes after you and tries to maintain it. If somebody later wants to extend A to cover something else, they might silently change the behaviour of something completely different in the spec. In fact, it's possible to even add new productions which take things which were valid parses before and turn them into SyntaxError. This is so toxic to maintainability and readability that over the 30 years we've resisted any attempts to have negative rules except for one. + +WH: The one negative rule we have is for optional semicolons. This has caused endless problems over the years. We have to support it because that's web reality. But everywhere in the grammar where you see \[no LineTerminator here], that's someone disambiguating something which broke because of that one negative rule we have in the grammar. Now, the optional semicolons we have can only happen at line breaks. So you can fix breakages caused by that one negative rule by adding no \[no LineTerminator here] constraints. But the proposed negative rule formalism would not apply only at line breaks, so it's not fixable that way. I see that as a dealbreaker. + +WH: The next item is behaviour changes. This proposal is not an editorial change. At the moment it makes significant changes to how ECMAScript behaves. I tried comparing this with the existing grammar and there are all kinds of places where this will just behave differently from our existing behaviour. So, as it is now, this is not an editorial change. And it completely neglects things such as \[no LineTerminator here]. There are other places I can't figure out what it’s trying to do. + +WH: The next item is: the presentation asserted that the new formalism is equivalent to the prior formalism, but I do not see how that’s true. I can see how to map cover grammars to the new formalism. I do not see how to map the new formalism to cover grammars. For example \[referring to the proposed new AssignmentExpression rule], here we have an AssignmentExpression where the first constraint is \[ assume not ArrowParameters => ]. I don't know how to map that to a cover grammar. That part of it just does not make sense. Maybe I'm missing something, but the claim was made of equivalence, and I don’t see how in the formalism as it's presented. + +WH: The final item is the biggest one and deals with what a spec is. A grammar spec must, at a minimum, regardless of what sequence of characters you provide as the input, either tell you a parse or say that that’s a syntax error. Furthermore, there must be a way to machine-prove that it does one of those two things for every possible input. + +WH: The way I've done this when I created the formalisms is as follows. The main syntactic grammar is an LR(1) grammar, a deterministic context-free grammar, which drives the choice of whether / is interpreted as a start of a regular expression or as a division symbol. You can only do this lookahead one token at a time. You cannot lex the following token until you’ve parsed the previous one. This behaviour of / is the reason that we have cover grammars in the language, and it's fundamental. I can feed the main syntactic grammar into a deterministic context free grammar generator. If there are no bugs in the spec, it will generate a state machine. Once you have such a state machine, you can verify that for each possible grammar state (there will be a few thousand of them), that you never have a state in which you have both a regular expression and a division as possible sequels. If you ever do, that is a spec bug. This is the formalism that we've been using for close to three decades and I’ve done the validations when we created the formalisms. Also, to make the spec valid you must have additional constraints as to how \[no LineTerminator here] behaves, which I won’t get into because they are technical, but the new formalism does not recognize them. You must also ensure that anything that a cover grammar elaborates into is a subset of that cover grammar. If it's not, it's also a spec bug. + +WH: To summarize. 1: You can generate an LR(1) grammar for the entire language. 2: That grammar is unambiguous—it compiles. 3: For every state in that grammar, you can never have both division and a regular expression as successor states. 4: Every elaborated cover grammar is a subset of the cover grammar it elaborates. Those form the formalism of the language; you use the top-level LR(1) grammar to drive the lexer. For what's being proposed none of that works. This is not even a spec at this point because I cannot get to step 1. I cannot generate an LR(1) grammar or any deterministic context-free grammar for the entire language in the formalism as presented. In fact, you can see in the production here that it wouldn't work because \[ assume not ArrowParameters => ] allows both division and regular expression. So this is just inherently broken. There is no way for a lexer to get going. This also contains intersections of deterministic context-free grammar. Per computer science theory, deterministic context-free grammars are not closed under intersection. So you can't do that to get something which is a top-level deterministic context-free grammar for the purpose of disambiguating division versus regular expression. + +WH: So those are my concerns. There may be ways to resolve some of them, but they are crucial. + +RPR: RGN has a reply. + +RGN: I might have been misunderstanding what Waldemar claimed, but I don't believe that the full language is LR(1). In |ForInOfStatement| we have at least two-token lookahead: `for` `(` negative-lookahead `let` `[`. Similarly, for checking async of: `for` `(` negative-lookahead `let` or `async` `of`. + +WH: Yes. I'm aware of those. However, there is a theorem which says that an LR(2) grammar is LR(1). + +RGN: If we're going to say that it's LR(k), then fine. The significance of the number is indicating the need for look ahead. If we want to say it's just LR, that's also fine. But I think claiming LR(1) is misleading given the grammar that we have defined. + +WH: Those are all deterministic context-free grammars. You can say “deterministic context-free grammar” instead of “LR(1)” if you want—they’re equivalent. + +RGN: All right. Understood. + +WH: On the other hand, the intersection of two deterministic context-free grammars, which is what the new formalism uses, is not a deterministic context-free grammar. + +MBH: Yeah. That is absolutely correct. And I have this slide now that very briefly talks about the parsing algorithms for these formalism. Of course, it defines languages beyond context free and I yeah, you have made many good points. I have to read the notes carefully to go through them. And if possible, I would love to talk to you about this and you know offline and because I have some other ideas and yeah, I would appreciate your feedback on those. + +WH: Sure, I'd love to chat more about this. + +RPR: Yeah. So in the matrix, MF has written up his reframed question. + +MF: I mean, again, just a suggestion. I don't want to step on MBH’s toes, but like that's my point of view of like where I see the value of this. And it's a suggestion. + +RPR: I don't see the reformulation. Yeah. Should I-- I'll read it as so this is just MF's suggestion when we haven't decided if we're going with it, but it's: is our current usage of cover grammars causing readability, writeability, implementability difficulties worth investigation and potential churn? In particular, consider the lack of explicit disambiguators, shown to be needed by all implementers, the non-locality of the grammar and its dependence on early error prose rather than being self-contained. WH has thoughts. Please go ahead, WH. + +WH: Yes, I share the pain. I hate cover grammars. They're kind of a necessary evil. Some of these, I think, could be done well using spec tooling. And one of the things which I'm thinking of doing is reworking my dusty grammar validator into something that can be run by folks. It will take me a while to do that, but that would definitely help. + +WH: On the other hand, cover grammars also indicate that you're doing something which you really ought to think twice about whether you should be doing. They signal places in the language where, if you choose to proceed, you’re creating serious technical debt and will have issues with evolving or adding syntax in the future. So I think the difficulty of creating new cover grammars from scratch is not necessarily a bad thing because I don't want to see more of them. + +RPR: MF. + +MF: I don't know if I fully understood that. Are you suggesting the formalism that MBH is proposing is the formalism that could appear in the spec as long as the way that we author it is using cover grammars? So that we are using a restricted formalism in our authorship so that we don't use the full power of this new one. And then we allow readers and implementers to consume the preferred formalism? + +RPR: WH. + +WH: Yes, that would be wonderful. The thing I care about is that we have an unambiguous spec that's evolvable and maintainable. Any reading aids which make the grammar easier to read would be great. + +MBH: So do I understand correctly that you, WH, are fine with this approach that is on the left? Where this would be just a syntactic sugar that will produce cover grammars? + +WH: I would rather go the other way where cover grammars produce this since that's much easier to reason about. What I don't want to do is to make it too easy to create new cover grammars because that causes maintainability problems down the line. + +MF: Sorry. I do feel that a solution like this would only be solving half of the problem, albeit the more important half in my opinion. It's better than nothing. I mean, we'll still have to fully discover the ramifications of it as we try to implement this. But my view of it now is that it will be better than not doing it. I'd rather solve half the problem than not do it at all. + +WH: What is the other half of the problem that this would not be solving? + +MF: Authorship would still be challenging. Really anything that touches the grammar for most champions requires a lot of assistance. + +WH: Yeah. I'm thinking of doing tooling in the long term which might help with that. + +MBH: But so WH, could you please summarize what you would be fine with? So how would that look like? + +WH: I don't understand the question. + +MBH: Well, you mentioned— + +WH: We have a huge space of possibilities. + +MBH: Well, when I mentioned this box on the left, that it would be a spec level operation that would produce cover grammars. And you mentioned that you would rather prefer the other way around. Could you elaborate how this spec text would look like? Would it still use cover grammars? And then we'll produce this formalism with like there will be like two formalisms or I'm not sure. I'm confused. + +WH: I feel like we'd be trying to design a formalism live in this meeting which I don't think would be a great use of our plenary time here. + +MBH: Well, I would like to repeat that I would like to talk to you about this. And see where we can go. Yeah. Thank you. + +RPR: MF. + +MF: Yeah. I think that it would seem like we now really understand the stakeholders in this and this would benefit from having out-of-plenary discussion where we can nail down the details. So WH, if you can, reach out to us and we can set something up. I think that'd be great. Possibly with the whole editor group, but at least between you and MBH to get things started. And then including the editor group. + +WH: Sure; I can do that in November. + +MF: Okay. Thank you. + +RPR: Thank you. Okay. Great. Thank you, Waldemar. So the action is with you to set up the meeting with Michael and maybe afterwards with the editor group. + +WH: Yes. I'm looking forward to this. + +RPR: Thank you. MBH, is there more you would like to get from this session? + +MBH: I guess that's it. + +### Speaker's Summary of Key Points + +* Presented an approach to rework cover and supplemental grammars that is based on grammars with unbounded look-ahead, with the goal of improving readability and writability of the spec. +* The approach was presented during the editor call on 2026-09-03, and the editors' positions are: (1) “Is there a problem worth solving with respect to cover grammars and their readability / writability?” Editors’ position: “Yes.” (2) “Is the suggested approach a feasible improvement for the described problem?” Editors’ position: “Yes.” + +### Conclusion + +* During the plenary presentation today, several delegates expressed support for the suggested approach, and there were some objections from one of the delegates. We will work together to try to refine/modify the suggested approach, in order to be able to present it at a later plenary meeting. + +## Continuation: structured TC39 data status update + +Presenter: Michael Ficarra (MF) + +* [slides](https://docs.google.com/presentation/d/1Qr0soLiTxn6od612KAnkDttMDhyS1BBRmFjmd9ken8Q) + +RPR: Yeah. Thank you. Okay. Thank you. All right. So that's been a deep dive. We only now have 10 minutes before lunch. CDA, did you want to do the agenda deadline during that time or should we try and go for a continuation? + +RPR: Continuation. Okay. So continuation is possible. MF, did you want to try and do the data one, the TC9 data status? You have 10 minutes or rather than the 15 requested. Okay. You've got 10 minutes then. Yeah. + +MF: Okay. So I think we had a fairly productive discussion when we talked about this last time. And I think we're just nearing the end of it. So on the first point, I believe we did reach consensus for recognizing those four inactive stages and possibly following up later with actually getting to our ideal. On the second point, I don't think there was any feedback. On the third point, I have some action items to connect with current, active delegates about any name changes that affect them. On the fourth point, we need to wait until we have some chair support for our new processes. So I think we only had to talk about this fifth point right now, which is something that CDA had requested at the last presentation at the July plenary. In the original presentation, I had suggested that we would have potentially better interfaces to all of our data. And CDA said that there might be some concerns from some delegates about exposing their affiliation information. So this is just that your name and your company are listed next to each other, while you are assigned as a delegate for that company. I wanted to get any feedback if anybody does have such a concern. And we can go to the queue. + +RPR: Hi. Okay. Let's go to the queue then. So KM. You're sorry. KM, you're on the queue with isn't the question about if anyone would be uncomfortable or. + +KM: Oh, okay. Yeah. I just made it back in. Sorry. + +KM: … But I think there was a question before yesterday about asking in the room if anybody would be uncomfortable. Like, with this answer. But I mean, in theory, we're answering the question for future delegates, which we can't answer accurately. But I think if it's being published anyway, maybe that's kind of a moot point. So I don't know. + +MF: The distinction there would be that for future delegates, we could make this notice clear at the time that they're onboarded. Whereas for current delegates, that was not already done. + +CDA: + +CDA: I don't have concerns because JHD is—very sorry to mention you, but JHD is very publicly available on the Internet. As am I. So I don't have concerns for me personally. I have concerns on behalf of those who are not so public. And so this isn't like a blocker by any stretch of the imagination. I just want to make sure that we're doing it very deliberately and I would sympathize with concerns of individuals that are a little bit more uncomfortable with that. In the same breath, I don't want to speculate that, an imagine that there's concerns that don't exist. But I just wanted to raise the point. + +JHD: Yeah. And to clarify, I'm not saying the question shouldn't be asked. I'm saying that I would be very interested to hear why like, as you said, you talked about discoverability. I think (the data) will be surfaced. I don't think that it's not I think it's 100 percent discoverable already in the age of AI. So I would love to understand someone's concerns about this, if they have them. Like, in other words, I would love to hear about some data that this would actually newly make available. + +CDA: Right. I agree with your perspective. And I don't think it's helpful for us to imagine things that might not be there. But it is helpful to consider things that may be there and raise them in case delegates do have those types of concerns. MF. + +MF: For some reason, actually, the reply button isn't there for me. So maybe this is a TCQ bug. Or maybe the chairs haven't advanced things properly. We'll find that out. But to JHD's point on "you can use AI to find them", part of the original delegate cleaning process, I was trying to find somebody's full name or something like that. I was trying to do that and I used a number of techniques, which were not successful, including many AI tools. And then I remembered (where to look). And it was there. So, I think, CDA does have a point that it really is just not discoverable today. But I'm still personally of the opinion that all the work we do is very public and it's hard to square that circle for me. + +RPR: Okay. We only really have about one minute left. So could we have some quick replies? You're not looking for a consensus here. This is. + +MF: I do eventually want to get to the point where we can do something like this, but that is not an urgent thing. So we can revisit this in future meetings. + +RPR: Okay. JHD. You're you're you're your topic is I think you may have already said it. Note that if your GitHub TC39 org membership is made public, you get PR previews on spec PRs automatically. + +JHD: Oh, yeah. That was from last time. Yeah. So the that was just saying there's a benefit to making your GitHub org membership public. Yeah. But the other thought I just had, which doesn't have to be answered right now, is we had a big thing about how all of our technical content has to be public as a result of export controls and stuff. Does that not also require the national affiliation and thus no human identity of all of us to be public? No? Okay. Yes. So it's-- I'm saying it's worth having a lawyer answer that question because that might be relevant here. + +RPR: So Samina, could answer that? + +SHN: I don't 100 percent know the answer, but I mean, sorry that I don't have the answer. But the question was repeat the question again. Sorry. Just tell me just say that question. + +JHD: Just so as a result of some countries being on lists where we can't work with them, then the exceptions are as I understand it, are that this sort of interoperable technical work, as long as everything's public, is fine. So is the question that does our identities and national affiliations have to be public as well? + +SHN: Definitely affiliations, because I know that you don't want anybody bilateral conversation. You need to have it in a group for certain affiliations, certain organizations. From certain regions. That's definitely a legal practice that I see in many SDOs. We have never had a hardcore statement in ECMA. We just follow that as best practice. But I think I want to take this away and try to get some clarity from some legal advice on this. So make sure we're in the right way. + +RPR: Thank you. All right. Final 30 seconds for RBR. + +RBR: I would like to have a different topic than what we've spoken so far about, which was more of the personality's perspective on if they want to be represented in public. Like, being committee representing the language I believe it is also very positive in fact to have a transparency of who represents that. Because it is a public thing that and, this represents the language, in a way. And I believe it is very helpful for people, external people, to have easy access to know who is moving this forward or not. Okay. And sorry, I yeah, I skipped CDA. So CDA. + +CDA: I know we're eating into lunchtime. No pun intended. I just wanted to express that any substantive change to a name in the delegates file and what I mean by substantive is not changing Dan to Daniel or Chris to Christopher or adding F. to Shane Carr. But substantive change to names in delegates the text felt I say should, but I feel more strongly I think it must be accompanied by a scrub of references in TC39 repositories. I do not want to see a change in delegates of a significant name change where we are preserving their dead name in repositories that that doesn't mean that it must happen at the same time, but certainly that needs to be recorded as a follow-up action maybe not an issues because that might be a little bit too visible. But yeah. We should make sure we're doing our due diligence for those sorts of changes before committing. + +RPR: All right. So we'll wrap up there. Apologies for going slightly into to lunch. We will resume at one 1:00 PM. And just before you go, I'll remind everyone that we in the room, at least, we have the opportunity to attend the Sony tour I'm told it's very good. People come from far and wide to go on this tour. That's at 4:00 PM. So we'll be we'll be leaving really on time for that. And if you want to register for that, because there's still places available in our Tokyo Matrix room, you can find the pinned post is a poll. And you just you do your emoji poll there. To secure your slot. We're at the moment we're up to roughly 16 15 or 16 people. We've got 20 slots. All right. Please enjoy lunch. + +MM: Can I just ask a quick question with regard to that very last point? + +RPR: I think we are on lunch, but. Oh, yeah. Go ahead, Mark. + +MM: Okay. So I very much sympathize with the desire to scrub dead names, but so much of our work is in Git. And. Right. The whole so I don't even understand technically how that would work. + +CDA: Sorry. What you don't understand how technically how what would work? No, I heard him. I want him to elaborate. Sorry. Go ahead. + +MM: To remove dead names from the existing public material. I mean, the public material is in Git. + +CDA: Right. + +MM: As far as I how would you change the history? + +CDA: We do a find and replace and create a pull request and ask the individual to approve it. We've done it before. + +MM: In other words, you wouldn't erase the history. + +CDA: Yeah. Yeah. Yeah. We're not rewriting the Git history. Reference. + +MM: Yeah. We don't rewrite history. If somebody wanted to go to Okay. Commit hash from 10 years ago, they would see the dead name. + +JHD: if it's very important for somebody to keep their previous name and new names connection secret, then I assume that what they would do is the old name would leave the committee and the new name would join the committee and we would just not acknowledge the connection. + +MM: Okay. I understand. + +JHD: I haven't seen that being typical a typical ask. + +MM: Okay. I misunderstood. I thought we were applying it to history. Okay. I understand. + +CDA: No, we're not yeah. But what Jordan had just mentioned is unprecedented. But if we did have a situation like that, maybe we would do that. Maybe we would do something else. I don't know. We would work with the individual to come to a solution that is amenable for for for them. + +MM: Okay. Great. + +CDA: All right. See you. Oh, we're seven minutes past. All right. See everybody here in 52 minutes. + +### Speaker's Summary of Key Points + +* Earlier discussion reached agreement on recognizing four inactive proposal stages, with further refinement possible later. +* Follow-up with active delegates about name changes remains outstanding, and new processes await chair support. +* Feedback was sought on making delegates' names and company affiliations easier to access through improved interfaces to TC39 data. + +### Conclusion + +* Improved access to delegate affiliations remains open for future discussion; no decision was taken. +* SHN will seek legal advice on whether export-control rules require delegates' identities and affiliations to be public. +* Substantive delegate name changes should include follow-up updates to references across TC39 repositories, with the affected individual's approval and discreet tracking. + +## Async iterators: the whole proposal + open questions + +Presenter: Kevin Gibbons (KG) + +* [proposal](https://github.com/tc39/proposal-async-iterator-helpers) +* [slides-1](https://docs.google.com/presentation/d/19xEFe4rHPDxpX_ai7dXrYY3wNtgwcsaKV25PwZiml54/edit?usp=sharing), [slides-2](https://docs.google.com/presentation/d/1FfYbAJ2pElLQPqn32ZvgtuTQzEWU_79ZjKMs--k1CMY/edit?usp=sharing) + +KG: Hello all. I have been trying to work on having my time boxes be adequately sized and based on how this conversation went last time we are signed up for two hours. No guarantees that we will actually require the whole two hours. On the other hand, if that's how the conversation goes, that's how it's going to go. So last time I presented this, I talked about a bunch of open issues, a couple of which we've resolved then or since. I will have more open issues in a separate presentation, which I'll get to after this one. But because it is my hope that we can resolve the outstanding major open questions during this meeting, the next thing that will happen after that is I will very painfully write some spec text and ask for people to review that spec text and come back for stage 2.7. Probably not by the next meeting, just based on the amount of work that it's going to require, but that's my hope. And given the scope of the proposal and the number of different individual decisions that have gone into all of the various parts, I wanted to make sure that the committee knows what you are going to be signing up for, knows what you'll be agreeing to, when this does come for advancement. And I want to make sure we're all on board with it before I go to all of the effort to write all of the spec text and come back for advancement. So before I get to the larger list of open questions, I wanted to just go through the entire proposal. Everything that's in it and all of—not all of, but some of the fiddly little details in the various parts of it to make sure that we're all on board with it. + +KG: Okay. Without further ado, there it is. That's the whole proposal. End of slides. No, of course not. + +KG: So I'm not going to read off this list, but I'll be going through all of the parts of it. Basically, it's the helper methods that were originally in iterator helpers as well as `Iterator.prototype.toAsync` and `AsyncIterator.prototype.buffered`. Each of which I'll be talking about in a minute. I am in particular not proposing to include stuff like zip or chunks or windows or concat or join, the follow-up things that we've added to `Iterator.prototype` since this proposal began. Just because I don't want the scope of the proposal to creep. So it's just the things that basically have been in here from the beginning. It's roughly speaking the array methods that make sense, except with take and drop in place of splice. And no `at` and no `findLast` or those sorts of things that don't make sense. So I'm not including the other things we've done since then. I do intend to come back with a follow-up, or a variety of follow-ups for things like zip, some of those are actually a little bit non-trivial in terms of making the implementation support concurrency, but I'm just not going to think too hard about those problems right now. Because I don't think they affect anything that's actually in the proposal. And I think that they all have basically one or a small number of possible semantics that will make sense. We just have to work through what those should be and, again, I'm not doing so now. Okay. So let's get into the meat of the proposal. I'm just going to go through everything that's in it and talk about what it is and if I think there's anything that's a decision that I have made that someone could disagree with. + +KG: So AsyncIterator is a new global. Not really anything to it. This only exists so you can do `class extends AsyncIterator` and so you can do `AsyncIterator.from`. It's technically constructable so that it can be used as a superclass, but you can't construct it directly. Only via `super` or something like `super`. It's basically exactly the same as Iterator. + +KG: So AsyncIterator, pretty straightforward. `AsyncIterator.from` is a static method for converting three different things—or arguably four—to valid async iterators, valid meaning inheriting from `AsyncIterator.prototype`. So it can take a sync or an async iterable or an iterator. If the thing that it is given already inherits from `AsyncIterator.prototype`, then it just returns that. If it is given something that is an async iterable, then it invokes `Symbol.asyncIterator` and if the result inherits from `AsyncIterator.prototype`, then it just returns that. Otherwise, it wraps it. The wrapper is on the next slide. For synchronous iterables, we need to lift Iterator to an async iterator. So basically, a Promise of an iterator result. This is the same way that `for await` over a synchronous iterable works. It's a little bit non-trivial to figure out how you want to do that with a bare iterator. If you just are given an object with a next method, you don't actually know if that's supposed to be async or not. That's one of the open questions. + +KG: We also have this not exposed new global, which I know people are sometimes worried about not exposed new globals, but this is just exactly the same as for iterator helpers. It's just the place that all of the `next` and `return` methods live or rather, there is just one next and return method for all of the helpers and there's just one class and they dispatched all of them. So instead of having a separate map iterator, async map iterator helper, and async filter iterator helper, and so on, we just have one set of methods that just checks an internal slot and then dispatches to the appropriate implementation. Again, this is just pretty much exactly like iterator helpers. And just like iterator helpers, we also have this wrapper that I talked about with `.from`. When it needs to wrap something to ensure that it has the right prototype, there's this not directly exposed new intrinsic that handles that. And again, open question exactly how this should work, which we'll get to in a second. Okay. Then we have the sort of boilerplate we always have, `.constructor` and Symbol ToStringTag. No real questions about those. Also, `AsyncIterator.prototype`. `Symbol.asyncDispose` already exists. And just invokes `.return` if it's present. So we're not adding that, but it is something that already exists. + +KG: Okay. Then we have the core three methods, the things that have been taking all of the time, which is map, filter, and flatMap. And they constitute almost all of the complexity of the proposal. We've talked about these a lot. We're going to talk about them a little more in the open questions. So I'm not going to talk about them more. Because I've done them to death. + +KG: There is a caveat on flatMap, which I haven't emphasized previously, but flatMap supports concurrency, but the concurrency being driven by the consumer just invoking dot next repeatedly is only able to get concurrency from the most recent inner iterator. It is not able to get concurrency from the underlying iterator. It's a little bit unfortunate, but there's no good way to avoid that problem without making the API shape more complex in a way I really don't want to do. Anyway, you can sort of fake it if you do this slightly awkward idiom here, because the `buffered` helper drives the underlying iterator concurrently, if you want to have concurrency in underlying iterator, you can just map over it and then do buffered and then do a flatMap to flatten the results. And then you get concurrency both with the underlying iterator and the inner iterators. + +KG: Okay. Then we have the obvious consuming methods. `some`, `every`, `find`, `forEach`, `toArray`. These consume the whole thing, return a Promise, take an asynchronous function, in the case of `some` `every` `find` and `forEach`. They don't have any built-in concurrency. There is a follow-on. The concurrency control proposal would allow passing a second argument to these, which would allow specifying a degree of concurrency or some more complex way of getting concurrency in these. An open question is whether we should reserve that second parameter or not. If we do the thing that we normally do, we just ignore any additional argument and assume that no one will be passing anything. And then at some later time, if people start passing the concurrency argument, if they are on an older implementation, they just don't get concurrency, which depending on your perspective, is either very bad because the program is silently slower or totally fine because the program has exactly the same behaviour that it otherwise does. So the open question is, do we throw if someone provides a second argument to these things? Or a first argument in the case of `toArray`? I see MF is on the queue, so since we've got a lot more things and I don't want to lose the context for this, MF, do you want to say your topic now? + +MF: I haven't thought about this any more than during the time that you were presenting it, but yeah, it seems to me that it is a good idea to reserve this spot. I know that's not a typical thing we do, but at least I feel pretty confident that if we're going to go forward with concurrency control, we're going to want to be able to pass that concurrency parameter there. And I also know that concurrency control is an earlier stage proposal at the moment, but that's only really because it's been sitting behind this one. I think it would have proceeded further if it was not blocked in that way. So because of those reasons, I think it makes sense to reserve this position. + +KG: What do you think about the argument that if we simply don't reserve it, then new code will work on old runtimes just fine? It'll just not get the concurrency? And so it's kind of unfortunate to make the new code throw on old runtimes if it doesn't have to. + +MF: Again, I hadn't thought about this topic any more than during the time that you were presenting it. So consider it a weakly held opinion and I could be swayed by things like that. I'm not sure. I'd have to think about it more. + +KG: Okay. Well, I will pick an answer to this by the next time I come back. + +KG: Okay. Moving on. `reduce`. It's also a consumer. Unlike the methods in the last slide, there's not really any obvious way to add concurrency. Reduce is ordered and each invocation depends on the result of the previous invocation. So it's sort of inherently sequential. So I don't think there's any open question here. We just simply are not going to have concurrency. I do want to call out that like with iterator helpers, this differs from the array prototype `reduce` in that it is not passed to the collection. So it will only be passed to the accumulator the value and the index. For arrays, the callback is passed a fourth argument, which is the array itself. That's not really useful for iterators because you can't index the iterator. So it's only passed to those three things. + +KG: `take` and `drop`. These are iterator-specific methods. They match the iterator version in that they don't actually do anything when invoked. They just give you immediately a wrapped result and so for drop, when you call `next` the very first time, it immediately does the dropping. There's an open question. Which is for drop, we could in principle invoke `next` many times or the number of times that the method calls for. So if you do `.drop(5)`, and then you call `next`, we could immediately do five invocations of `next`, or rather six invocations, because five of them are going to be dropped and then one of them will be the result, without waiting for the previous Promises to settle. I have this listed as an open question. I feel moderately strongly that the right answer is that we shouldn't do that. We should wait for each Promise to settle before invoking `next` again. This follows a loosely held feeling or principle that we should not cause there to be concurrency unless the user does something which asks for concurrency, such as invoking the `buffered` method. That said, 99% of the time that I invoke this, I'm going to want to have the immediate behaviour—well, not 99% of the time, but much of the time. So perhaps it would make sense to have a Boolean parameter for opting into this more aggressive concurrent dropping. Anyway, I have it listed as an open question, but unless someone feels strongly my intention is to just do it in the boring sequential way. Where we wait for each Promise before invoking the next one. + +KG: Okay. `buffered`. This one is the thing that is unique to async iterators. This one takes an argument that is the size of the buffer and it keeps an internal buffer of that many Promises pulled concurrently from the underlying iterator. So when you first iterate over the iterator produced by `buffered`, when you first invoke `next`, it will pull n + 1 Promises from the underlying thing concurrently. The whole point of this—well, not the whole point, but the main use of this is it does that concurrently so that it can drive concurrency in things like `map` and `filter`. And then it just holds them in the internal buffer and runs them in the original in the order in which they were produced from the underlying thing, regardless of whether later ones have settled or anything like that. There is a point where this could have been done in a different way, which is that as I've done this, invoking `buffered` doesn't do anything immediately. It only does the calls to the underlying `next` method on the first call to the result iterator. So you can construct your whole pipeline and it won't actually start buffering until you consume from the pipeline. I think that's definitely the right default behaviour. It is moderately annoying that you can't start buffering before you start consuming the pipeline. Often, when you are buffering, the whole point is that you want to be getting the work ready so that when you actually get around to consuming it's already available. And that doesn't work if you don't have eager buffering. So maybe there should be an option to opt into it. It's moderately annoying to implement this yourself. I'm not really sure if I'm going to add that as a Boolean parameter or not. Leading weekly towards yes, just because of how annoying it is to do without support in the language. And it doesn't add very much complexity. + +KG: Right. So this is the only way that will be built into the proposal to get concurrency from things like `map`. We spent all this time talking about how it's nice to make map concurrent or support concurrency. The concurrency has to be driven by the consumer. There's not very many things that consume async iterators in the language. And none of the existing ones and none of the things like `some` and `every` will be concurrent by default. So if you want to have concurrency, what you have to do is put buffered on the end. And then do one of the non-concurrent things and then you will get the concurrency from the buffered method. This also allows you to be concurrent between the async iterator and the thing that is consuming the async iterator. The most obvious example is just if you're doing a `for await` over an async iterator. Without the buffered method, then the order goes that you pull from the async iterator, you wait for that to settle, then you enter the body of the loop, you wait for all of the work in the body of the loop to complete, and then you do another pull from the async iterator. So the loop is never running concurrently with a pull from the async iterator. With `buffered`, even a buffer size of one, you can be doing the pull from the underlying iterator at the same time that you're doing the body of the loop. So it's a very useful convenience method. But in addition it is the only way that you get concurrency right now. + +KG: Okay. `toAsync`, is on `Iterator.prototype`, it's the only thing added to `Iterator.prototype`, and it's basically just a convenient way to get from a synchronous iterator to an asynchronous iterator. You could generally just do `AsyncIterator.from` and pass the iterator. That would work as well. I think it's nice to have the `toAsync` method. Something that is true of all of these things that turn a synchronous iterator or iterable into an async iterator is that they do actually have some special handling for synchronous underlying iterators, which is that if the iterator gives you a `done: true` result, then that can resolve immediately even if you are blocked, even if earlier calls to `.next` are still waiting for a Promise rendered by the iterator to settle. So in this example here, you have an array with two Promises which haven't yet settled. You get an iterator of the array and call toAsync. And then pull from that three times. The third one can resolve immediately with `done: true` because you know at that point that the underlying iterator has only two values, even though the values themselves are not yet observable to the consumer of the async iterator because the consumer of the async iterator needs to wait for the Promises to settle. This is especially useful if you're doing flatMap for reasons I'm not going to get into. But it's not a completely trivial wrapper. In particular, this isn't how the spec native wrap-sync-for-async-iterator thing works. But we are not going to use that built-in because that is only intended for use with `for await of` and is not user exposed and we really don't want to make it user exposed because then users can mess with it and that can break a `for await` loop. So `toAsync` is going to be its own thing. All right. + +KG: So what's left to do. There's open questions, which we'll get to in the next presentation. And spec text, which is going to be a lot. I apologize. I think flatMap is going to be the most complicated algorithm in the spec by a factor of three approximately at least. There's nothing that even comes close to this. Sorry. When you start doing things with concurrency, they get complicated. But that is why this has been taking so long. The spec text is going to take me quite a while to write, which is why I can't promise that I'm going to come back with it at the next meeting. Also, after that, of course, we'll have to do tests. There will be hundreds of these. I already have hundreds of these. But of course, that doesn't have to happen before stage 2.7. And then I will eventually be asking for consensus. + +KG: For stage 2.7, I will need reviewers. So I would like to invite people to sign up to be reviewers. There are technically people listed as reviewers, but I don't think they signed up for the proposal in its current form. So I don't think I'm going to subject the people who previously signed up to this. But I'd love it if we could have people sign up to review some moderately annoying concurrency code. I will make it as easy for you as I can. I’m going to give a minute in case people want to volunteer. Otherwise, I'll circle back to this. But I want to wait at least a little to see if, for example, MF wants to volunteer. + +JHD: I can be a reviewer as well. + +RBR: I can also be a reviewer. + +KG: Excellent. All right. Thank you both. Okay. So I do want to talk briefly about future work that I am not going to put in this proposal, that I want to do in later proposals. Or I want other people to do, in some cases. This is mostly just because I think it is useful to have a sense of what the world will look like when we are done with this particular questline. So concurrency control, which I mentioned before. This is a proposal that will provide ways of limiting concurrency or driving things like `AsyncIterator.prototype.something` concurrently. I think it'll be very useful. That also is kind of gated on the AbortController work because some of the concurrency control mechanisms in there really need cancellation. So we have to get cancellation in the language before we can proceed with that proposal. Also, unordered iterator helpers. One of the design principles for this proposal, which again I'll bring up in the next presentation, is that you always get the same results in the same order that you would have originally, with some quibbles; that's not necessarily true if the underlying thing is incoherent in a particular way or if there's races. But apart from that situation, you get the same results in the same order if you pull concurrently or not. I think that is necessary and makes the results easier to reason about. But in a lot of cases, you simply don't care. If you are going to be mapping your results into a set or something afterwards, you don't care about order. Then you can get strictly faster pipelines if you allow results to come in out of order. So the unordered helpers are just a way of doing an unordered map that gives you results as they settle instead of always giving you the first one in line. Also I want to add the other iterator helper methods, zip and so on. And then there's two more, I will have slides about: I think we need to have some mechanism for registering clean-up, and I'd really like to have some way of getting an iterator of Promises to an async iterator by racing. So I'll talk about those very briefly. + +KG: So for clean-up, we have this longstanding problem that async generators have a single queue for calls to `.next` and `.return`. What this means is that if you're iterating over an async generator that is using something like buffered, and you decide that you're done with the async iterator, then you break out of the loop. This invokes `.return`. But the `.return` method doesn't actually run until the current unit of work that you're blocked on in the async generator finishes. So in this example, it needs to complete whatever fetch it's doing before it can call `.return`. This means that you might have hoped that you could just have an AbortController that would cancel the fetch in a finally block and that `.return` when invoked would enter the `finally` block. But it doesn't because of this shared queue. So you have this very longstanding and very annoying problem that you are not really able to exit out of an async generator when it is doing work. So I think the solution to this is to have a way to register behaviour to run on `.return`, behaviour that runs before the underlying `.return` is invoked. In this example, you could have an AbortController that is aborting any work that the async generator or whatever, `asyncIterator.map` or whatever, is doing. So I do think we need this pretty urgently. It comes up a lot as soon as you start doing anything with async iterators. But again, not going to be in v1. + +KG: And then the second thing, this is a little bit orthogonal, but it comes up a lot. If you have a bunch of Promises and you want to do something with all of them, it's really nice to be able to do them to write a `for await` over the Promises. But right now, there's not an easy way to consume all of the Promises as they come in. You can `Promise.race`, but that just gives you the first one. And I have a utility on the slide that is what you would do if you wanted to be able to do `for await` over all of the Promises in the order they come in. This is actually a pretty common thing in other languages. Python has this. C#, Swift. They all have a way to say, I have a collection of futures or Promises or whatever, not an asynchronous collection, a synchronous collection of Promises. And I want to do an async iteration over the results as the results become available. I think this would be really useful, but it isn't necessarily entangled with any of the other things. But I can only champion so many things at once. Okay. That's the whole proposal. Pausing for a minute. Are we all happy with that? If I go forward, assuming we get resolutions to all of the open questions, everyone is excited to approve this and put this in the language. Yes? + +CDA: CHU says yes. + +CDA: ACE also says yes. In a distributed fashion. It's almost too clever. JHD says, not fully convinced of some of the follow-ups, this one seems great. MM and MF support this. And ACE. + +KG: Yes. Unhandled rejections we’ll be getting to in a moment. + +*Switching to [second set of slides](https://docs.google.com/presentation/d/1FfYbAJ2pElLQPqn32ZvgtuTQzEWU_79ZjKMs--k1CMY/)* + +KG: Okay. Great. Thanks very much. That was my first of two presentations. So I hope you are not sick of my voice yet. Now let's get to the open questions. Always the more fun part. Many of these we talked about last time, and came to resolutions or partial resolutions on some of them. I've removed some of the things and also added a couple more. Also, I do want to remind people that I have a demo that is useful for checking out a bunch of these things. So that you can sort of visualize what's happening, which we’ll be doing a couple of times during this presentation. + +KG: Design principles. I have slightly updated the slides since last time. So I'll go through it again. These are things that I'm intending to achieve. We want the result to be order preserving, which is to say it doesn't matter if you are doing things concurrently. You still get the same results in the same order unless the concurrency itself has races. If the things that you are doing concurrently have shared state or something, obviously we can't guarantee order. But assuming that everything is well-behaved, you should get the same results in the same order, no matter what order Promises are settling in. Also, the helper owns its underlying iterator. This mostly just means that it's responsible for invoking `.return()` at the appropriate time. In the case of flatMap, you can own multiple iterators. You have to close all of them. Also, we want to not lose values. I'll get to that a little more on the next slide. And since we do need to be able to reason about the underlying iterator somewhat, we have a constraint on the underlying iterator, which is that if you have a sequence that gives you a `done: true` and then later in that sequence, not necessarily in the sense of the order that Promises settle, but the order in which they were originally vended, if you get a `done: true` and then later in the sequence you get a `done: false`, that's considered incoherent. We have to have some behaviour, but we are not going to try to achieve any particular good behaviour in the sense of not losing values or anything. This only applies to specifically `done: true`. Errors are allowed to precede `done: false` and we're still going to ensure values are not lost in that case. + +KG: So what do I mean by "don't lose values"? Just that if you are managing all of the calls to `.next` yourself, in that case you are guaranteed to see every value produced by the underlying iterator, either as an argument to one of the callbacks or as the result of one of the Promises. In the case of something like `.map`, values are guaranteed to get passed to the mapper function and then the result of the mapper function is guaranteed to be given back to you. Only if you are consuming the calls to `.next` yourself. Obviously if you're doing something like a `for of` over something with a buffer, things that were in that buffer, if you early exit from the loop, are just lost. Including any rejections, if you have a rejected Promise later in the buffer, that's dropped. It's not considered an unhandled Promise rejection in that case. The “don't lose values” principle only applies if you are managing all of the calls to dot next yourself. That said, we don't try to achieve this when the underlying iterator is incoherent. One of the main reasons that we need this incoherency definition is to allow us to not have to try to achieve this principle in that case. Mostly because it would make certain cases much slower than necessary. And I think basically we shouldn't care about this case. Okay. Before I move on, are we happy with these things? Oh, I see MM is on the queue. + +MM: So first of all, I appreciate the definition of coherence and that it's a nice thing to define and expect all of the iterators produced by specified mechanisms to be coherent. What I don't understand is why we need to require the iterators fit into all of this mechanism to be coherent or to put another way, why our guarantees are somehow reduced if they're not coherent. What I would have thought the invariant was is that once an underlying iterator reports done we stop asking. And if we stop asking, as soon as it reports done once, then the fact that it might stop reporting done if we asked again is a non-issue. + +KG: Yes. We talked about this last time. Hopefully, we can illustrate this with a demo. \[summons [demo](https://bakkot.github.io/async-iterator-helpers-implementation/#filter-exhaustion-3)] Okay. So here we're calling `.filter`. Hopefully, we all remember what the demo looks like, but just to recap, we have the underlying iterator that we're pulling from. There's some internal machinery, which is exposed to users, and there's results. So the dot is going to indicate next actions. So let's say we pull from the result. That returns a Promise. It, of course, immediately pulls from the underlying. Then we pull from the result again before the underlying has settled. So now we have two outstanding result Promises. That means we have two outstanding underlying Promises. Proceed a little bit. Let's say the second one happens to settle first. Settles and gets passed to the predicate function. The predicate settles with false. Because that means that value is not going to go into the result, we know that we need to do at least one more pull from the underlying iterator. We immediately do that pull. Okay. Let's say that—so now we have these two outstanding Promises from the underlying iterator. Let's say we then do another pull from the result, which of course triggers another pull from the underlying. So now we have three outstanding Promises from the underlying iterator. Let's say that this box on the third line, that Promise settles with `done: true`. Okay. In this case, what I would like to be able to do is settle these two results on the right-hand side with `done: true`, because we have seen a `done: true` and assuming coherence from the underlying iterator, that means that the underlying iterator contains at most one value that will pass the predicate. We've seen two earlier values. One of them has not passed the predicate. So I would like to say, in this case, there is at most one value that will pass the predicate. And let's say that that one then settles and the predicate settles and we get true. Okay. The problem is we still have this outstanding Promise from the underlying iterator. So what happens? Let's say that this settles with a value. Where does that value go? + +MM: I would say that just drop the value. + +KG: Okay. Great. I agree. That is the answer to your question, though. Because I had a design principle of don't lose values. But you just said, drop the value. My point is that I don't want to try to achieve that when the underlying iterator is incoherent. + +MM: Okay. But that seems like something that you can specify as just what you do when the underlying iterator is incoherent. As opposed to the way you were phrasing it sounded like there was some kind of requirement on the underlying iterator being coherent or something weird would happen. And just dropping values after a done is not that weird. I think that's very easy to explain. So I don't know that introducing the concept of coherence for this purpose is really necessary. It's just the values that you pay attention to are only those up to the first done. + +KG: Sure. You can. I broadly agree. Let's run through [this other case](https://bakkot.github.io/async-iterator-helpers-implementation/#filter-exhaustion-4) and see if that still makes sense to you. So it's basically the same as in the previous one, but now the last two values are going to settle in the opposite order. We get a non-`done: true` value, which passes its predicate. And then subsequently to that, we do want to give this to the predicate function as soon as we can. Subsequently to that, an earlier Promise in the chain settles with done true. + +MM: So the price of this is that you've called the predicate with a value that you don't want to propagate. So even though the predicate says true, I would say as far as the result is concerned, D never happened. + +KG: Okay. Yeah. I agree with that. Okay. There's [one similar example](https://bakkot.github.io/async-iterator-helpers-implementation/#map-exhaustion-2) for map. We could get a `done: true`, which we want to propagate to the result immediately. For filter, the value was just hanging out in the internal machinery. We couldn't do anything with the value until earlier things finished anyway. But for map, in principle, we could. So consider this case. Similarly to filter, we're doing three pulls. Third one settles. Goes into the mapper function. Mapper function settles. I would like to be able to put this value in the result right away. Problem is, what if the earlier pull then gives you `done: true`? + +MM: If you put the value in the result right away, that means that you're producing an incoherent iterator. Are you saying you want to be allowed to produce an incoherent iterator if the underlying iterator is incoherent? + +KG: Yes. I very much want that. Or I would put it a different way. What I want to be able to do is settle this Promise right away. And the cost of that is that if the underlying iterator is incoherent, the result is as well. + +MM: I see. I see. Okay. I understand the motivation. How bad is the penalty if we say that the result iterator must be coherent even if the underlying is incoherent? + +KG: Well, it's pretty bad… + +MM: I see. Okay. Okay. I kind of get it. I mean, no, go ahead. Talk it out. How bad is it? + +KG: So for map, it's maybe not a huge deal because if you're consuming the results of map in order, then you don't super care when this third Promise settles. But consider something like `some`. For `some`, if the third one settles with true, you really want to be able to resolve the whole chain with true. You don't want to have to wait for all of the earlier things to settle. Because you know that you got a result. It's very unfortunate if you have to wait for every earlier Promise in the chain to settle. + +MM: Oh. Oh. Oh, that's very interesting. Ooh. + +JRL: Okay. So I think the open question here is, essentially, what happens when we're incoherent? I have a couple of questions that I really want to answer about this. And one of this is about the first example you showed, but it's no longer presented. So we can just kind of skip it. But it really is the second one. It seems like if we have an incoherent source, then we have an incoherent output. And that seems like the source shouldn't have been incoherent in the first place. That's their fault and not ours. + +KG: That's my opinion. + +JRL: If we have a coherent source, so like a good source, does every async iterator guarantee a coherent output? + +KG: Yes. + +JRL: Okay. Then I'm completely satisfied with that. Just blame it on the input source and they shouldn't have done whatever they did. + +MM: So depending on how bad these cases are, I'm certainly willing to agree to that. But I'm not satisfied yet that that's a forced position. Let's take the case of `some` again. The output of `some` in this case is true. It's not an incoherent output iterator. It's the reason why it's true is due to something that we would have wished to have ignored, but we output the true before we could know we could ignore it. But we're still not outputting incoherence. Map was the only case where we were outputting incoherence, and you already conceded that the cost is not high. + +KG: The cost if you are just iterating over the result of `.map` without concurrency is not high. But consider the case that you do—let's say you `map` with a predicate function. And then you just do a `some` with the identity function. And let's say you do the `some` with a concurrency of 3. In that case, for the thing that is currently on the slide, if we are not allowed to do this, then `some` doesn't get to see this result because none of the Promises returned by `map` can settle. + +MM: So first of all, let me verify. All the cases we were talking to up till now did not involve concurrency in the sense of buffered, correct? + +KG: They all involve concurrency in the sense of you are doing three pulls from the result. If you never have multiple outstanding Promises from the underlying thing, this just doesn't come up. + +MM: You're right. All the cases are concurrency. Okay. Work through this one again. The last example, where it was a composition of multiple things that created a problem, where the individual thing was a map and a some together is, if I recall. Whereas map and some considered individually, neither one of those force us to produce incoherence. + +KG: Yes. So let's consider the case where you are doing a `.map` of a predicate function. And then you are doing a `.some` with the identity function. And concurrency of 3. Okay? Does that make sense? I wish I could write that out. + +MM: That makes sense. I understand that. Good. + +KG: Okay. In that case, if we are forcing `map`’s output to be coherent, then for this thing on the slide right here, we would not be allowed to settle this third Promise. Because we need to wait for the earlier ones to settle. So if this happens to be the value `true`, then what we would like is that `some` settles immediately with `true`. But it can't because it can't see any of these results until all of them are available, basically. If we are forcing coherency. + +MM: Right. But okay. But still, we already granted we were looking at some individually. Oh, I see. Right. The problem isn't that we're producing something incoherent because some just produces a Boolean, which is necessarily not incoherent. The problem is that if map is constrained to only produce coherence, then we're delaying some… what some is producing is, in some sense, wrong, but it's not incoherent. And we're delaying some from producing something wrong early and forcing it to produce something correct later because the intermediate map was coherifying things. + +KG: Well, the result is not necessarily even incorrect, but yes. We are. + +MM: It's potentially incorrect, whereas… + +KG: Potentially incorrect. That's right. Or, well, I honestly don't know. I honestly don't know if I would say that that result is incorrect. + +MM: Okay. If we consider the semantic values of an iterator to only be those that are produced up till the first done, then anything that pays attention to subsequent values are paying attention to values that ideally don't exist. + +MM: So if some is reporting true based on one of those values, then it's true is potentially incorrect. I mean, it's correct according to the spec, but it's incorrect according to the meaning of some. + +RBR: For me? I believe another problem is it's non-deterministic in that case. On one run, it could be true and another case, it could be false. + +RBR: And that's definitely an issue from my perspective. But isn't it about ordered versus unordered iteration kind of how we handle it? And we could give guarantees for ordered iteration. And that's always going to be correct as such because we have to wait. Versus if we say it's unordered, then we don't give this guarantee for this edge case. + +KG: Well, so my preference is to say I don't think we should be forcing anyone to pay a cost. So my problem is not "what do we do in the case of incoherence". My problem is I want to be able to settle this Promise right away. And I don't want to have to pay a cost for this, just to be defensive against this edge case. What I want is—because almost everyone is going to be coherent, I want to be able to assume that they are going to be coherent and produce results under that assumption. And not delay things just in case they were incoherent. Because I think in practice, everything is going to be coherent. And it doesn't make sense to be delaying things just so that we can be coherent even if the underlying thing isn't. + +RBR: So for which operations does this matter? That's `some`, that's `find`, that's anything that produces a single result kind of. Right? But even find does not yet… would also be impacted. + +KG: It also comes up with `find`, yes. It's not just those. It's also pretty much anytime you compose things. So if you compose two `map`s and you pull three times from the result of the thing, the second map, you would like to be able to start doing the work for this value as soon as possible. But you can only do that if the first map is allowed to settle this Promise even while these first two Promises have not settled. + +MM: Okay. Chained map is a very good example. + +RBR: When we look at map, I'm not too sure about it because actually, when we look at just array map, and then you always have the right order. In which it is operated. And as a receiver, I would normally expect to receive the elements in the order of which we received it through a network or whatever it is, right? Even though in theory, it could be received differently. So. + +KG: You'll get the same results in the same order. These are order-preserving. + +RBR: Yeah, but you have a method normally that you call or something like that, right? You do something in between with that value. And you might have a state by yourself that expects it to be in that order or maybe I missed something there. + +KG: Sorry. I haven't understood. + +RBR: So when we receive the value as soon as it's there, to do something with it. Or wait. Let me take this through again. Sorry. + +ACE: The map function itself isn't called ordered, but the resulting iterator will still be ordered. That's what Kevin's showing here. So the resulting iterator preserves the order. But the map, we don't because the map function doesn't rely on the previous one reduce does. We call map eagerly. So here, we're calling map on the third result because that was the third Promise that resolved. And then it's being put into that Promise is now resolved. So. + +RBR: Yeah, exactly. But that's what I would say we should delay kind of until the former ones are there. + +KG: No, no. The whole point of the concurrency model for async iterators if you want that, just don't call `.next` multiple times concurrently. + +MM: Okay. KG, you've talked me into it. Reluctantly. + +KG: Great. + +JRL: Yeah. To reiterate what KG just said at the very end there. If you're using `for await of` or you're doing a normal iterator, then you don't have to worry about any of this. This is literally if you are hand-rolling an async iterator and you do it badly, and then the consumer of that async iterator then calls `.next` manually and they do it multiple times, synchronously. Then we have multiple pulls from that same badly written iterator. And in that case, you can write an incoherent iterator. But I think that's on you and you've made your code bad. If you are pulling from an actual iterator source or an actual async iterator from one of our proposals, you will always have a coherent output. We may optimize and call the mapping function or the some function, the predicate function, early on a case where some later value is early. But it's still going to be a coherent output. And whatever `.next` call that you did or `for await` that you did will be in the exact order that you expect. + +KG: Well, you can get a race for `.some` in this case. The result that you get from `.some` will depend on the order in which things settle if you are feeding it one of these handwritten incoherent iterators. But you are totally correct. The only way to do this is to handwrite it. Nothing in the language and no use of these things will ever give you something incoherent. + +JRL: But from a good source, we will have a consistent deterministic output. And from a good source, we will have optimized results. And if you're consuming even from an incoherent one in a with a `for await`, you'll still get the answer that you expect depending on which one… actually, sorry, I should rephrase that. If you're pulling from a good source with `for await`, you'll get the answer that you expect. And if you're pulling with `for await` from an incoherent source from something that you handwrote and did badly, then you might get a bad result. That seems fine to me. I don't want to hamper the overall performance of this proposal because someone might write bad code. + +KG: Okay. Sounds like we're on board with this. + +JHD: Okay. So first thing is I was under the impression that in sync iterators, if I do map and then filter, that it maps and filters each value as opposed to mapping each value and then filtering each value. Is that incorrect? Is that correct or not? + +KG: You are correct. For sync iterators, you'll generally be doing map and then filter on a value and then map and then filter on the next value. + +JHD: So I'm confused why we can't do that here. Why does some have to wait for all the maps to be done? + +KG: So we can do that. That is what we do if you aren't doing things concurrently. If you are not doing things concurrently. If you just pull one value at a time, and then wait for that Promise to settle, which is how `.some` will work by default, then yeah, that's exactly what happens. + +JHD: So it would short-circuit if the first one returned true. + +KG: Yes. + +JHD: For the `some` condition. + +KG: Yes. + +JHD: Okay. + +KG: The thing that happens, though, is that you want to be able to do things concurrently when you're working with async functions. So you want to be able to pull two values. And in that case, because your mapper functions might be asynchronous, you might have two mapper functions running concurrently before the filter function has been invoked for either. That's kind of the point, is you want to be able to do that. + +JHD: Right. So I hear that. But in the case of some, as soon as any of the pending values would result in a true, then you can… the point of some is to drop all the values and give you a Boolean. So why not do that immediately? + +KG: We would. That's my intent. + +JHD: Even with concurrency. + +KG: Yes. Yes. That's very much how it should work. I agree. The problem is it can only do that if the values are available to it. And if we were not able to resolve this third Promise in that case, then it wouldn't be able to see any of the values. So we wouldn't be able to do that. Which is why I think it's important that we should and everyone seems to now be on board with that. So I want to get to my other questions. + +RBR: Still related. So when we use some, and we receive something that is true, and therefore we settle immediately, do we still look at the former values at all, or do we stop immediately? Because theoretically, what I could also imagine is to have at least a kind of reporting mechanism for misbehaving iterators. + +KG: Right. So I think the only thing we could reasonably do is fire an unhandled rejection event. And we could do that. I kind of don't want to. + +RBR: Yeah. Exactly. Because unhandled rejections, the question is that even really necessary? I believe that would be quite harsh on developers because even the application itself could… yeah, I don't believe most applications would suffer from a misbehaving iterator, really. So I would rather have something else than an unhandled rejection because thinking in Node, for example, this tier is down your application. + +KG: Yeah. There isn't any other channel, though. I don't want to add a new global channel that you can listen to. And there isn't any other one. Once the Promise from `.some` has settled, there's nowhere else to put something. + +CDA: Nothing remains on the queue. + +KG: Okay. Great. Well, I'm glad we resolved that question. Technically, I hadn't even gotten to its slide, but it was an important one to talk about. That was all theoretically a long-winded answer to MM’s question of why I have this notion of incoherence. And that is why I have this notion of incoherence. Okay. + +KG: Let's get to open questions. Another open question. Last time, I talked about the fact that for `filter`, you want to be able to support an async predicate so you want to await the result of the predicate. But most of the time, your predicate function is going to be synchronously returning true or false. So it's kind of unfortunate to pay the cost of an await in that case. And we agreed that we should not pay the cost of an await in that case. That is, we agreed that for `map` and `filter`, if the result is not an object, we should not do an await. This doesn't unleash Zalgo because there's always at least one await in the system. It's just about whether you're doing two or one, basically. Another question is, I realized after that conversation that we could generalize this to non-thenable values. We're going to be looking up the `.then` property to do the await. And we could say, if we don't get a `.then` method, then we don't do the await. I think we should. I think that in general, it's nice to not pay extra in cases that we know we can determine that there's no reason to. This means that the precise number of ticks things will take is a little bit hard to predict. But who cares? There's actually already a bunch of places that diverge in the precise number of ticks things take when you're working with async iterators. And it doesn't matter at all to anyone ever. Yeah. We have a queue. Excellent. + +CDA: RBR says, plus one for fast path for non-thenables. ACE says, plus one reducing unnecessary micro tasks is good. JRL says, support. MF says, support. WH says, plus one. + +MM: I want to understand the Zalgo issue because I think I agree, but I want to make sure. First. In general, anytime the issue has come up of if it's a non-thenable, can we just do it synchronously? We've always answered no, on Zalgo grounds, and the reason and the distinction that you're making is that over here, we're always already protected by a turn boundary. So we're already in a new turn. Whereas in all of the cases where we rejected it, the issue was being in the same turn that has already done other things and for which there's already a call stack above us. In this case, it's a brand-new turn. There's no call stack above us. So there's and that's why there's none of the Zalgo concerns. Is that correct? + +KG: All of that is true. I would phrase it a different way. The thing that is important to me here is that what happens afterwards is only the settling of a Promise. So it is just a question of, do we settle this Promise after waiting an additional tick, or do we settle it right away? But because it's only settling a Promise, that cannot synchronously cause anything else to run. So there is always going to be a pause after this. It's just a question of whether we delay before settling the Promise. I don't think there's ever an issue with settling a Promise sooner than we otherwise would have. + +MM: But this is a thenable. You'll be invoking `then` on a thenable. + +KG: Yes. I'll be invoking `then` on a thenable or not. What we are producing as a result of that is an iterator result, a Promise for an iterator result. + +MM: I think I'm satisfied that there's no problem here. I am satisfied that there's no problem here. + +CDA: LEK is on the queue with support. Sorry, JRL, were you going to say something more? + +JRL: Yeah. I was just going to say we're not vulnerable to Zalgo, but if Mark's satisfied with KG’s answer, then perfect. I'm satisfied. + +CDA: All right. MM is on the queue with support. + +KG: Great. Okay. Let's keep going through this. We just talked about this question of what do we do with incoherence. And I think we all were happy with the answer that we just throw away anything that happens after a `done: true`. And if we can't, then we just have an incoherent result and we don't worry about it. + +KG: Let's get to some of the trickier ones. So we just talked about `map`. For `map`, we are delivering values as fast as we can. This is super useful for a lot of things. We cannot deliver values that quickly for `filter`, because the order matters for `filter`. We can't know where to put this value until all of the earlier things have settled. So we can't do this eager delivery for `filter` no matter what. + +KG: `flatMap` has a more complicated diagram because we have inner iterators. So let me talk through [this example](https://bakkot.github.io/async-iterator-helpers-implementation/#flatmap-delayed-delivery), actually. Let's say we are pulling from the result of flatMap. That will immediately pull from the underlying iterator. Let's say while we are still blocked on that pull, we pull from the result of flatMap again. So you have two outstanding things. This does not trigger another pull from the underlying iterator because each unit of the underlying iterator can give us potentially unboundedly many values in the result. So we just keep a counter internally that says we want two values from the underlying thing, we want two values in the result. Then the underlying thing settles. The thing that we do is invoke the mapper function. But again, just once, and we wait for it to settle. Eventually, it settles. It gives us an async iterator by hypothesis. This is flatMap, so it needs to give us an iterator or an async iterator. Let's say it gives us an async iterator. At that point, we ask for two values from that inner async iterator because we need two values for the result. Let's say the second Promise settles in the result. That value is guaranteed to go into this second slot, assuming coherence, and throughout the rest of this talk I'm going to be assuming coherence. This value is guaranteed to go in the second slot because we can't discard the first value. For flatMap, all of the results go into the output. So the question is, should this immediately settle this result? And it's an amount of bookkeeping to do this. But we totally could. + +KG: There is another case that is slightly more complicated that I want to talk about before we answer that first one because it's even more bookkeeping and potentially you might want your answers to both of these questions to be the same. So let's talk about [the second more complicated case](https://bakkot.github.io/async-iterator-helpers-implementation/#flatmap-delayed-delivery-2). All right. As before, except this time, we're going to pull three times from the result while the underlying one is still waiting. All right, we get the first value from the underlying, we invoke the mapper. Mapper settles. We pull from that mapper three times. Now let us say that the third one settles with `done: true`. So the first mapper result has at most two values. We now know it might have one, it might have two, it might have zero, but it has at most two. In this case, we know we need another value. So we pull from the underlying again. Let's say it settles. It invokes the mapper. That mapper settles. We pull from that. Let's say that gives us a value. In this case, we can't yet deliver this b0 value, because it might be the case that we get an earlier `done: true` from the first underlying iterator. Does that make sense, why we can't deliver this value? Okay. But let's say that we get the second value from this first underlying iterator settled. Now, again, assuming coherence, we know that the first iterator is of length exactly two. We don't have all of the values from it. One of the Promises is still outstanding. But assuming coherence, we know that this thing is of length exactly two. In this case, we could deliver not just a1 as in the previous example, but also b0. So we could deliver both of those to the second and third result boxes while we're still waiting for the very first one to settle. So this is an even-more-bookkeeping version of the question from the one just a second ago. So the question is, should we? + +KG: I did this in my implementation. It adds an amount of work. It's like 50 or 100 lines of JavaScript or something. I forget exactly. I think closer to 50 than 100. It's totally doable. But flatMap is already very complicated. This is making it even more complicated. On the other hand, in some sense, this is the best version of the function, and it seems a shame to put something in the standard library that''s not the best version of itself. What do we think? + +WH: In answer to your question, I think that I like this. My question was slightly different, also regarding flatMap. Let's say that you have a flatMap, and you pull the first 10,000 results. + +KG: OK. You pull many times. + +WH: Yes, you pull 10,000 results. And they all wait for the underlying iterator to generate a nested map. It does. And now the question is, do you immediately pull 10,000 results out of the inner one? Because if the inner one actually has 10,000 things, that's fine. But if the inner one has a length of 1, then you end up turning a linear algorithm into a quadratic one. + +KG: Yes. The answer is yes. You do. You do pull 10,000 times. I agree it has that problem. + +WH: This is kind of annoying. + +KG: Yeah. I think in practice, I expect the degree of concurrency to be small. So even with degree 10, yeah, it's quadratic. But if you end up with 55 or whatever it is. It's just not a big deal. + +KG: You're right to call that out, though. Yes. This does make it quadratic. But quadratic in the degree of concurrency, which I think is in practice small. + +CDA: RBR says plus one on having the optimization. + +MM: So I'm trying to understand the downside is of the optimization. Given that there is a piece of code written by you that you've carefully thought through that everyone else can refer to. So just sort of by rote imitating more lines of code rather than fewer lines of code, I mean, obviously, there's a downside that you had to do the work, but you already did that. And then the other downside, the only other downside that I can see, is less confidence that you got it correct because it's more complicated. And that's kind of through the whole thing. I mean, this stuff is complicated. And in the age of AI and languages like Lean and such, and in the presence of groups like KAIST and the South Korea group that works with us, I would hope that we can formally model and verify enough to get over the lack of confidence caused by the complexity of these algorithms and if we anticipate doing that, I don't see any remaining downsides. + +KG: The downside is just the bookkeeping, as you say. The bookkeeping and the confidence in getting it correct. But I'm pretty sure it's correct. I have spent a truly unreasonable amount of hours staring at this. + +MM: Okay. So yeah. So I'm in favour of the optimization. + +ACE: Just to check my understanding. The amount of bookkeeping, is this just effectively like one thing in an iterator of where in the resulting iterator it can start filling in from? So that's the amount of memory overhead? + +KG: Yes. It's one integer per open inner iterator. Yeah, where you are keeping track of its length, basically, or whether you have established a maximum for its length. Maybe it's a maximum and a minimum. I think you need a minimum. I forget why. Maybe it's just the maximum. Anyway, yes. At most, 2 integers per open inner iterator. + +ACE: Thank you. + +CDA: All right. We still have 35 minutes. + +JRL: So map is able to deliver eagerly, I think we should make the same optimization. And I'll save the rest. So I agree. Yes. Let's do the optimization. + +KG: Okay. + +KM: I don't know if I'm correct here, but maybe you can help me out. It seems like this optimization could be worse in some circumstances. As in, if you're drawing from the original iterator were somehow incredibly expensive, run an LLM request that costs $1,000, then eagerly doing pulling from the source iterator, the underlying iterator, might not be what the user is that accurate, or is there? + +KG: You are thinking of a thing I was not considering to be an open question. I am pretty set on pulling from the iterator as many times as the degree of concurrency you've asked for. You should get the concurrency. The optimization that we're discussing is only about how eagerly we can settle Promises in the result. That's all it is. + +KM: I see. Yeah. I misunderstood. Okay. Yeah. I think that's fair. + +CDA: MF says: "we are in the unfortunate position of absorbing this kind of complexity so that all of our users don't have to. The extra bookkeeping isn't an extraordinary burden or overhead that likely wouldn't pay for itself, so let's do it." + +JRL: I'm sorry. I might have a similar topic to what KM just brought up. How does this interact with a concurrency limit? If I pull 50 times, and that's 50 open things, and we open iterator, and that iterator pulls 50 times, I'm assuming that inner iterator is the thing consuming my concurrency limit, correct? + +KG: There is no concurrency limit on these. + +JRL: Sorry. I know that's a different proposal I guess. Okay. So it's not part of this. And so we shouldn't talk about it. + +KG: It won't even be in the other proposal. `map`, `filter`, and `flatMap` don't have a concurrency limit built in. Even with the other proposal, the concurrency that you get is you asked four or five things. So that is the concurrency that you get. You get degree five concurrency. + +JRL: Okay. And then so it's still me. In WH's case that he was describing where we have an n-squared behaviour, essentially, I pulled 50 times, and then the iterator resolves done true, and then all this other stuff. Assuming a proper iterator, I can assume the remaining three Promises here in A1 are going to resolve to done rather quickly. So it shouldn't remain open Promises forever, right? + +KG: Yes. That will be the case for pretty much everything unless you specifically go out of your way to make it not the case. Also, we're just going to ignore those values even if they do settle. So it's not like they'll affect any other part of the system. + +JRL: Yeah. I don't want to treat these as incoherent or anything. Just assume it's a good operating iterator. I think what will happen is we'll allocate a bunch of Promises, and all those Promises will just resolve to done and then we'll garbage collect those at some point in the future. But eventually, we'll get the 50 things that I actually want out of this flatMap. + +KG: Yes. But at the cost of having done 50 times 49 over two calls, I'm not going to do that in my head. 1200 whatever. Yeah. You've done a bunch of function calls. You've done a quadratic in the degree of concurrency number of function calls. For something that didn't need to be quadratic. But yeah, probably they're all quite cheap. So assuming your degree of concurrency is not very large, the actual overhead is in practice going to be small. + +WH: Could you go back to the [three-element example](https://bakkot.github.io/async-iterator-helpers-implementation/#flatmap-delayed-delivery-2) of A and B? Here you would deliver a1 into the second slot and b0 into the third slot. What happens if the unresolved first A slot then returns done=true? + +KG: Great question. My answer—I guess I should have actually talked about this more. My answer is that we get `done: true` in the first slot. So we just get incoherence in the result. I think we could reasonably put an error there. But I'm choosing not to, basically for the reason that I don't want people to rely on getting errors in the case of incoherence. Because the fact that you got that error is just, you got lucky with the timing. + +WH: Okay. Yeah, that's perfectly reasonable. + +KG: Okay. We're making excellent progress. This is why we had a very long time box. So it sounds like we want to do this optimization. Okay. + +KG: So I brought up this next open question on the slide in the previous presentation. Should we reserve an additional parameter for things like `forEach` and `some`? And by reserve, I mean throw if someone passes a second argument to them, because we think we might want to use that for something else. Michael had a weak preference for yes. I have conflicted feelings about this. So I'm willing to just go along with MF’s opinion if no one else has an opinion. My expectation is that this won't affect anyone before concurrency control ships because you shouldn't be passing a second argument to any of these anyway. Yeah. Does anyone have an opinion about whether we should defensively reserve this second argument? + +JHD: So I'm going to start with the question. You'd mentioned that if we do not reserve the argument, that new code will simply just run quietly on older engines without concurrency, right? + +KG: Correct. + +JHD: Is concurrency the type of feature where it is necessary or is it one where it's fine if you don't get the concurrency you asked for? + +KG: Great question. Depends on the program. You will get the same answer, assuming everything is well-behaved. You'll get the same answer. It's just a matter of, how quickly do you get the answer. So if you were asking for degree four concurrency, and you get no concurrency, your answer is potentially four times slower. But you still get the answer. + +JHD: But given that your answer is “depends on the program”, I assume there may be some programs where failing to include the concurrency would be particularly bad, maybe it might get you rate limited on an API or would crash the program or fill the disk or something. So assuming… + +KG: Those things are very unlikely. It is generally just going to be that your program is slower. The consequence, except in very unusual circumstances, is only going to be that your program is slower. + +JHD: Okay. So I guess that's what I'd say is if there are non-zero programs, where running without the requested concurrency is harmful, then we should throw now. But if, in fact, it's not harmful because I would argue that correct-but-slower on older engines is not a harm, then I think we shouldn't throw now. But I mean, I don't have enough confidence as to whether it's non-zero programs where it would be harmful. But if you're saying that it's never harmful, then I think we shouldn't throw. + +KG: It is certainly possible to construct a case where you will get bad behaviour. Not merely slow programs. I think you kind of have to go out of your way to contrive those cases. But it is possible to contrive a case where you get bad behaviour. + +JHD: Okay. I mean, there's a judgment call, I guess, between how likely we think it is versus how contrived we think that would be. Because I would rather… I would not want to have a world where it silently runs without concurrency and causes harm. That's all. + +ACE: I'm pro not throwing; I also think that concurrency is best-effort at some layer of the tech stack, right? Even if I try and call a million-fetch requests at some layer, either the browser or the network, at some layer, I'm going to be put in a queue. At some point. So I think programs relying on concurrency are kind of asking for problems in general. So I think I agree with what KG is saying. + +MF: On the topic of this potentially causing issues if you request concurrency and don't get it. Wouldn't users be able to get themselves in situations where they have a deadlock? They expect an operation to have a certain level of concurrency and they acquire some limited resource. And then there's no other process that is available to also get— + +KG: It's possible. Yes. I think given how these helpers are, you kind of have to specifically contrive for that to happen. I don't think that will happen in practice. + +MF: Yeah. But ACE was saying that concurrency is a best-effort. And I don't think that it's quite that weak. I think it is stronger in that if we have a task it will be gotten to. We're not allowed to have those tasks forever… I think you know what I'm saying. + +MM: I understand the deadlock case. I certainly understand the slowdown case. But there are a bunch of things said before deadlock came up that I didn't catch, at least. That this no-throw behaviour has potentially bad consequences other than slowdown or deadlock? What are those? + +KG: It’s just if you are designing your program in such a way that it requires this function to be called concurrently with itself. There's a variety of ways that you could construct that if you specifically wanted that to happen. + +MM: Okay. So let's say that that was the case and you have a program that you constructed that way. Obviously, that program can only run correctly on a machine that's up to date with the spec. And if you run it on an earlier machine, then you run it on a machine in which that program cannot run correctly. And the trade-off you're making or the trade-off we're talking about I just want to make sure I understand. The trade-off we're talking about is do you get a clear error signal that your program is not able to run correctly so it's a nice fail stop. You have a diagnostic so you didn't expect it to run correctly. Or do you allow it to run incorrectly? That's the trade-off we're talking about. + +KG: Yes. Well, that is one half of the trade-off. The other half is, all of the programs that don't have this requirement will still run correctly. + +MM: Okay. Okay. Good. So in general, I am on the side of stoppage with diagnostic is better than running incorrectly. I don't find that compelling in this case. In this case, I think not throwing and running with the sequential slowdown is what I would prefer. + +CDA: MF is plus one to MM's comments. + +KG: MF, you've changed your mind? + +MF: Yeah. I think that the arguments here are just not compelling enough for us to diverge from our typical approach. + +JHD: This is not relevant until the concurrency control proposal. But it seems also useful to make sure there's a way to feature detect the existence of the concurrency feature. So that if you do have one of those programs, you can just use that check to make sure it will not run incorrectly. Yeah. + +KG: It might be the case that you can only detect that asynchronously. + +MM: Wait, can't you just feature detect on `buffered`? + +JHD: Well, I don't know what the exact shape would look like. I'm just saying please prepare for me to ask for a synchronous way to detect it in that proposal. + +ACE: I initially also worried this would be like an async feature detection. But it feels like if you have a getter on the `then` I feel like there would be something it wouldn't be like it'd probably be more lines of code than you'd normally do for a feature detection. But maybe like 10 lines of code. + +KG: Yeah. You're totally right. Getters on `.then` would synchronously detect it. + +RBR: Async throwing is not a good idea. However, what I am worried about is developers are often writing code without knowing the consequences in their test sets. They often have very minor sets and they would expect this is totally fine to run. And then they have in production, something where they are starting now a million things at the same time. And causing a big problem on the machine. So what about having a safe default concurrency level which is not ideal for everyone obviously. It's a default. Of, let's say, I don't know, just random number, 100. It's probably too high for somehow ever too low for others. And then the user could overwrite that value as soon as we have the other proposal for defining the concurrency level. Where you could go higher or lower. Because that way, at least in average, I believe we would have bound the problem. And not overwhelmed the machine automatically with a huge concurrency. + +KG: I feel strongly that the only acceptable default concurrency is one. + +RBR: Acceptable! + +KG: Yeah. I don't think we should be providing a default concurrency for any of these. You should only get concurrency if you specifically ask for it. + +MM: Yeah. I'm suddenly confused about the whole question. Given that there's a first proposal that's all of async iteration, all of these helpers, but without concurrency, without concurrency, has no buffered. And makes use of no second parameter on for each. Then there's… + +KG: It does have `buffered`. That’s in the proposal. + +MM: What does `buffered` mean before concurrency? + +KG: Concurrency is in the proposal. + +KG: The thing that is in the proposal is the support for concurrency in map, filter, and flatMap. If you actively drive them concurrently, then they go out of their way to allow you to do so. And `buffered` exists so that you can actively drive those and any other existing async iterators concurrently. + +MM: I'm sorry. So the question that we're examining is only an issue if the version that introduces `buffered`, i.e. the version that's currently in front of us, does not make use of the second parameter. + +KG: Correct. + +MM: What if rather than reserving the second parameter for `forEach`, we just go ahead and make use of it in the way that… + +KG: MM, I've been doing this for like three years. I don't want to make the proposal bigger. I'm sorry. + +MM: Well, but I mean, okay. Okay. So that's fine. I probably agree to that. But let me just make sure I understand. The reason why this reservation is an issue is because we're not proposing it all at once. + +KG: Correct. + +MM: Okay. Okay. Okay. I'm still in favour of not throwing and just letting this slow down happen as the way to cope with the version issue. But this explains to me why the feature test does not testing for the existence of buffered. Okay. Good. Thank you. + +ACE: Technically, even though we split these up, I guess it's still very much in our control how big a window there is between when these things are actually out on the web in a way that people think it's stable enough they can depend on it. I don't know, KG, if that matches or is this follow-on thing actually like years of work? To me, it feels like maybe… + +KG: The follow-on is significantly non-trivial. It's not just about passing a number for these, or at least, we could have a version that only allows passing a number for these, but the thing that MF has been working on is about having more control. And that being able to define things that have concurrency that depends on other parts of the system. And actively varies and stuff. So I think the follow-on is actually pretty large if it's not just the basics. + +ACE: Yeah. Actually, if anything, it being a big period of time, if anything, I think helps people understand that there was a version of this that had some set of features. And then there's a new version of it that has more and will maybe be more aware of being cautious of the not relying on it. So I think everything's fine. I think this is already good. + +KG: Okay. Two hours is not a big enough time box. All right. No, this is great. We've been resolving questions left and right. I am going to try to get through the remaining ones. Okay. I'm going to skip this one because I think the others are somewhat smaller and/or basically already resolved. And I can take my last 10 minutes for this one depending on how those go. Okay. So last time I presented as an open question, how do we interpret `return` on the result? In particular, the question is, do we consider that to mean only that the consumer is not expecting to call `next` again? Or also, that they don't care about pulls that have already been made? This comes up in the context of `filter`. So let's just switch to [this example](https://bakkot.github.io/async-iterator-helpers-implementation/#filter-closing-2). + +KG: Okay. So filter. Let's say we pull a couple of times from `filter`'s result. And then while that's still happening, either the predicate or the underlying iterator or both are still unsettled, the consumer calls `.return` on the result of `filter`. At this point, we're done. We have closed the result iterator. And of course, we also call `.return` on the underlying iterator. The question is, if the second result settles with false, we now only have one value from the underlying iterator that we could possibly vend, or that we have vended. And we had two outstanding Promises. So we could attempt to go to great lengths to fulfill this earlier Promise by pulling from the underlying iterator again, even though we've already closed the result iterator. I originally had this as an open question. I now feel pretty strongly that we should not pull from the underlying iterator again in this case. We should just say, you said you were done. I'm not going to go to great lengths to try to fulfill things that you asked for earlier because you said you were done. And in particular, the reason I think this is that the place I expect this to come up is if you are buffering the result of `filter`, for example you're doing a `for await` over a buffered filter. In this case, if you early-exit from the loop, you really do not care about the things that are being produced to fill in the buffer. So we should not be doing additional work to try to fill in the buffer. So because of this example in particular, I really think that we should sort of optimize for this case and say, once you call `.return`, you should not expect earlier values to fulfill, even if they in principle could have. Yeah. + +KG: Oh, RGN, do you want to just go ahead and ask—“so the Promise never settles?”. No, it settles with `done: true`. It only settles with `done: true` once the predicate actually settles, though. Because if the predicate had settled with true, then in order to maintain our principle of not losing values, we would need to not lose this value, and the only place to put it is this Promise. So the second Promise doesn't settle until the predicate settles. But it will either fulfill with the value from this slot if the predicate passes it, or it will fulfill with `done: true` if it doesn't. The thing that we don't do is go back to the underlying iterator and try to find a new value that could pass the predicate. Okay. RGN says “plus one, end of message” on the queue. Great. Sounds like we agreed on that. WH is getting on the queue, also “+1”. Excellent. Okay. + +KG: Another thing that I had presented as open last time is how do we handle `.return` on flatMap? So for flatMap, we can potentially have two open iterators at a time. The underlying iterator is open and this inner iterator is open. At that time, if `.return` is called, we have to close both of them. The question is, in what order and concurrently or not? I am now convinced—last time we said that the order should be inner first, underlying second. We left it open whether we should wait for the inner return to settle before calling the underlying. I am now convinced that we should wait for the first one to settle before calling the second one. The reason for this is maintaining the principle, which I guess I ought to have written down as a principle, that **you only get concurrency if you explicitly ask for it**. So in this case, in this most basic case, you have not asked for concurrency at all. Except insofar as you called `.return` while blocked on a `.next`. But I think because you haven't asked for concurrency, you shouldn't get concurrency, which means we should wait for the inner return before calling the underlying return. I have this as no longer open because I'm happy with this answer. But people can fight me about it if they want. No one's getting on the queue, so I assume we all agree. Okay, great. + +KG: I had one more open question that we are probably not going to get to. I am going to try to explain it in the remaining time. So that if people have opinions, you can put them on a GitHub issue or on Matrix or something. Okay. The question is, if you have `AsyncIterator.from` and you pass it an iterator, so an object that has a `next` method, there is nothing which tells you whether this iterator is synchronous or not. You could look at the prototype and see if it has `Iterator.prototype` in its chain somewhere. I think that's a little weird. So the question is, in this case, you're just handed an iterator and you call `.next`. Should we await the result of `.next`? There's two things that you could in principle await. You could await the result of `.next` or you could look up the `.value` property and await that. If you knew it to be synchronous, you would eagerly look up the value of the `.value` property and await that. Because that is how—in general, how `for await` over a sync iterator works is you assume that the `next` doesn't give you a Promise, but you might have a Promise in the `.value`. + +KG: Or you could await the result from `next`. And in that case, you assume that you're working with an async iterator and async iterators are not supposed to have Promises in the `.next`. So you shouldn't await it. The question is, what do we do? Given the answer to the earlier question where we said we want to fast path non-thenables, my inclination is to say that we check to see if the result of the `next` call is a thenable. If the result is a thenable, we assume that we're working with an async iterator. If the result is not a thenable, we assume we're working with a synchronous iterator. I wasn't sure about this earlier because I wasn't sure how receptive the committee would be to the check-if-we're-thenable thing. But since we're doing that, that's what I would do here, that is, branch on thenable-ness of the `next` result. For things that are sync iterators, this costs an extra property lookup. But I don't really care. I guess we could, in theory, only do it for the very first value and then stash that. Say because you gave us something that wasn't a Promise, we are assuming nothing else is going to be a Promise. I'll have to think about that a little bit more. + +KG: Anyway, that’s the last major open question. There's some minor things about timing. Thank you for bearing with me. I'm glad our time box was almost big enough. Happy to take opinions on any of these things, but your time to have opinions is running out because I'm going to come back with a full proposal. And I will ping the reviewers when I have spec text written. + +CDA: MF is on the queue with support. Yeah. + +KG: I don't know exactly what you're supporting, MF, but message me on matrix. + +CDA: He just wants to be supportive of you, okay? Jeez. All right. Thank you, KG. + +KG: Thanks for your time. + +### Speaker's Summary of Key Points + +* The “Async Iterators” proposal is relatively complete, most outstanding questions have been resolved. +* It will not contain all the methods on `Iterator.prototype`, but they will likely be in followup proposals + +### Conclusion + +* JHD and RBR to review +* Incoherent underlying iterators: we will not try to be defensive, and no extra errors or warnings +* We will have a fast-path for non-thenable objects, not just primitives +* flatMap will deliver all results ASAP, accepting the cost of internal bookkeeping +* We will not reserve addition parameters in methods like `.some()` +* `.return()` indicates we should not make additional effort to fulfill outstanding prior calls to `.next()` +* For flatMap, `.return()` will be called sequentially, not concurrently, on the underlying iterators. + +## It's about the agenda deadline + +Presenter: Chris de Almeida (CDA) + +* [slides](https://docs.google.com/presentation/d/1uA690pDEj3NplfGnACwKAhek3bcECChVcQELcu_nF_Q/edit) + +CDA: All right. Let's talk about the agenda deadline. I was not going to introduce it this way, but it would be really cool if we could breeze through this really quickly so that we could get to some of the continuation topics, if possible, because we're already in overflow. So hopefully, we can just make it happen. All right. So the agenda deadline today is 10 days before the start of plenary. And it's subject to wherever the local time is. So we have to calculate 10 days before from 10:00 AM, whatever Tokyo time or whatever. So yeah, meeting starts Tuesday at 10:00 AM. Deadline's 10 days earlier at 10:00 AM local time. Delegates outside of Japan must convert that to their own time zone. So this produces different deadlines depending on where we meet. Which it creates unnecessary cognitive load. Not going to read all the words on my slide. You can see them. And there's not really any benefit to doing it this way. + +CDA: The point is to have a period of review time for delegations to review the agenda. Meetings either begin on Monday or Tuesday depending on if we're doing virtual only or hybrid. And so under the rule, when it starts on a Monday, the deadline's on Friday. If it starts on a Tuesday, the deadline's on Saturday. Saturday is not great. Friday is also not great. So I am proposing that we change from a host local time deadline with anywhere on Earth deadline so it's the same deadline globally. We don't depend on the meeting location. We don't have to worry about time zone conversion. And this is familiar convention that many folks are probably aware of for standards work in general. And so the agenda can simply show the date plus anywhere on Earth. So I'm also proposing we're not using exactly 10 days. So this is not just 10 days before plenary anywhere on Earth time zone because that doesn't really solve what I'm trying to solve for. Because it would still require accounting backwards from the meeting. You have a different deadline for Monday versus Tuesday. And you have potential Saturday deadlines. + +CDA: So my proposal is that the agenda deadline should be 23:59 anywhere on Earth on the second Thursday before plenary. This gives us one simple predictable rule—it doesn't matter if plenary starts on a Monday or Tuesday or wherever it is in the world, it's always the second Thursday before that week. So you have the resulting lead time of if it's a Monday meeting, you have approximately 11 days. If you have a Tuesday meeting, it's approximately 12 days. And it's very close to the 10-day window that we currently have. So why Thursday? So Thursday is the best balance between avoiding the weekend, as I mentioned before, it's approximately the same amount of prep time or review time as the current 10-day window. It gives delegates a predictable weekday. You have a full working week before plenary. And that small increase from 10 days to 11 or 12 days I would suggest is negligible. And the rule becomes easier to understand and easier to remember. Just a reminder, this does not shorten the time between plenary meetings. It's the exact same amount of calendar time between meetings and between deadlines. The only thing that changes is where the deadline falls within that existing window. + +CDA: So this is primarily an ergonomics and predictability improvement. It's not a substantive change to the agenda process. So before, we have meeting location, local time, subtract 10 days, convert time zone. My proposal is you have a meeting date second Thursday before anywhere on Earth. One predictable deadline regardless of where we are meeting. Currently, agenda items must be submitted at least 10 days before the start of plenary. My proposal is that agenda items must be submitted by 23:59 anywhere on Earth on the second Thursday before plenary. Discuss. + +SFC: I support this, but I would rather have it be second Friday because we have our TG2 calls on Thursdays. And while this anywhere on Earth on Thursday does allow us to technically get things submitted onto the agenda, it would be really nice to have that extra day. If you're in Japan, this is basically means that's a deadline is on Friday afternoon. In Europe, it's like Friday midday. So I would so this I would rather just have the-- basically at the end of the week, end of the work week, have your agenda item submitted anywhere on Earth rather than on Thursday if you're in the Americas or on Friday if you're in Asia or on Friday morning if you're in Europe. I'd rather it just be end of week for everyone, which means Friday. 23:59. I would prefer it. Thank you. + +CDA: But that's not accurate. And that's the entire point of doing Thursday is to meet that goal because if you change it to Friday, now you've pushed the deadline into the weekend for some parts of the world. + +SFC: Which is still after the end of the work week. Which is fine. + +CDA: I'm suggesting that it's not fine. I'm suggesting I deliberately do not want the deadline to fall on a weekend for anybody. + +SFC: Currently, the earliest the deadline is practically is when there is a Tokyo meeting, that puts the deadline at approximately end of the day at workday on Friday. I'm not comfortable moving it earlier than it currently is. + +KM: I guess independent of any choice that we make here, should we put the deadline as a calendar event in the decision calendar? I don't know if it is already. I don't think so. But just to have I mean, it would be you just place it as an event and then people can see it. + +CDA: I think that's a good idea regardless of whether we do this change or not. Yeah. + +JHD: That's totally something we can do. There's already a diagram on the agenda. So it's visible, but there's nothing wrong with making it visible in another place. + +MF: So the reason why we have an agenda deadline is because before we had an agenda deadline, people would put things on the agenda right before the meeting. And a lot of people would complain that we were talking about a subject that they didn't have sufficient time to review or talk about with their colleagues and form an opinion. So a typical work week is Monday through Friday for most of us, I think. Putting it any time before Monday only serves to reduce the amount of days that we have to work on the proposal without benefiting us with the number of days we have to review the proposal. So I don't see why we would aim for the end of Friday generally across the globe rather than aiming for before Monday in the first location that would experience it. Additionally, on this topic, not all of us get to work on this stuff during our work time. Some of us only have time during our free time. And that's how we enjoy spending our free time. And this would, again, take away our ability to do that. + +CDA: So there is a small, as I suggested earlier, negligible in my view, shift in that. But the gain is that you technically were exchanging a little bit of prep time for a little bit of review time. So it's not like a net loss entirely. + +KM: I guess it's kind of a question, but maybe it should have actually been a topic. Sorry. But I mean, are there delegates that use the weekends with emphasis on S to do review for the meeting, right? If you're coming on your own time, then you might want more than just one weekend in advance to review if you can't do it during the weekdays. So I could imagine that moving it into the weekend, then takes away theoretically from their ability to review, have the four days of review because you get two weekends before. Yeah. I mean, I don't know about that, but I'm just asking if anybody else has. + +JHD: So I don't actually understand what's the problem with a weekend deadline. I assume that most of the people that must review and must and need the time for it are the ones that are doing it as part of their job, which means they're not going to review until Monday anyway. And if the deadline-- if you don't want to submit on the weekend, you don't have to wait till the deadline to submit. You can submit on Friday or Thursday or Monday. You can submit whenever you want. I like the anywhere on Earth part. I'm not I think that's that makes sense to me. But I do not understand at all what the problem is with a weekend deadline. Who does that hurt? + +CDA: It doesn't hurt anyone. + +JHD: But I mean, you said you do not want that. So presumably, there's a reason for that. What is it? + +CDA: I just think people shouldn't have deadlines on weekends or working into the weekends. If the committee wants to say it's Friday anywhere on Earth, now it's Saturday. Yeah. I think Thursday is better. Because that avoids the weekend entirely. + +JHD: Right. But that sounds like a value judgment that people shouldn't be working on the weekends. And that's not anyone's place to make. There's nothing wrong with working on the weekends if you want to. So why is it important that it not be on a weekend? You can simply choose not to work on the weekend. + +CDA: Okay. Fair enough. + +KM: I think I mean, I guess my question hopefully should indicate possibly why someone would feel that. In advance are important, right? If you're contributing your if you're spending if you're contributing your own personal time for this committee, you may not have those you want those weekends to review the changes. So this extra the five-week days prior to the meeting are effectively meaningless time because they're lost. That certainly could be a reason. But that wasn't Chris's motivations. That's what I was asking about. And separately, I haven't heard anyone yet or seen anyone yet jump on the queue to indicate that that's important to them. + +OMT: I am on the queue. + +JHD: Oh, cool. Well, then I'll comment before I head to you then. But I'll say is that I have at many times not been able to use work time for TC39 things. And if I don't have time to review, I just don't review it in advance. The requests for review time have always in my recollection come from the browser companies who need to review it as a team, and figure it out with OKRs and stuff. I can review everything on the plane to plenary typically, because I don't need to get formal permission from anyone for my position. So I just don't know if weekend review time is actually important. + +OMT: So I think it's a great idea to put it on Thursday. I think it's the right incentives. If anything like the earlier deadline, the better. I think the discussions are more informed. If people are prepared, so we should always if in doubt, we should fall to the side of giving more review time in my opinion. Also, I don't think it's a value judgment. It's basically just saying for example, it's giving people the option of using that deadline as a justification to make room in their calendar to do it during the week and not push it to the weekend. And so that is a nice tool that we can provide to people. It doesn't cost us anything. Almost nothing. I really don't understand the discussion. It seems like the most natural idea to do here. So I strongly support Thursday. I also support the proposal. Overall, yeah. + +SFC: Yeah. So the Friday deadline would still allow for weekend review. I think that largely addresses that concern. At least for me, my Mondays through Thursdays are very busy with non-TC39 stuff. And I often don't have time after we have our TG2 meetings on Thursdays to actually go and make sure that pull requests have been open to the agenda doc and so forth. And I don't really like how anywhere on Earth sounds great, but the actual impact of it is that anywhere on Earth is UTC minus 12. So the actual impact of this is that you're saying that Americans need to get them turned in on Thursday, but Japanese turn them in on Friday. And so do Europeans. This is I don't think this is a very equitable choice, I think, that choosing a deadline that's after the work week is more equitable. + +ACE: Also, plus one for prioritizing review time over prep time. You have infinite prep time because you just don't put your thing on the agenda until you're ready. I could right now be preparing my slides for 9 plenaries time. My 2028 proposals. However, the people reviewing as soon as you add the thing and we've got a plenary and you're asking a stage advance then the clock is ticking. So in that game, you have to give the advantage to the reviewer because they're on the back foot. + +CDA: Sorry, just real quick response to SFC. I hear your point, but I actually think the point that you're making is actually more support for why the status quo is worse. + +RPR: So on the queue, we have lots of voices of support from OMT, CM, RKG, Peter, me, `JMN`, and `LVU`. We'll then go to SHN next. + +SHN: Thank you. Irrelevant of whether you choose a weekday or Saturday or weekend. We do have a rule in ECMA that is three weeks. And we have discussed this actually in the plenary in I think it was in May when they was at Igalia. And we had a lot of discussion on it. And I do recall some of the individuals said that they need more time to review as a team. I think Mozilla was one of the ones that made some of the comments. So I understand that it's a very tight schedule. Everybody's very busy in this travel. And you want to give enough time. But if you can consider whatever day you choose to try to make it that three week to give that amount of time to really be well-prepared would be highly recommended. + +CDA: Yeah. But it's an excellent point. And I had originally planned to have more slides if I could get traction on this, to move the deadline actually earlier. But we're not going to be talking about that today. + +SFC: I posted this before people were saying that weekend review time is important. But if weekend review time is less valuable than syncing the deadline to the beginning of week on the following week seems also like a good option. + +CM: Yeah. I think either SFC or I and maybe some others are confused about what anywhere on Earth means. My interpretation was if it's midnight on Thursday, it's just midnight on Thursday. And no time zone convergence involved. And yet Shane was saying something about 8:00 AM on Sydney or something. + +CDA: Yeah. So the point, yes. So technically, yes, it is. There is a point in time. And yes, that time is different depending on where you are in the world. But the point of using it is to just say it doesn't matter where you are. The deadline is Thursday, end of day. + +CM: Right. So you just go according to Thursday, the end of day, where the hell you are. And you just it's local time. For you. + +CDA: Yeah. + +MM: I thought it was you can if it's before the deadline, anywhere on Earth, it doesn't matter where you are. You just pretend that you're in the most favourable time zone. And that's the deadline. + +?: If you yeah, yeah. If you want to if you want to use a VPN so that the timestamp on your GitHub post or whatever. + +MM: Right. But I thought that's I thought that's what anywhere on Earth means is that you don't need to use a VPN. You don't have to pretend you're in you just use the you just everybody use the most favourable time zone. + +CDA: Yeah. I think my understanding was: we don't think about time zones. + +MM: Yes. + +CDA: Yeah. Okay. + +SFC: Anywhere on Earth has a definition. The definition is UTC minus 12. So when we say 23:59 anywhere on Earth, it's the equivalence of saying 11:59 AM in the GMT. That is the exact equivalence statement. + +MM: Okay. Thank you. That's what I was hoping. And that's different than what CM was saying. + +CDA: No, I don't think you're confused. I think you have the right mental model. The point is to not have to think about where exactly—it's just Thursday. Your deadline's Thursday. You're good to go. Just make sure your stuff is on the agenda by Thursday. + +JMN: Without knowing the definition of AoE, I can tell you that my experience with that in academic world was I'll get to it tomorrow. Something like I take the most generous interpretation of what the date time zone is, and I say, well, if it's Friday, AoE, then it means any time on Saturday that I do it is fine. In my local time. However, Sunday is definitely past the deadline. Right. But it sounds like this may be in conflict with the other people's understanding of AoE. + +SFC: I thought MF was before me. But yeah, JMN is right. And that's my but he's making my point. We're like the thing about I'll get to it tomorrow only works in some parts of the world, but not the rest. That's why I think weekend deadline is safer. Or end of work week, rather. Not weekend deadline, but end of work week. + +RPR: MF says plus one to JMN. + +ACE: I feel like the only way people can misinterpret this is that they will give themselves accidentally less hours than they technically had, which is not going to make a big it's like if they go, oh, 23:59 in my time zone, they're just reducing those number of hours, which is obviously going to be less than 24. And maybe less even worst-case scenario, the person adding the item has lost some hours because they misinterpreted it. You can't misinterpret this in a way unless you really, really not reading the sentence. You can't misinterpret it in a way that other people are going to suffer and you're going to post after deadline. + +RPR: Google says “Anywhere on Earth” is a calendar designation, meaning a deadline expires only after the date has completely passed across the entire globe. Isn't it equivalent? Okay. Ruben. + +RBR: I personally feel we are overcomplicating this a little bit. + +(various people): Yes. We are. + +RBR: And the question from me is just like, what are we optimized for? It's just either we want to have people to put things early on the agenda. That's one target. Another is like. And that's probably like to have people giving more review time. Or like to have people do it until the very last minute. I believe the proposal is probably about making people put things on their gender TED earlier. It's my and I believe that's actually positive because it is like incentivizing ourselves to do things earlier and I am part of that. So yeah, I think it doesn't really matter all that much if it's like one day earlier or later and all these details. Just if someone feels like they need more review time, we should probably focus on that. Ollie. Ollie says. + +It was just asked this meeting shows the optimization target should be to have fewer items on the agenda. + +ACE: I think we're massively as usual, yeah, over we're over and we do not police this in any strict people have been adding slides during the last week. Definition of being on the agenda and actually having the material. And it's very if the thing is really complicated and you add it late, that's worse than if it's a trivial thing and you add it late. And I think it's all is this like it's really much guidelines. We don't send each other to jail for this. It's silly how we hold ourselves to we pretend we work in a way that we clearly don't. It makes me laugh. + +JHD: I actually disagree. The deadline is only for advancement items. Non-advancement items, you can add slides two seconds before you talk if you want, even though you're requested to add slides. We definitely have procedurally blocked consensus for advancement because materials weren't available early enough. + +ACE: Sure. And in my opinion, that's just rude when we do that. Again, if it's a-- even if you're not asking for advancement, if you put a massive topic like if we'd never heard about using iterators and KG was like, "Oh, by the way, tomorrow I want two hours." I feel that's not respectful of our time as a committee, even if it's like yes, no one can block us doing that. As we've all rules, it's about finding what is an effective way of us working together. And guidelines helping nudge people in the right direction. + +MF: I still think that having a very precisely defined line is important, not for the purposes of calling this out like, "Oh, you didn't add your thing in enough time. I'm going to say that it was not ready." But more in the other direction of, I'm the champion, I add my thing to the agenda before the time, and I say, "I know I can successfully defend from that kind criticism." And if somebody says, "I didn't have enough time to review. I didn't think about this." I say, "Well, we have a precisely defined line and it was before that. So that's not a valid criticism of this proposal." + +ACE: I didn't mean to suggest we shouldn't have a definite line. I'm just laughing about how much we're quibbling over exactly where that line is in such a because CDA has proposed a definite line and it's in half an hour like it's like yeah, we should just agree on the definite line that's been proposed. And we can always change this if it doesn't work. This is not set in stone forever. + +SFC: I am actually happy that \[observer] Florian brought up the thing about weekends are not a universally well-defined concept. So trying to align or disalign with them is kind of not necessarily a goal, I think we should be having. But I was just giving some example my latest comment is Google Summer of Code is like one example of that I've worked with of like an organization that has to have deadlines that work across the world, and they set they picked 1800 UTC as their deadline for things. The equivalent here would be if we would do Friday 1800 UTC is basically six hours later than Chris's proposal. + +RPR: And YSZ points out that Brunei's weekend is non-contiguous. Amazing. + +RPR: All right. I would like to ask the committee for consensus to make this change. + +RPR: So ACE is supportive. Yes, let's try it. See how it goes. Peter is supportive. SFC objects, saying no, I don't want to regress the deadline relative to where it is currently. Leo yes, we have so MF you wanted to ask? + +MF: I mean, it sounds like we already have blocking concerns, but I would be willing to try this once and require us to reaffirm that we want to continue with that rather than the default of going back to the way it is now. + +RPR: So SFC, can I ask what do you think of that compromise? The try it once? + +SFC: I just posted: it's fine. + +JHD: Yeah. + +RPR: Once is fine. Okay. All right. A breakthrough. And JHD also says once is a good compromise. YSZ is positive. Leo is positive. KM is positive. OMT's still positive. RBR, Leo, okay. There's people still typing even though I think we've got a conclusion. KM says, "Can has calendar event pls." Okay. And JHD has said that he will do it. All right. I think given that we've only got three minutes left on the agenda because we are finishing it at 3:55, we don't have any more time for regular slots. But I'll say thank you to CDA for bringing this. We have an action and a next step. Did you want to summarize anything? + +CDA: No. + +### Speaker's Summary of Key Points + +The speaker did not provide a summary. + +### Conclusion + +No conclusion recorded for the minutes, please refer to transcript for more details. diff --git a/meetings/2026-09/sept-29.md b/meetings/2026-09/sept-29.md new file mode 100644 index 00000000..22b76390 --- /dev/null +++ b/meetings/2026-09/sept-29.md @@ -0,0 +1,1735 @@ +# 116th TC39 Meeting + +Day One—29 September 2026 + +**Attendees:** + +| Name | Abbreviation | Organization | +|---------------------|--------------|--------------------| +| Chris de Almeida | CDA | IBM | +| Richard Gibson | RGN | Agoric | +| Yusuke Suzuki | YSZ | Apple | +| Waldemar Horwat | WH | Invited Expert | +| Christian Ulbrich | CHU | Zalari GmbH | +| Ross Kirsling | RKG | Sony | +| Keith Miller | KM | Apple | +| Nikolaos Papaspyrou | NPU | Google | +| Ashley Claymore | ACE | Bloomberg | +| Lea Verou | LVU | OpenJS | +| Jordan Harband | JHD | Socket | +| Ruben Bridgewater | RBR | Invited Expert | +| Samina Husain | SHN | Ecma | +| Chip Morningstar | CM | Consensys | +| Mikhail Barash | MBH | Univ. of Bergen | +| Peter Klecha | PKA | Bloomberg | +| Sergey Rubanov | SRV | Invited Expert | +| Jesse Alama | JMN | Igalia | +| Luna Pfeiffer | LPR | Yavashark | +| Istvan Sebestyen | IS | Ecma | +| Jack Works | JWK | Sujitech | +| Guy Bedford | GB | Cloudflare | +| Ron Buckton | RBN | F5 | +| Philip Chimento | PFC | Igalia | +| Andrew Paprocki | API | Bloomberg LP | +| Daniel Minor | DLM | Mozilla Foundation | +| Daniel Rosenwasser | DRR | Microsoft | +| Justin Ridgewell | JRL | Google | +| Kevin Gibbons | KG | Invited Expert | +| Mathieu Hofman | MAH | Agoric | +| Michael Ficarra | MF | F5 | +| Mark S. Miller | MM | Agoric | +| Nicolò Ribaudo | NRO | Igalia, S.L. | +| Olivier Flückiger | OFR | Google | +| Rob Palmer | RPR | Bloomberg LP | +| Shane F Carr | SFC | Google | + +## Opening & Welcome + +Presenter: Rob Palmer (RPR) + +RPR: Yeah, yes. We don't want to lose time, so. So Riku will be introducing this meeting in 4 minutes' time. Okay. The campaign begins. I think, like, maybe 20 seconds until we start. Are you presenting these slides so you have the control? All right. So I think we're about to start, and we've got our host is going to introduce things can we have some quiet for our host, please? Thank you. All right. We're all good. I think everyone has just about settled, and the on the teams, we have now have plenty of people. Just to check, can István or Kevin, can you hear us remotely? + +RPR: All right. Good morning, everyone. On behalf of Sony Interactive Entertainment, or SIE, I'd like to welcome you all to Tokyo, and to the 116th meeting of TC39. Please do not tap on the microphones. So when you start speaking, don't be like just start speaking, and if there's anything wrong, we'll take care of it, so don't worry. Emergency procedures. So we are in Japan, so we'll have to go through what happens and what you should be doing when and in case of an earthquake. So and in case of an earthquake, please do not try to run while the shaking persists. That's the one thing you can't do. Just stay where you are. Try to take cover and wait for the shaking to stop. So what people do is they usually go under their tables. So please do that. And please also try to stay quiet. There may be building-wide announcements that may be in Japanese. I'll try to translate as soon as possible. So I know it's going to be panicky mode, but please try to stay quiet. Right. And also another relevant natural disaster coming our way. So we actually have a typhoon approaching us right now. So I'm thinking it'd be all right, but just a rule of thumb is once severe wind or rain starts, just try staying indoors. All right? And also, this office is located near a river. So beware. Flooding can occur. There are people who die every year because of typhoons. So please take it seriously. If anything, ask us for advice. All right? Cool. Now, the most important thing that I need to announce: security badges. So we gave you your security badges down on the first floor. They must be returned at the end of day three. Please don't take them home. All right? If you're leaving the meeting early and not coming back, please let us know so we can take your security badges from you. These ones you can take home, but not your security badges. All right. Now onto the fun part: social events. So we have a social dinner planned on Wednesday, 7:00 p.m. It's at Fujiya Honten Sakura Stage. In Shibuya Station. You're free to make your own way there, but if you're unsure, we will be leading a group from the office so please stay behind on Wednesday if you want to come with us. Also, a very special attraction we have this time around. We have a visit to Sony Square planned. Sony Square is an invite-only Sony state-of-the-art exhibition. We usually only invite special guests, which is you all. So we will invite you to a visit to the Sony Square on Thursday, 4:00 p.m. So that's right after meeting starts. They are very strict about time. So I'll be rushing you guys. Into the elevator, down the fifth floor. So please try to stay alert. Now, one caveat is that we have a maximum capacity of 20 people. So we're unfortunately going to have to prioritize delegates. And only if some delegates decide to opt out, we'll start inviting observers. So sorry, but this is going to be fun. Please look forward to it. Okay. And finally, so once again, my name is Ricky. I am the coordinator for this event. I have two other fellow coordinators, Nicholas and Kenro, who you met downstairs. If anything, please ask us. We are here our undivided attention is here for you guys for the next three days. Also, shout out to Sachiko and Yuka. They are in charge of logistics. They are the people behind the scenes who are powering the whole event. So if you have a chance to see them, just say thank you because they deserve a thank you. All right. So we hope you have a successful conference. And please enjoy your time in Japan. Thank you so much. I'll pass it back to Rob. + +RPR: Thank you, Ricky. So I'm going to have a go sharing from Teams. See how that goes. So it says that I'm sharing. And we are. Wonderful. So yeah, thank you for hosting and as a really useful intro. I will also say welcome everyone to Tokyo. I think we've been able this is the fourth year in a row that we have returned around this time of year. And it's always been an excellent meeting. Running the meeting today, we have the chair group. So in the room is myself. I'm Rob. With Chris here. So we have two chairs. We also have the announcement that Usual is leaving the chair group as he's moving on. And we thank him for his contributions over the, I think, at least two years, maybe three years. 2023, yes. So three years serving as a chair. And really doing essential work, helping myself and Chris. He continues on as an editor of 402. So he's not leaving the committee there. And then we also have dialing in Justin Ridgewell. And Daniel Minor and Daniel Rosenwasser. As the facilitators. Please could everyone use the sign-in form? So even if you're in the building, please use the video sign-in form so that we track your registration there as well. + +It's funny because we never update the month. Yes. We got lucky. + +RPR: And then please keep in mind that we have a code of conduct on the TC39 website. This is something that we expect everyone to read. And for everyone to respect, not just to the letter of the document, but also the spirit to which we can sum up as the excellent to each other. That's Bill and Ted for anyone that has not seen the film. We've got a fairly regular schedule here of the morning session till 12:00. So lunch is 12:00 till 1:00. We'll break in the middle of the afternoon. And then the meeting will finish at 5:00 p.m. sharp. Ricky already talked about the social dinner on the Wednesday. And also about the Sony tour, Sony Square tour, on the Thursday. So we will be definitely finishing on time for this meeting. No overruns. On our comms tools, there has been a refresh you may have seen TCQ getting reloaded, revamped, re-energized. With wonderful new features. For anyone that's not been here before, TCQ is how we manage the agenda and also how we manage people talking and contributing to the live meeting. If you are participant and you choose the Q view, so not the agenda, the agenda is the full list of items, but the Q represents the currently running item. You'll see some buttons there. In general, you want to prefer buttons on the left. So that big blue new topic is the normal default way of entering the conversation. And then moving to the right, if you just want to quickly clarify something, the green clarifying question. And then finally, if you need to stop the meeting, for example, if the AV tools are down, if note-taking is down, these are all reasonable reasons to use a point of order to escalate as quickly as possible to the chairs. We also use matrix for chat during the meeting. I think everyone is probably already on this. But if you are not, please sign up using the links from the original invite. And then a reminder that we have an IPR policy so everyone in the meeting in general either you are a delegate of an ECMA member company. You can ask Samina if you're not sure at the moment. Then likewise, we have invited experts which is a category that a formal definition in which you have applied and received the confirmation of that after filling in the form. And then finally, if you are neither a delegate or an invited expert, that means that you are an observer. You are welcome to listen to read only. But please do not talk during the meeting because we need to have everything covered. So yeah, please read the contributing MD. Then we have note-taking going on. So this is transcribed live, using the tool we have here from Chris. Sorry, originally by Kevin, operated by Chris today. And as part of that, a detailed transcript of the meeting is being prepared and will eventually be posted on GitHub. You may edit this at any time during the meeting in Google Docs for accuracy, including deleting comments which you do not wish to appear. You may also request corrections or deletions after the fact by editing the Google Doc in the first two weeks after the TC39 meeting or subsequently making a PR in the notes repository or contacting the TC39 chairs. And we're going to keep reminding, but at the end of each topic, the primary speaker will be asked to summarize the key points so that we can make good notes. So for the notes, we always need people to help. To help edit and improve the notes in real time whilst context is in our heads. Please could I get two volunteers to do so for this first part of the meeting? So I see CHUs hand straight up. And ACE. Sorry, if there was yeah. We love volunteers. Yes. Volunteers all get recognized in a special addendum by the chairs at the end. The next meeting is another remote meeting. It's on the boundary of November and December. The chairs are almost ready to share the next year's schedule. Just locking down a few final points that it's pretty much there. So be announcing that very shortly. On the housekeeping, can I request formal approval for the previous meeting's minutes? Any objections to approving those minutes? No objections? That is approved. Are there any objections to adopting the current agenda? No objections. So current agenda is adopted. So we move on to the secretary's or just before? + +CDA: One more thing. So for folks that are attending in person, you should have received an invite to the local matrix chat room for Tokyo attendees. If you have not, please let us know and we will get you invited. + +Thank you, Chris. All right. So I'll ask Samina. + +## Secretary's Report + +Presenter: Samina Husein (SHN) + +* [slides](https://github.com/tc39/agendas/blob/main/2026/tc39-2026-037.pdf) + +SHN: Good morning. Despite the weather of rain, potential typhoon, earthquake, which may have already taken place and future earthquake to take place, it's great to be here. And, we'll all stay safe. Thank you very much, Sony, for Sony Entertainment for organizing this. It is beautifully done. As always, I do have a short report. And I'm here for all day tomorrow and day after, this afternoon, I will step away and AKI will be online to answer questions if you have but I'm happy to have any discussions as the todays go on. + +SHN: So I just want to do first a little bit of a correction. I made an error in doing some statistics. I do think it's important that I do correct that. Then I'll do a general update on all the activities that are taking place currently within ECMA. I did some statistics last time. This is 65 years of ECMA, and I'd been looking back at statistics and I realized I made an error. It was pointed out to me I haven't necessarily found a way to down correct everything but what I want to highlight is that we have been talking about ECMA 376 which comes from a different TC, TC38, as being the second most downloaded. It's not about being first, second, or third but those numbers aren't exactly correct. That's actually a series of standards and I should not be doing it in that way. So actually when I look at it, ECMA 404 is right behind ECMA 262 and then one of the parts of ECMA 376 is also still very much used, just a slight update but those numbers are also reflected. So it is just a correction that I want to make and I've just highlighted it here. It's not a huge issue but it should be noted. + +SHN: For some new additions, I understand that potentially we have a new ECMA 404 coming to the GA for a December approval. If I am incorrect, you will let me know. But you do have, of course, a 60-day opt-out review period. Our ExeCom is scheduled for the 8th of October. And the GA is the 8th of December. But we would need ECMA 404 in its correct format for approval by the 8th of October, which would be the 60-day start of the opt-out. ECMA-404, you've had no updates for a while. So it would be almost 10 years. I think it was all discussed in the last meeting. So if I've got that right. I mentioned this already, it is going to be 35 years of ECMA script next year. And I would like to do a recognition of that throughout the year. + +SHN: But I cannot do it without your input. So it would be great if within TC39, if there are a couple of people that want to come together and design a logo build on the one you have or something a little bit new, I'd appreciate it. Send it to AKI and I will figure it out. It makes some stickers and also use it to recognize it and also do some visibility on ECMA with that. As soon as the dates are confirmed for the meetings next year, the hybrid meetings, the ones that we do where we have a good crowd in person, I would like to try to do a little bit of an extra celebration. So I'll wait for that. And I want to do some blogs. So I will reach out to people within TC39 to maybe help me write some content because you know your work the most. + +SHN: I'll also go back to some individuals that have worked on it for some time ago and ask them for some information. So we'll do some visibility on this. I'm also looking to take some budget and do some swag. Like I already mentioned, the stickers. And many people have mentioned sock. So I've been watching some of the text going on in matrix and somebody some few people recently mentioned hoodies. But even consider that maybe we just subsidize the hoodies. So I'm looking at a few things and I would appreciate any comments or feedback directly to me here while I'm here or to AKI and I through whatever channel you want. But I would like to have that before the next plenary so I can start to plan. I also do need to build my budget this year for next year and I really want to recognize that I have everything well in place. + +SHN: Some things that we're doing at ECMA and you all would have seen that I sent a survey many of you replied. So thank you for that. We received some very interesting feedback. It did only end last week and I'm here this week. So I haven't had much time to do some deep research but I do appreciate the feedback that I received. Some things that we'd already begun to do. It is very important for ECMA to have a critical mass. We do need members and I'm talking to every TC about how we can approach new opportunities to target members in the segment of the work that that TC is doing. Also help to develop some new work areas and also to look at some collaborations externally that are relevant for those TCs. + +SHN: TC39 is extremely active. You have a very strong group working. You are very productive. Other TCs are smaller but also are producing a lot but they're smaller and it's important that every TC has good critical mass. But I want to also recognize the work of all of the work that you're doing here. So we will do some of the visibility that I already mentioned. We already started to make some changes. Whether it's going to be on our website or some other channels on social media including LinkedIn that we would like to try to do some blogging quite regularly. Here's something new. Here's a new standard or did you know and join. That would be something that I would like to be able to do. And I would appreciate it from your side if you would tell me here's an organization that could be interesting. Why don't you try to reach out to them or here's a channel that would be better for TC309. Both AKI and I would appreciate that so we could have a bit more focus on whichever TC that we're trying to support. Interestingly from the survey the feedback that we did get was that ECMA needs to be more visible. So we will make clear the visibility of the work ECMA does. We're also looking to do some tool improvement here. I want to be very specific. We are engaging with ISO JTC1 where we do the fast track where their tool and their document methods are different'. They have the platform that they want to use but it doesn't necessarily match with the work that much of TC309 does or any committee that's working on GitHub and working on doing their standards and developing on GitHub not only for ECMA but other SDOs so that's one of the areas that we are looking to do some tool improvement. Of course, we will ripple it into also what would improve within ECMA. And then the external collaboration that is something that I'm always trying to do with our work in the European Commission and internationally. So just some outreach that is very important. And I can do this outreach and I want to support every TC but of course I always need some specific feedback. So I appreciate it from this committee and I may reach out to you directly to ask for some input. + +SHN: The annexes have our usual documents from the GA and ExeCom and all of the documents for TC39. I will leave you to go through it. They're on the annex side. The dates of our next meetings which are of course very important especially the GA the next June GA is set for the 30th. That's when you typically do your next editions. But the December GA I've double highlighted here and also the date change of October it was meant to be a day earlier it is a day later. So please note that as you think about 404 for the approval at the next GA. I'm looking forward to hearing about the next meetings. So as soon as you have the dates that would be great. And again, it's great to be here in Tokyo this year. Thank you again Sony for doing this work. The documents are listed there and the code of conduct which you all know information for the invited experts. We have many here. Very active ones in TC39 work is extremely appreciated. And that is the end of my presentation. I'm open for any questions. Thank you. + +RPR: Any questions for Samina? No, I think that is all good. So thank you, Samina. + +### Speaker's Summary of Key Points + +The Ecma Secretariat provided a brief update covering statistics, upcoming approvals, anniversary planning, outreach, and administrative matters. A correction was made to previously reported download statistics: ECMA‑376 is a series of standards and should not be counted as a single item. Updated figures show ECMA‑404 directly behind ECMA‑262 in downloads. A new edition of ECMA‑404 is expected for approval at the December 2026 GA, with the 60‑day opt‑out period beginning at the October ExeCom meeting. This will be the first update in nearly ten years. The Secretariat noted that 2027 marks the 35th anniversary of ECMAScript and requested TC39’s support for a commemorative logo, visibility activities, and related materials. Survey feedback highlighted three areas: increasing ECMA’s visibility, improving tools, and strengthening external collaborations. Work continues with ISO/JTC 1 on tooling alignment, particularly for GitHub‑based workflows. Upcoming GA and ExeCom dates were reviewed, and members were reminded of the Code of Conduct and the rules for Invited Experts. + +## Addition of Eemeli Aro as an ECMA-402 Editor + +Presenter: Richard Gibson (RGN) + +* No slides presented + +RGN: EAO cannot be here today but he has reached out to me and I think also shared publicly his interest in being an ECMA 402 editor. And for that, he has my full support. He's already making a number of editor-like contributions to the project, and would be a fantastic addition to the team. So I would like to formally recognize him as such. And that's pretty much the entirety of the topic. I could sing his praises for a long time but those of you who know him also know that it's not necessary. + +RPR: You have +1 support from CDA. + +RGN: I do have a process question on what is necessary to actually accomplish this. + +RPR: So sorry, we haven't conferred before on this but I'm so long as this was put on the agenda with sufficient notice so this has been widely available. And so long as we don't have any objections I think that we are free to appoint editors on an as-needed basis. + +RGN: Fantastic. + +RPR: So we also have plus ones. YSZ,, did you want to speak? + +YSZ: I think yes. Sorry. + +RPR: Okay. Yes. Yeah, please put the EOM (text) if you don't wish to speak. All right. And then SFC. + +SFC: Yeah, we discussed this in the 402 call. EAO joined us for a few minutes and yeah, basically everyone is in support of this. + +RPR: All right. So we've only heard support. I'll just do a final check. Any objections to EAO becoming an ECMA 402? No? Okay. I think that is confirmed then. + +RGN: All right. Can't wait to share the good news with him. Thank you. + +### Speaker's Summary of Key Points + +EAO has been invited to join the editors of ECMA-402 Internationalization API with the approval of the committee. + +## ECMA262 Status Updates + +Presenter: Michael Ficarra (MF) + +* [spec](https://github.com/tc39/ecma262) +* [slides](https://docs.google.com/presentation/d/1x2UCdQjVo-5GEwE77Ww8SD5HYCpfsAp5QuYf4n1yC-0) + +MF: Okay, this is the 262 editors update. Two notable normative changes since last time. We approved a needs-consensus PR to switch all of the counters used in iterator built-ins to Numbers instead of requiring arbitrary mathematical arithmetic. This shows up as counters stopping to advance once they hit Number.MAX_SAFE_INT. So we merged that. And also we merged the other needs-consensus PR for `Promise.try` to skip two micro task ticks when used with an actual Promise—or an actual instance of the constructor of the thing you're using `Promise.prototype.try` on. So those are both merged. + +MF: We've been doing a lot of work getting Temporal in. So we've landed a lot of PRs that are still prep work for that. And the review continues. We merged a PR to clarify how we expect implementations to make the choice on whether to use 'get' or 'set' in the function name, asking them to be consistent with that choice. And we now have—I guess I have a figure for this next one. Yes, we have better linking for the internal methods. So now you see the right column here lists all of the call sites for these internal methods at their definition. And all of the call sites link to the definition for these essential internal methods. Upcoming planned editorial work looks mostly the same. As I said last time, we are now more consistently using our board on GitHub to track our work. So if you really want to know the minutiae of what we are working on, that link at the bottom is the place to go. And that should be it. Any questions? + +RPR: Nothing on the queue. So all good. Thank you, MF. + +### Speaker's Summary of Key Points + +* Iterator built-in counters now use Number arithmetic rather than mathematical arithmetic, so they will now stop advancing at Number precision limits. +* `Promise.try` now skips two microtask ticks for promises that are instances of the constructor being used. +* Temporal integration and review continues, with many preparatory PRs merged. +* Editorial improvements have clarified consistent getter/setter naming and linked essential internal method definitions with their call sites. +* Upcoming work is tracked on the GitHub board. + +## ECMA-402 Status Update + +Presenter: Richard Gibson (RGN) + +* [spec](https://github.com/tc39/ecma402) +* [slides](https://notes.igalia.com/p/2026-09-ecma402-editors-update/) + +RPR: And then it's back to RGN with the 402 status updates. + +RGN: First off, thanks very much to JMN for putting these together. We had a little bit of a game of chicken in deciding who would give the update. And this work is very much appreciated. So since last time, we have a couple of normative changes that have made it into the spec. First off, we are now taking the language subtag into account and computing the correct hour cycle and calendar lookup. + +RGN: So French as spoken in Canada versus English as spoken in Canada actually implies information about how timekeeping is properly rendered. That previously was not possible to take into account. We applied a normative change to take care of that, and now it is possible. Everyone gets better localization as a result. Likewise, in locale objects, the `getCollations()` method is going to behave better because it no longer has an implicit fallback to the default locale but rather to the root locale when there are no known collations for its locale. So this reduces fingerprinting and it gives more deterministic behaviour. It's kind of an oversight that we weren't previously doing this, but that has now been corrected. + +RGN: Another normative change that made it in rather recently is that `getWeekInfo()` now pays attention to the Unicode extension keys for region overrides. So that you can get weekday/weekend/start-of-week etc. information tailored to a specific region regardless of other language-level localization. ICU4C implementations already had the desired behaviour, but now the spec defines it. + +RGN: In an editorial context, we've also got a large handful of things that are coming in. For dealing with rounding modes, there was just a minor cleanup. Which is also propagating into Temporal as well. We’re also keeping up with ECMA-262 conventions for rendering the well-known intrinsic objects table and replacing the overly general term “finite” with the narrower term “finite number”. And finally, there’s a handful of new normative PRs that haven't yet made it through the TG2 process, but likely will do so between now and the next meeting. They're similar to the ones we already discussed for refining locales based on browser configuration and Unicode extension keys. And one that I think we’ll be discussing in this meeting, actually defining the behaviour of toLocaleString for TypedArray objects. Up to this point, that’s been a hand-wavy reference to the analogous algorithm for Array toLocaleString, and ECMA-262 kind of assumes that ECMA-402 already provides a superseding definition. So we're just going to make it actually do that. + +RGN: Upcoming on the editorial front, again, preparing ECMA-402 for incoming Temporal and Amount changes proposals, we’ll be generalizing the low-level ResolveLocale operation and planning to replace GetOption with references into ECMA-262. And then another issue that I think we'll probably discuss in this meeting: just recently, IANA un-deprecated what were previously these legacy time zones with permanently-locked daylight saving time transitions. We really don't want them to show up in time pickers, but unless we do something, they're likely to be in the output from `Intl.supportedValuesOf("timeZone")`. So some kind of fix is probably going to be necessary. It would be ideal if we can convince IANA to re-deprecate them. I don't know if that will happen. And then questions around just general behaviour.[tc39/ecma402#1098](https://github.com/tc39/ecma402/issues/1098), I think we're also going to be discussing specifically. It has to do with whether the default locale observed from an environment can already have Unicode extension keys. That's currently not allowed, but there are some circumstances where it is web reality nonetheless. And that brings us to the end. If there are any questions, I'm happy to field them. If not, we can move on. + +RPR: Queue is empty and I think we've completed the time box. + +RGN: All right. Thank you. + +RPR: All good. Thank you, RGN. And then on to CM with ECMA 404. + +### Speaker's Summary of Key Points + +* Recent changes have improved localization of time rendering by language-in-region and week information by region override. +* ECMA-402 is keeping up with ECMA-262 editorial conventions. +* ECMA-402 will soon be providing a definition for %TypedArray%.prototype.toLocaleString. +* Some issues will be discussed specifically in this meeting. + +## ECMA-404 Status Update + +Presenter: Chip Morningstar (CM) + +* [spec](https://github.com/tc39/ecma404), [issue](https://github.com/tc39/Reflector/issues/587) +* No slides presented + +CM: So as we're all used to the tradition with ECMA 404 is that nothing ever happens. As SHN alluded to, something has happened. And so we're going to be having a new edition of ECMA 404. This is purely an editorial change; the definition of JSON has not changed. A couple of months ago, there was an effort to clean up the 262 spec for how `JSON.parse()` worked and to move JSON evaluation into an AO. As part of this, there was a desire to incorporate ECMA 404 by reference rather than having a duplicate grammar in the 262 standard, at which point somebody noticed that last December, when JHD gave us this wonderful gift of an Ecmarkup version of the ECMA 404 spec document, one of the things that kind of slipped by without at least without me noticing (JHD is probably aware because he did it), is that whereas the original ECMA 404 document shows the grammar in terms of railroad diagrams, when it got converted to Ecmarkup, JHD added an actual BNF for the grammar. A couple of months ago, somebody observed that, well, actually, that makes it a new version of the spec document. And so we probably ought to follow our procedures and actually bless it as a new edition. At that point, somebody said, well, if we're going to be incorporating that grammar by reference, the grammar also needs to deal with the specification of insignificant white space, which the grammar that was there did not do. The railroad diagram version of the grammar dealt with insignificant white space informally using prose in the body text of the standard. RGN volunteered to produce a PR to update it to incorporate the notations for insignificant white space, which he did. And I merged that in. At that point, AKI also added another minor PR that tweaked the formatting ever so slightly so that her thankless task of getting the PDFs to come out in legible form would be more easily accomplished. And so those have also been folded in. These PRs have been landed. It is in the repo where the standard lives. It is ready to roll into the formal process of blessing it as a new version of the standard, which I think is what SHN was talking about earlier. It is all ready to go. It's been almost 10 years since the standard was revised, but note that the thing the standard specifies has not changed. I don't know if there are any questions, but if so, I'm happy to answer them. + +RPR: No questions so far. But still shocking news that we have. + +CM: We have an update. Well, it never changes. And it hasn't changed. It's just that this is a new edition. + +RPR: Okay. Then thank you, CM. Did you want to dictate a summary for that? Okay. You'll write it. Thank you for that. + +### Speaker's Summary of Key Points + +* We have a new version of the ECMA-404 standard document using the standard Ecmarkup formatting. +* It adds a BNF grammar for JSON in addition to the existing railroad diagrams. +* This includes BNF for insignificant whitespace, which had not hitherto been part of the formal grammar spec per se. +* JSON itself has not changed. + +### Conclusion + +* The first new edition of ECMA 404 in ~10 years! + +## Test262 Status Update + +Presenter: Kevin Gibbons (KG) + +* [repo](https://github.com/tc39/test262) +* No slides presented + +KG: So hello all. This is my first time coming to you with the test 262 update. I joined the maintainers group around the time of the previous meeting. Mostly because the current maintainers haven't had as much time to work on it. So I'm trying to contribute as well. And to that end, we actually have a couple of things relevant to the committee as a whole, or at least the people who write and consume tests, which ought to be all of you, although it isn't necessarily. So the first thing is, you may have seen the info block in the test metadata. This is where there's a section of the 262 or 402 spec text that's copied more or less verbatim into test files. We no longer recommend this practice for new tests mostly because it's a lot of work. And we don't want this to be an impediment to writing tests. We think the value that it provides is not worth the time that it takes in preparing and reviewing tests. But also these get out of date almost immediately and are never kept up to date. So just keep that in mind if you're writing tests. Please don't add the info block. We're not going to go through and delete them from existing tests. But going forward, we're not recommending their use. + +KG: Thanks to PFC, we have this new table of results for new and modified tests on engines in pull requests. The precise presentation here is likely to change, but this is technically something that's always been available but was kind of hard to find. And now it will be posted as comments on pull requests. One thing I want to highlight here is that the tooltips on these entries will show you the reason that the test failed, basically. So if you're wondering what's up with that, that's what's up with that. Okay. Other than that, I want to call out that we're trying to get through the backlog. I believe that we have gotten through all of the tests for stage 2.7 and conditionally stage 3 proposals. I may have missed some. + +KG: There was quite a backlog. But we're really trying not to be in this awkward state where there's proposals blocked from advancement because of not having tests or the, in my opinion, even worst state where things are in stage 3 but haven't had their tests merged. So please ping us if you are aware of pull requests that need merging otherwise, I'm we're going to try to prioritize the sort of large backlog of things. But things that are blocking proposals, I'm going to try to make those the highest priority, at least for me. Okay. That is my update. Thanks for your time. + +JHD: If anybody notices a mismatch in the proposal data from what they believe it should be, regarding advancements, conditional or otherwise, please surface it and let me know. That's all. + +KM: Is there a timeline for conditional stage 3 where if the tests don't appear, it just kind of falls back out of phase stage 3? Or do we update the table before while it's still in that conditional state? Or is it only the table get updated. + +JHD: The source of truth is whatever plenary has decided. The closest written form of that is the proposals data in the table. + +KM: Is that table updated while it's in conditional still? + +JHD: No. So I'm usually the only one that updates it. And I don't update it until the conditions are met. + +KM: Perfect. + +JHD: At which point I try to update it. But I'm human. And make mistakes. + +KM: Yeah. Yeah. Not worried about that. I just want to make sure. I think people would find it confusing. They're looking at that base effectively as the source of truth. + +JHD: Yeah. We could alternatively alter the table to display some sort of conditional status. But I don't know if that's necessary because we, I think strive to have the that window be very small anyway. + +KM: Yeah. We don't discuss it too much. Thanks. + +RPR: Thank you. Kevin, would you be kind enough to write up the summary? + +### Speaker's Summary of Key Points + +* We no longer recommend the use of the "info" block containing spec text in test metadata +* Pull requests now have an automated comment giving results of new or modified tests on some engines, hover over the emoji for failed tests to see the cause of failure +* I believe we are done with the backlog of open PRs for stage 2.7 and stage 3 proposals, let us know if not + +## TG3 (Security) Update + +Presenter: Chris de Almeida (CDA) + +* No slides presented + +CDA: TG3 security task group. As is our custom, we continue to meet weekly to discuss security impact of various proposals in various stages. But we've since last plenary, we've also done something else, which is ECMA received a liaison statement from the GSM Association, which is the telecoms providers. Who are doing some shall we say potentially interesting things or talking about doing some interesting things about pushing untrusted JavaScript™ between network devices and repositories. So they've been meeting with us. We've had a couple of meetings. With Walter from them. It's been a little bit slow going just because we have lots of questions and they sometimes don't have the answers. So we're continuing to do that. I think the next time the next meeting when was it, JHD? The 14th or something like that? It's mid-October meeting. So if that's of interest to anybody, please join us. I'm told they have answers to some of the questions that we had before. So we will continue to engage with them. And that's about it. + +RPR: No questions on the queue? Please, Chris, would you write the summary? Oh, sorry. We've got a question coming in from MM. Mark, you're free to speak. + +MM: Okay. CDA, did I understand you to say that there are answers to our questions? They just haven't brought them to us? + +CDA: Yes. My understanding is that Walter went back to speak with their side on the questions that we had. And they have some answers for us. So at that mid-October TG3 meeting, Walter should be able to join. And we can see what they say. + +MM: Okay. And we can see if they are actually answers. + +CDA: Yes. So MM is alluding to is it's been kind of hard to get answers to questions because they're they seem to take like a formal approach to speaking on behalf of the association. So hopefully, we have some answers to questions. And it's not so ambiguous. Because the challenge that we're in is we want to help them. But it's hard to do that with the limited information that they have. And so it's we kind of have to speculate and it's a little bit nebulous. So yeah. Hopefully, we have more information, particularly around like their host environments. And things of that nature. But we'll see. + +SHN: I just comment on that question, please? Thank you, CDA, for that. MM, just to say that I'll go back to Walter. Walter represents Huawei. To ask him to give us some of those answers in writing. They are very formally structured. So we have a liaison document that came to ECMA where they asked questions. We're going to respond to that liaison. And I will ask Walter to send us some of that response in advance so the committee can have a look at it. And then we'll see how the committee will proceed. But there's certainly a strong interest to not duplicate work and try to work together. So we'll also try to set up a more formal structure between the two organizations. But Walter does represent a member organization. So he may be able to share some information with us. Thanks. + +MM: Okay. Thank you. + +### Speaker's Summary of Key Points + +The speaker did not provide a summary. + +## TG5 (Experiments in Programming Language Standardization) Update + +Presenter: Mikhail Barash (MBH) + +* [slides](https://docs.google.com/presentation/d/1H-6Ot6FZM4RG9FCU3qs1GOZCm89aG8a0fZGfJ8HO3Bk/edit?usp=sharing) + +MBH: Okay. So TG5 continues to have monthly meetings. And we had yesterday a TG5 workshop at Shibaura Institute of Technology, which was a successful event. And I would like to also again bring your attention to the workshop on programming language standardization and specification, which will happen next week. On Thursday, in California, co-located with SPLASH. We have two fantastic keynotes by Gilad Bracha and by Bertrand Meyer. And we also have a panel with several very accomplished panelists who have contributed to many programming language standards. I would like to particularly mention Guy Steele here, who was one of the editors of the very first edition of ECMA-262 in 1997. So if you are based in California, MF, YSV, and myself encourage you to attend next week. It's still possible to register. It's going to be on Thursday next week. Yeah. That's it. + +RPR: Thank you, MBH. + +### Speaker's Summary of Key Points + +* TG5 hosted a successful event at Shibaura Institute of Technology +* There will be a Workshop on Programming Language Standardization and Specification co-located with ACM SPLASH in Oakland, on October 8, 2026 + +## CoC Update + +Presenter: Chris de Almeida (CDA) + +* No slides + +RPR: CDA, what do we have from the code of conduct meeting? + +CDA: Nothing, which is good. No new reports. No significant issues. As far as I'm aware, in our repos or other spaces, and as always, folks who are interested in joining the code of conduct committee can reach out to us and we are always happy to have more folks. + +## Needs-consensus PR: make DataView.prototype.{byteLength,byteOffset} not throw when backed by detached buffer + +Presenter: Kevin Gibbons (KG) + +* [PR](https://github.com/tc39/ecma262/pull/3972) +* [slides](https://docs.google.com/presentation/d/1SgGitTmE7BtyJ2Vnqkv5CUOhhACuHFlIOe85qNXLBYI/edit?usp=sharing) + +KG: So I am here to ask the committee about making the byteLength and byteOffset accessors on DataView prototype less throw-y. What do I mean by that? First, some background. Both DataView and TypedArray are views of an underlying ArrayBuffer. ArrayBuffers can become detached or can shrink. Well, some ArrayBuffers can shrink. Some can become detached. Also, DataViews and TypedArrays have these accessors for reading the length of the view and the offset of the view, which respect the underlying buffer. When the underlying buffer becomes detached, the original values for these accessors no longer have meaning. Your offset in a detached buffer is not a meaningful value. The length, you could say that the length is zero. + +KG: The thing I am here to talk to you about is that these have different behaviour, which is, to me, weird. So when the view becomes invalid, either because the backing ArrayBuffer became detached or because the backing ArrayBuffer shrank such that the end of the view is now past the end of the ArrayBuffer, the TypedArray is now invalid or the DataView is now invalid. And when that happens, these setters on TypedArrays return zero. And on DataViews they throw. Here I have the algorithms for you. You can see these algorithms for byteLength, for TypedArrays versus DataView are extremely similar, except that TypedArrays return zero, DataViews throw a type error. Similarly for byteOffset. My proposal is to make the DataView ones not throw. + +KG: So why would you do that? Well, consistency is the reason. These things are very similar. It's just weird to have them be different. And the reason this is coming up is that WebIDL is in the process of rationalizing their treatment of DataViews, TypedArrays, and ArrayBuffers. Which has been necessary for a long time and is part of what's been blocking movement on, for example, getting immutable ArrayBuffers shipped. But in the process of trying to rationalize WebIDL's handling of these types, they were trying to work with DataViews and TypedArrays and they ran into this inconsistency where they were trying to match the underlying spec, but the underlying spec is inconsistent. So I should also mention that ArrayBuffers similarly have a byteLength which behaves like TypedArrays. It used to be specified to throw when the ArrayBuffer was detached, but that was never actually web reality. Also, as you may be aware, we inherited these things from the Khronos specification. The WebGL specification. Which is part of why they're a little bit weird in a number of ways. And in the Khronos specification, none of them threw. And I dug up [the old spec](https://web.archive.org/web/20160204045935/https://www.khronos.org/registry/typedarray/specs/latest/) for us to look at here in case you're curious. + +KG: And, an interesting fact here is that the way that these were originally defined, both DataView and TypedArray were specializations of a base ArrayBufferView interface where the byteOffset and byteLength properties were defined, and so it was impossible for TypedArrays to have different behaviour than DataViews because they were literally the same interface originally. So I think this just highlights how weird it is that they have different behaviour. + +KG: Now, technically, we are changing the behaviour of shipping code if we do this. So there is a web compact question. We would be making an error into a non-error, which is usually fine. Also, I think it is pretty unusual to be working with detached or out-of-bounds buffers. Out-of-bounds buffers only became possible relatively recently. Detached buffers until relatively recently could only arise if you were post-messaging the buffer to a separate thread. This is an unusual thing to do. Also, DataViews are somewhat unusual to use. Most use cases for ArrayBuffers call for a TypedArray, not a DataView. Not all, so DataViews are used. And buffers do become detached. But I think the combination of these factors leads me to suspect that it is unlikely to cause problems in practice. Both because the code that would run into an issue here is relatively unusual, and because we are only making an error into a non-error. + +KG: So this is the spec text. The change in spec text that I am proposing just in those two cases that I showed before where we have a throw a type error, now we return zero, matching TypedArrays. Yeah. So I would like to ask for consensus for this change. + +RPR: You have some messages of support on the queue. So RKG says, "Web compatible consistency updates make me happy." Thumbs up. Dan Minor says, "Agree that these should be consistent." Support the normative change. RGN is +1. MM has a question. MM, would you like to ask? + +MM: Yes. Can you hear me better now? + +RPR: Just about. Are you fine? + +MM: Okay. So there was the phrase on a slide, "Out-of-bounds buffer." Which confused me. + +KG: Yes. That was my mistake. This should say, "Views of buffers where the view is now out of bounds because the buffer has been shrunk." + +MM: Okay. That's the clarification I was looking for. Thank you. + +KG: Yes. That was incorrect phrasing here. + +MM: Oh, and I support. + +KG: Thank you. + +RPR: Thank you for your support, Mark. Mark. And Keith, sorry, before we move on, I think WH may have a reply to the current. WH, you're asking about a race? + +WH: Yes. At what point can this turn from some nonzero values to zero? Are there any possible race conditions here? + +KG: Fortunately not, because SharedArrayBuffers cannot shrink and cannot become detached. So this is only relevant for ArrayBuffers which cannot be cross-thread. + +WH: Okay. So it's not possible to asynchronously shrink something and then observe via this functionality? + +KG: That's right. + +WH: Okay. Thank you. + +RPR: Back to KM. + +KM: Yeah. Plus one on this. I will take, I guess, a moment to get on my soapbox and say that we think that transferring ArrayBuffers should be considered a deprecated technology. But that is not necessarily the problem here. I think it's still a good idea to do this anyway. + +KG: I will also mention that we have these new methods like transferToImmutable or transferToFixedLength which also cause an ArrayBuffer to become detached. Also, sometimes you just want to detach an ArrayBuffer so that you can free the memory without having to ensure every instance of it is garbage collected. So you still end up with detached buffers even if you're not literally transferring them to other threads. + +KG: But also I would be interested to hear more about why you think transferring is deprecated. Because I'm totally still doing that in new code. But offline. + +KG: Okay. Sounds like we have support for this. We'll get test262 tests landed. And then we'll get this PR shipped. So thanks for your time. + +RPR: Thank you, KG. And I will trust you to write up your summary. + +### Speaker's Summary of Key Points + +* DataView.prototype.byteLength/byteOffset are inconsistent with the TypedArray getters of the same name, in that they throw rather than returning 0 when the backing buffer is detached or the view becomes out of bounds. The proposed change would be to return 0 in those cases. +* This could technically not be web compatible, but making an error into a non-error is rarely breaking, plus both DataViews and detached buffers / OOB views are separately unusual, so it will probably be fine. + +### Conclusion + +* "make DataView.prototype.{byteLength,byteOffset} not throw when backed by detached buffer" reached consensus to merge + +## Normative: Update `RevalidateAtomicAccess` to account for all bytes of a TypedArray element + +Presenter: Richard Gibson (RGN) + +* [PR](https://github.com/tc39/ecma262/pull/3926) +* No slides presented + +RGN: *Presenting the PR* + +RGN: All right. The short description of what's going on here is that we currently have a spec bug: when a length tracking TypedArray has multi-byte elements (so it's an Int32Array, a BigInt64Array, etc.—something other than Uint8Array or Int8Array) and its backing array buffer is shrunk during the processing of the arguments for an atomics function such that the target element, which was initially inbounds, now still *starts* inbounds but extends past the new end of the backing ArrayBuffer that has been shrunk, then `RevalidateAtomicAccess` currently does not throw an exception and proceeds as normal, resulting in control reaching an assertion that fails for insufficient bytes in ArrayBuffer. The kind of scenarios where this comes up are code we're looking at on screen, where the `Atomics.and` function for index 1 takes the value argument, an object with a valueOf function, that shrinks the array buffer to only seven bytes rather than the eight that would be necessary for the complete representation of the element at index 1. So that sets the stage. + +RGN: The reason that is coming before the committee is that the test262 PR, which I'll show briefly in a moment, isn’t passed by all implementations, which is relevant because this is being presented as a web reality pull request. However, the nature of their failures is consistent with their current non-conforming behaviour for shrinking the ArrayBuffer by a whole number of elements. So you do get an error everywhere except in Moddable XS, just like when you shrink the ArrayBuffer by enough bytes such that it falls on an element boundary. But in JavaScriptCore and V8, the error that you get is a TypeError rather than a RangeError. And that explains the test failures. + +RGN: Actually, I'll jump over to that now. As we previewed earlier, test262 pull requests now surface what's going on for the tests. Regarding these tests, the complaint for JavaScriptCore and V8 failures is “expected a RangeError but got a TypeError” and for XS is “expected an error but no exception was thrown”. And as mentioned, that's already consistent with their existing behaviour for whole-element reductions. The ECMA-262 pull request itself is fairly straightforward. I'm going to show the rendered diff because that's a little more readable. + +RGN: Previously, we were throwing the RangeError exception only when byteIndexInBuffer, the starting index of the element, was greater than or equal to the length of the ArrayBuffer. Now we're getting the element size, and we're checking the last byte index, which is byteIndexInBuffer plus the element size minus 1. + +RGN: As an aside, `Atomics.notify` is unique in its non-use of `RevalidateAtomicAccess`. So shrinking the buffer of a length-tracking TypedArray during `Atomics.notify` argument coercion to mirror what we looked at above is not specified to throw; instead, you actually just immediately get a `0` result. This pull request is not changing that. I might come back to it at some point, although it's worth noting that this is really not an intended use case for `Atomics.notify` because that function really wants to deal with SharedArrayBuffers (which cannot shrink). + +RGN: What is changing is strictly `RevalidateAtomicAccess`. As a representative example of how it is used, I’ll refer to `Atomics.load`. First we validate atomic access, then we `RevalidateAtomicAccess` because the first validation can invoke user code inside of the index processing. `Atomics.store` is similar. We do a few things up front and then `RevalidateAtomicAccess`. `Atomics.and`, `Atomics.compareExchange`, `Atomics.xor`, etc. all call into AtomicReadModifyWrite, which itself again has that same pattern—process the inputs (potentially invoking user code) and then `RevalidateAtomicAccess`. So the number of API functions that are affected by this one deep operation is fairly substantial, but not overwhelming. Coming back to the high-level overview then, what we're looking for here is just consensus to land the PR as it is and the corresponding tests for it, avoiding the spec bug that can cause a failed assertion and understanding that implementations will be expected to come into conformance with respect to thrown error specifics over time. So with that, I think I'm ready for the queue, if any. + +RPR: You have support. DLM. Who supports the normative change. MM. + +MM: I support also. I just in listening to all this again, I just have a question that just if you have an answer off the top of your head, otherwise we can just drop it. Why in practice do people actually shrink ArrayBuffers? What's the motivation? Not in theory. + +RGN: I actually don't remember that. It might have been before my time on the committee. + +MM: Okay. Okay. Thanks. I support this. + +RPR: And MF, also supports this is clearly the right thing. So I think we've only heard support. + +RGN: Okay. Great. Let's do it. + +### Speaker's Summary of Key Points + +* Implementations other than Moddable XS already throw exceptions in the relevant circumstances, but JavaScriptCore and V8 throw TypeError rather than RangeError (consistent with their behaviour when such shrinking fully undercuts an element rather than splitting it) +* `Atomics.notify` is unique in not using `RevalidateAtomicAccess`, but V8 implements `Atomics.notify` with such revalidation + +### Conclusion + +* "Update `RevalidateAtomicAccess` to account for all bytes of a TypedArray element" reached consensus to merge + +## Needs-consensus PR: Allow `Locale.p.getNumberingSystems` to return > 1 items + +Presenter: Jesse Alama (JMN) + +* [PR](https://github.com/tc39/ecma402/pull/1074) +* No slides + +JMN. Which is the get numbering systems. If there's no objection, I have these three items in one slide. Let me try to share them. Just a moment. I use Teams only at Sony. So the last time I used it was two years ago. It takes me a second here. + +JMN: Yes. Okay. Yeah. I'm just reporting on what has happened in the 402 side of things. We have three items in a row. I expect these to be relatively uncontroversial. Just a couple of minutes. Per item here. Although, of course, we can go to the queue and take a look. After each one. The first one. Oh, just a moment. This is about the notion of numbering systems. Where we introduced a sectionally regression. And had to fix it. + +JMN: This was something that was discussed back in July. But we got some feedback from Anba saying that we needed to refine our initial attempt to revert this. We found out that there's the concept of supported numbering systems in our locale. And numbering systems in common use. Which is essentially what's going on here with this comment from ABR. And the fix is implementing that. So we essentially take an intersection of the two concepts here. If we take a look here. So now this algorithm here or these steps is essentially taking the intersection of what's supported in the locale and what's in common use. Any questions or comments? So this received support at the most recent TG2 meeting just last week. All three items that I have now received support in TG2. No one is on the queue. So we could just. + +SFC: I can't find the tab in time. But we actually discussed this a couple of times. And then I'm glad that Amba brought up this observation. And yeah, we discussed this in TG2. I'm hoping that also we can separately go through and make sure that this condition that ABR found is also enforced. And elsewhere that it may need to be enforced. And I prefer to. + +RPR: Okay. Well, we have universal support. RGN says +1. DLM says thumbs up. I support this. And YSZ also is +1. So I think we can say we have consensus. + +JMN: Okay. That's great. Thank you. + +RPR: The next agenda item or next two are also yours, JMN. + +### Speaker's Summary of Key Points + +* Three items reached consensus at the most recent 402 monthly call and were presented to TG1 to ensure there are no objections. + +### Conclusion + +* "Allow `Locale.p.getNumberingSystems` to return > 1 items" reached consensus to merge + +## Needs-consensus PR: Determine `getWeekInfo().firstDay` using First Day Overrides + +Presenter: Jesse Alama (JMN) + +* [PR](https://github.com/tc39/ecma402/pull/1097) +* No slides presented + +JMN: Yeah, that's right. Again, just reporting on what we've discussed in 402. Most recently. And got consensus on there. Here, we have the notion of weak info. Weak information. And the concept of the first day of the week of a calendar. There's an algorithm that Unicode. Encodes or defines which they call the first day overrides. And essentially what we're doing is just mimicking that in 402. We can take a look here. Just a moment. This is the abstract operation. And here if we go down to the use of it. You can see that what we do here is we essentially just defer to that. So the notion of weekend is ought to be unchanged. But then the notion of first day is supported here. Calling this new first day overrides. So think about calendars in which say the first calendar day of the week might be Sunday. It might be Monday. Maybe even Tuesday. The intention here is to respect that in 402. We can go back to the oh, yeah. Any questions or comments? + +RPR: DLM says support and SFC says? + +SFC: Yeah, this change originated in CLDR when we realized that there's four or five different extension keywords that can influence the first day of the week. So about a couple of years ago, we spent some time in CLDR figuring out what is the correct fallback order. And this PR takes that and adds it into 402, which is exactly the right thing to do. So this is the process working as intended. + +RPR: Okay. Are there any objections? No. I think we have consensus. The first day. Okay. + +JMN: Great. + +### Conclusion + +* "Determine `getWeekInfo().firstDay` using First Day Overrides" reached consensus to merge + +## Needs-consensus PR: Define %TypedArray%.prototype.toLocaleString + +Presenter: Jesse Alama (JMN) + +* [PR](https://github.com/tc39/ecma402/pull/1095) +* No slides presented + +JMN: Last item and this is something that RGN hinted at briefly. Just a few minutes ago. Which is essentially defining two locales doing on TypedArrays. On the 402 side. This was essentially defined in kind of a hand-wavy way. But here we simply do the work. So if you take a look here. We have this is the definition here of whoops. Scroll up here. So here is the 402 side array prototype two locales string. Being simplified here. And then going further. Here you can see this is new. And we're just mimicking that here. So it's just filling out something that was perhaps implicitly contained there. But not actually specified. So TypedArray two locales string. + +RPR: SFC? + +SFC: Yeah. This encodes web reality with you currently, go and try to do this. This is the behaviour you get. And it was missing in the spec. And now it's in the spec. Thank you, RGN, for noticing this. And getting the pull request prepared. + +RPR: MF supports this? Sorry. + +RPR: Any other questions or comments? Objections? + +RPR: No. If there are no objections, then you have consensus. + +JMN: Great. Thank you. That's all. + +RPR: Thank you, Jesse. + +### Conclusion + +* "Define %TypedArray%.prototype.toLocaleString" reached consensus to merge + +## Normative: Make tail-call optimization normative-optional + +Presenter: Richard Gibson (RGN) + +* [PR](https://github.com/tc39/ecma262/pull/3957) +* No slides presented + +RGN: All right. + +Room: *Laughter* + +RGN: For those who don't know, the background on this is that tail call optimization was introduced in 2015 in ECMAScript 6. And predates our current staging process. In fact, it also predates Ecmarkup. It's been 11 years and as far as I can tell, in those 11 years, it was added to just one browser and one major non-browser implementation. JavaScript core and ModdableXS implement it. All of the other well-known implementations that are downloaded by esvu do not. If someone were proposing tail call optimization today, this lack of implementation would definitely be deemed insufficient for advancement to stage four. So I'm proposing a relatively simple change here. It can be viewed on one screen. Which is that the step to discard all resources associated with the current execution context inside of the PrepareForTailCall abstract operation is prefixed as normative optional, such that the supermajority of implementations which do not include support for tail call optimization will be conformant with this operation. And I am seeking committee approval to merge this pull request and make tail call optimization normative optional. Shall we go to the queue? + +RPR: WH has a question. + +WH: Yes. Scroll to the thing that you showed initially. + +RGN: To the code sample? + +WH: Yes. The two print statements are the same, so I'm unsure which is which here. + +RGN: Yeah. There's a GitHub bug. I was using emoji thumbs up and thumbs down to indicate support or lack thereof. And at some point, either I or someone else edited this description the emoji got lost upon submission. So the distinction is preserved. JavaScriptCore and Moddable XS here at the bottom are the ones with the thumbs up. And the remainder are the ones with the thumbs down. + +WH: Thank you. + +RPR: KM. + +KM: Sure. This answer will come as a surprise to probably very few people in this room. But I mean, this was not a new proposal. This is the committee agreed to do this including members delegates from the organizations that have decided not to implement it. And in fact, many of those delegates were supportive of the idea at the time. It was standardized. The so we don't this is definitely implementable. I think the concerns about not wanting to implement it, are I think they're solvable. We've shown they're solvable. + +KM: The so we don't feel that we should be going back on things like this. I also worry that if we do make it normative optional, as people are stating, below, it will be probably then presumed banned. Which then means we have to possibly remove the set optimization, presumably for other types of proposals like having consistent stack traces or having etc. And I think it's not even clear that we can't do that anyway. And I don't want to be in a position where we are going we have to solve this problem in some other way. + +RGN: I would call your attention to this web reality label on the issue. I think it's extremely important that consumers of our specification get an accurate picture of what that specification means in terms of what they can do and what they can expect. 11 years is among the clearest signals that the participants of this committee have ever provided with respect to how they feel about integration of this feature. Again, if it were proposed today, it would be at stage three tops. + +KM: I mean, I think there are many things in JavaScript that if they were proposed today would not happen right? I don't think we would do many parts of the entire language core parts of the language probably would not would be redesigned that doesn't mean we should go back and revisit all of those even if they are web compatible. + +RGN: Well, those have implementation agreement. I can read the spec and know what a conforming implementation will do. And I have a reasonable expectation that the current implementations are conforming. That's not the case here. I can read the spec, write a function that assumes that tail call behaviour will be optimized. And then be extremely disappointed in two out of the three major browsers. + +KM: I mean, I think there's also a question of is the entire and only purpose of this spec to represent what actually engines implement? Or is it to represent what this committee feels like are the expected behaviours of the language? + +RGN: If an expectation goes unsatisfied for over a decade, I think the problem is with the person holding it, not with the people who are failing to satisfy that. And there have been other examples. So think about array sort stability. This is a thing that was never guaranteed. And because the implementations agreed, we were able to tighten it down. Even if we accept this change and make it normative optional to support tail call optimization, there is a potential future where implementations start supporting it. It does become a reasonable expectation. And then we remove the optionality. But as things stand right now, we have a spec that is inaccurate and that's just not acceptable. + +KM: I think we'll probably just have to agree to disagree on that. I mean, I disagree that that is the only purpose of the spec. + +RPR: Maybe we could try getting through the queue and uncover. + +RGN: I was just going to suggest that. + +MM: Yes. So Keith, you mentioned well, first of all, with regard to the overall issue, I want to agree with you on procedural grounds while emotionally supporting RGN's perspective. RGN says unacceptable. I agree with you that you have the right. So I want to agree with KM on the procedural issue. But emotionally agree with RGN. I think the current status quo is really terrible. And Keith, I wish that you change your mind. But as you know, I'm a stickler for the strict interpretation of the consensus rule. And to withdraw something that has already been part of the spec when there is no security emergency, I think requires consensus. The only time I would question the consensus is if somehow there is a security emergency. This is not that. But the reason I put myself on the queue was neither of those. I put myself on the queue because something you mentioned I think is at least more nuanced, if not quite a straw man. Which is if I understood correctly, you were saying that if we make it normative optional today, then tomorrow we might make it prohibited. And normative optional leaves JSC in conformance. If we prohibit tail calls, then JSC becomes out of conformance. So first of all, if JSC continues to be on the committee, then a normative change like prohibiting it you're in a position to block that. Also, there has been tremendous resistance on the committee to saying anything about what the content of stack traces is. I don't expect that to change. And if it doesn't change, then the spec is silent on the content of stack traces. The spec also never demands that an implementation reach an out-of-memory condition. + +MM: So doing more garbage collection of unobservable things is always allowed because the spec never requires reaching out of memory. And I don't expect that to change. So I think that what's being proposed here does not lead to your nightmare of JSC going out of conformance. And I don't think that so I think the proposal stands of normative optional. And I think you should respond to that in kind. + +MM: And with regard to the question you asked, what is the purpose of the spec? I would like to hear your opinion of what the purpose of the spec is. To my mind, the spec is the rendezvous point between users, tool creators, and implementers. And as a rendezvous point, if it's out of conformance with what engines actually implement in a permanent manner, that is a failure of the spec to serve its purpose. + +RPR: Okay. I think we will go to JHD because there's quite a queue. So please be mindful of the time. + +JHD: Yeah. So I agree with all the things that have been said in support of this of making it normative optional. As you said, KM, that's way back in 2015. That's essentially what we all agreed to. Anyway, we just didn't do anything about it. And this is now finally doing something about it. So I think we should certainly do this period. My follow-up question which might spawn too much debate and if so, I apologize. But I'm going to ask it anyway. Is there a reason we then it would be nice if we could then remove tail call PTC proper tail calls from the spec so that we could pursue which wouldn't make JSC in violation, right? Because the spec doesn't forbid that optimization. And then we could pursue syntactic tail calls or something similar in other words, using an explicit affordance that you want the tail call behaviour. Which to my understanding, addresses all of the issues anyone has with tail call optimization. And I assume would require a very small change in JSC's implementation. I could be wrong about that, of course. The only reason that we didn't do that 11 years ago was more of a philosophical / ideological one, not a technical one to my understanding. + +RPR: And anyone that I see on the top. + +RPR: Does anyone want to open this if this is a kind of an extra conversation? + +JHD: Yeah. And as such, it can of course be deferred to a future plenary. Or future day. + +RPR: Okay. And Chris points out we've got 15 minutes remaining. So let's proceed to the queue. So MAH. + +MAH: Yeah. I wasn't there 10 years ago. I actually do not fully understand why this is in the spec in the first place. Because my understanding is that this is dealing in an observable behaviour if the machine had unlimited resources and had basically an infinite stack. So I understand that there is an implementation reality that the stack is limited. However, I am not aware of anywhere else in the spec where we admit the fact that we actually have resource limits and try and behaviour to optimize for that limit. + +RGN: I do think it's appropriate in the spec. I would draw a loose analogy to the requirements of amortized constant time access for maps and sets. Where with the current state of the specification, it is required that even given finite resources, particular function calls are going to complete and won't exhaust those resources. That is a guarantee that can only be made because of the specific behaviour as it appears in the PrepareForTailCall. + +MAH: And so if we make this normative optional effectively, the program cannot rely on that. + +RGN: Right. + +MAH: Which is also the reality today anyway. But right. So I'm just wondering why at all as well in that case if it cannot be relied upon. + +RGN: Well, I mean, if you had interoperability on this point, then it could be relied upon. And the current specification requires that. It's just that engines don't implement this detail. And reading further down the queue, it looks like there are no plans to do so. + +MAH: Right. + +RGN: But I do think that it belongs in the spec. It is appropriate to communicate to developers that in a conforming implementation, they can rely upon not encountering resource exhaustion when they write their code in a particular way. + +MAH: Yeah. This feels as if this could take the form of an editor's note in that case. But okay. + +RPR: I think we should move on to your next RGN. + +RGN: Okay. I think this is probably a restatement of MM’s question. If the spec is at least in part aspirational rather than descriptive, over arbitrary timeframes, then I'd like some clarification on what the position is that supports retaining normative required status for tail call optimization but not in requiring uniformity as was proposed for prefixing the accessor function toString output. Because it seems like this is a participant taking opposite positions on similar questions. And I'm not sure how to resolve potential disagreements without an understanding of what it actually is that the spec should be. I really like MM’s phrasing as a rendezvous point. + +RPR: So the reply is that it's not web compatible from GIF? + +RGN: But it is web compatible to introduce normative optionality to tail calls. Clearly, it's web compatible because on the web, no one can rely on them. + +KM: Well, I'm talking about I mean, I'm completely open to the aspiration that we to have uniformity and get separate prefixing for the build and strings. It's just not a web compatible change. We tried it and then we had to revert it because it broke a bunch of websites. Because they were like, if Safari do this check for this version, if other browser check for this version, not saying that's the right practice to do, but it's what they do. It's the same problem with a lot of date things where because web pages check on the user agent precisely and then decide what they're going to do rather than falling through between possible implementations it's not compatible to switch. + +RGN: But it is compatible. Again, it is compatible to recognize reality and make tail call optimization optional. + +KM: But my objection is not about that it's compatible. + +RGN: Okay. Can you clarify your objection, please? + +KM: My objection is that this committee decided it wanted tail call optimizations in the language and we're not comfortable with removing it from the language. It's not about a compatibility. + +RGN: I think this is a good time to move down the queue. + +RPR: Yes. + +RPR: JHD. + +JHD: Yeah. I guess I should have put in a message. The spec can only be aspirational until we know we can't reach the aspiration. So for example, you tried the get/set thing. You couldn't do it. So we updated the spec to match that reality. Even though we would prefer that everyone be able to do it. It's not achievable that everyone implements tail calls. It's not going to happen. So aspiring to that is no longer valuable and hasn't been for over a decade. + +RPR: Okay. And RBR has a compromise to suggest. + +RBR: Yeah. I believe actually both are understandable. On one hand, we want to have the reality, which is it's not implemented. On the other hand, I believe it's also good to be aspirational. Right now, it's a very neutral wording. And sometimes it is about wording when it comes to this. So in this case, we could potentially say instead of it is optional, just taking it from a different angle and saying it's strongly recommended to be there because that's the aspirational character. Then there is also nothing about removing something out of existence which is already implemented. As it is recommended to do so. But effectively, it means it is optional that way. + +RPR: JHD says that's already normative optional, when legacy is absent. And I think Keith has a reply too. Go ahead, Keith. + +KM: We, I mean, we think that the spec is correct today and that web pages should be able to rely on tail optimization. Web pages or any scripts. It doesn't have to be web pages. So it's not that we don't think that this is a good part of the spec. We actually do think that it should be part of the spec. + +RPR: Okay. And then you have a question about other implementations? + +KM: Yeah. I guess I'm curious from other implementations if they want to speak or not. Why not implement tail optimization? I'm curious if it's the same reasons that were presented many years ago or if reasons have changed. I also don't want to take the whole thing the whole time to go over that. But. + +OFR: Actually,I don't have a good answer. I think this was decided before my time. And not revisited recently. I know that debuggability is a concern. Basically, not being able to set a breakpoint and then basically your stack is gone and you don't know how you ended up there. I know that that was one of the biggest blockers I think. And I'm pretty sure that that would still count as a yeah, as a how should I put it? As something that we would think would be a regression if we added it. And also I want to okay, maybe this is a different topic, but I mean, no, let me put this as a different topic. + +DLM: (from the queue): From the Mozilla side: doesn't know the history. Sorry. + +RPR: And I see that KM says worth noting that the backtrace issue is solvable because JSC does it. So onto SFC. + +SFC: Yeah. I mean, the way that we deal with any other features that are not consistently implemented is you just let engines fail the test262 tests for the things they don't implement. And why should we do something different here? + +RPR: OFR has a reply. + +OFT: As I understand it would not be possible to write a test262 for this. Correct me if I'm wrong, but range error is not part of the spec. So I wouldn't know how to even write a test for this. + +RGN: Yeah. I agree with that. This is not the kind of thing that test262 is set up to cover. + +RPR: So KM believes that there are tests. And YSZ says if I recall correctly, test262 has several TCO tests. + +KM: Right. To clarify, you cannot write a test which is free of both false positives and false negatives in the abstract. Right. Because if you in fact have unlimited resources, then whether you implement tail call optimization or not, you will fail to exhaust those resources. + +RPR: Reply incoming. + +RGN: Correct. Yeah. GC tests have the same characteristic. + +KM: Yeah. There's no GC there's no WeakRef tests that have no false positives. As well. So we have tests for things that I don't think this is going to be something to remove. That yeah. + +RPR: Just waiting for the replies so I'll just say whilst we're waiting for this plus one support from CDA. For the whole proposal. + +RPR: JHD says: so let them have failing tests. Is not intended to be a coercion tool. Just an indicator of reality. What most of the web does is web reality. Thank you. + +RPR: WH says: Fine with normative optional. Don't delete tail calls altogether. + +RPR: DLM says: support normative optional no plans to implement TCO. And Matthew says whilst I don't think normative optional is even necessary, I support it as a resignation to reflect reality. + +RPR: Then CDA says please consider updating your browser. Not sure what that means. Oh, sorry. That's a comment about the UI colour scheme. And it means nothing more than that. + +RPR: But CDA, would you like in the last minute, would you like to talk about history? + +CDA: Yeah. Just real briefly. I just did a quick search in the notes repo. I think it was back in 2016. The Google position was that they could implement it, but silently deleting stack frames from ordinary existing return F code is bad for debugging profiling telemetry and developer intent. And Mozilla had security concerns across realm security membranes fundamentally interfere with the bounded space guarantee and programmers cannot know when those membranes are involved. Plus, we share many of the debugging and predictability concerns. + +RGN: Is it a final comment in this time slot? I've been encouraged to request an eight-hour extension. Does anyone feel up for it? + +RPR: I'm actually really pleased that everyone has been respectful of time here. We've got to the end of the queue. + +RGN: I will again supply the summary offline and I think this will be put back on the shelf for now. + +RPR: Okay. Thank you, RGN. + +RGN: 10 more years. + +### Speaker's Summary of Key Points + +* Despite being required by the spec for 11 years, a supermajority of implementations do not optimize tail calls. +* There was much support for the PR to make tail call optimization normative optional, but it was not unanimous. +* There is no current intention to optimize tail calls in SpiderMonkey, V8, or any other implementation that does not already conform. +* A question was raised about whether introducing syntactic tail calls would resolve the objection to this PR, but it was not answered. + +### Conclusion + +* The PR does not have consensus. + +## Establish normative conventions for invalid input strings: RangeError vs. TypeError + +Presenter: Richard Gibson (RGN) + +* [PR](https://github.com/tc39/ecma262/pull/3982), [PR-comment](https://github.com/tc39/ecma262/pull/3982#issuecomment-5774277939) +* [slides](https://docs.google.com/presentation/d/1beXrmkClhi-J0NvgoppM4yj4uWIcgQppytVG7IBNC8s/edit?usp=sharing) + +RGN: So this is an attempt to establish normative conventions for invalid input. RangeError versus TypeError, versus… we will see. First, an excerpt from the spec. We've got a section describing native error types. There's a fairly large handful, a lot of them don't see much use. Some of them are legacy, but these three at least are still in active use. In alphabetical order, RangeError indicates a value that is not in the set or range of allowable values. SyntaxError indicates that a parsing error has occurred. And TypeError is used to indicate an unsuccessful operation when none of the other native error objects are an appropriate indication of cause. Going over a little bit of incomplete history of their use, some of which are in external documents that don’t get versions… I didn't have a chance to do full digging. But the earliest example I found is one of ours. It's ECMA-402 in 2012. Among other options, `Intl.Collator` validates `usage`. When usage is not one of the known valid strings, it throws a RangeError. Also, when in `Intl.NumberFormat`, `currency` is not well-formed, we have a RangeError. And coming over to ECMA-262 in 2015, the introduction of `String.prototype.normalize`, its `form` parameter accepts only four values and otherwise throws a RangeError. Skipping forward by almost a decade, Temporal has APIs that act like the ECMA-402 ones. When a value is not well-formed or when it is well-formed but not valid, we get a RangeError. And then hot on the heels of that, some recent proposals that haven't even made it into an annual edition yet. `Iterator.zip`, `Iterator.zipKeyed`, and the UInt8Array base64 APIs have respectively `mode` and `alphabet`, and when those strings are not valid, we get a TypeError. Briefly looking further afield, in HTML, there are a handful of legacy APIs like insertAdjacentHTML that expect a string from an enumeration and invalid strings result in a SyntaxError. Modern WebIDL has guidance to say when a string does not come from a particular set of valid values, that the result should be a TypeError. That last guidance was used in the context of our recent ECMA-262 proposals to justify TypeError in response to an issue that was suggesting RangeError. So as you can see, we've got a mix of behaviours. The older ones tended to prefer RangeError, but arguably even in inappropriate cases, like well-formedness violations. The newer ones, especially in the two recent proposals, have been specifying TypeError, citing alignment with the web. And then as a bonus, not specifically requiring consensus here, but maybe we can also get it, here are some examples of runtime SyntaxErrors… JSON.parse, BigInt, eval, Function. And there are a number of cases in Temporal that currently are specifying RangeError for similarly ill-formed inputs. So we're in this kind of weird state right now where, as the previous slide shows, there's guidance for when the specific kinds are appropriate. And then there's the actual specified APIs that don't quite align with that guidance. What I'm seeking today at a high level is normative conventions either to strive for using these errors under particular circumstances. I don't think RangeError is going to be abandoned for things like numeric bounds where something must be from A to B. But at least with strings, we have a variety of behaviours and I would like to be able to write down some clear guidance. Are we committing to following the guidance implied by native error type descriptions in ECMA-262, possibly with a few updates? Or are we going to kind of adopt the base64 and `Iterator.zip` approach of treating string enumeration violations with a TypeError. I don't have strong feelings about it. I think there are decent arguments in both directions. If others have strong feelings, I think that can guide the discussion. But if I'm forced to share an opinion, I will do so in the pursuit of actually getting some resolution here and writing down what we want this to look like going forward. And in particular, it might affect Temporal either in the existing proposal or as a fast follow. Probably the latter. + +RGN: So with that, I'm ready for queue items. + +JHD: Hi. Okay. So I think type error is wildly overused. And I think WebIDL's definition is just bad. Literally, the description of the thing that you read says in the range of allowed values. And we have something called range error. So it doesn't make any sense to me to use anything but RangeError for that case. And I just think we should use whatever error type actually makes the most sense for a given thing. If we can describe that and make a rule out of it, awesome. But I don't care if there's a rule or not, as I care that we use the error that makes the most intuitive sense. If we're not going to do that, then why don't we just use bare error for everything? There's no point in having all the subtypes if we're not going to actually make it make sense. And TypeError for something that is the correct type but not a valid value is completely nonsense. + +MM: Yeah. JHD, in my experience with JavaScript is that I've seen code that switches on SyntaxError or not. But I've not seen code that switches on TypeError versus RangeError. So the thing about if it was green field, should everything just be an Error? It might still be worth distinguishing SyntaxError. But yeah, I would say that the differentiation to error classes is only historical baggage that we're carrying forward without being able to make sense of it. And that's why I'm enthusiastic about the code proposal. Because it gives us a fresh chance to enable programs to switch on a meaningful taxonomy but the error taxonomy we have is just beyond repair. + +JHD: So I definitely have seen code that switches on all the various types. But it's always when typically, that's just trying to detect quirks or specific agents or whatever. Meaning it's not about what the type is. It's just about what that the type can tell you about the environment. So I'm not really I don't really care about those use cases. I'm talking about just debuggability. I want error types to be useful to humans. I don't want code to be checking it. I want humans to look at it and have it make sense. And I think that and I agree with you completely about the code proposal. That will also help. But having everything be an error with just a different code is also not very helpful when you're looking at stack traces and logs. + +JHD: If something is a RangeError, an error in a range, it should be a range error. And then the code should give you the specific information. + +MM: I pass. + +SFC: Yeah. There's been a number of examples that have come up over the last couple of years where the question is, WebIDL says we should do this thing, but TC39, we've done this other thing. Case and conventions come to mind. I know there's others I didn't look up all the other examples. But I think that there's two there's two outcomes here that I think are reasonable outcomes. One is that we are self-consistent within to ECMA 262 and ECMA 402, in which cases, we should use RangeError because that's the oldest and biggest set right? And consider the two that aren't using RangeError to be anomalies. And then that's one reasonable outcome. The other reasonable outcome is we do a global we take a step back and be like, should we be aligning more with WebIDL? Or should WebIDL be aligning more with ECMA script, right? This is actually a good example. Maybe we actually want to go to WebIDL and be like, maybe there's some things that WebIDL does we want to integrate. Maybe there's some things that we do better than they do than WebIDL does. And then we want to maybe push those out there and do an actual concerted effort to resolve these types of misalignment issues. But I don't think that we should be taking these little things and saying, oh, because WebIDL does it, we should do it. I don't think that's the right approach necessarily. + +WH: My question here is, why don't we just use the existing guidance as it is? It's something which is very tricky to legislate in the abstract. If we have specific controversial cases for which it's unclear how to apply the existing guidance, that would be interesting to bring to the committee. But just trying to say, should we continue to do this or not in the abstract?—I'm not sure how to answer that question in a productive way. + +MF: Do we have the exact text of proposed guidance? + +RGN: No. My plan is to ideally get an agreement in principle here. And then come back with some text that documents that agreement. The short description of it is going to be an enumeration of cases where we feel like RangeError is appropriate. Ideally, also an enumeration of cases where we feel like SyntaxError is appropriate. And as you can see on the screen, TypeError is kind of the catch-all for just about everything else. And the question on the table here, more narrowly, is for when there is a collection of valid strings and the input is a string outside of that, whether we want to use range error or TypeError. + +RBR: I believe TypeError is currently in the ecosystem itself. Used a lot for input validation. And it's more like why is it used? Because there are no other more specific error types. Which is good for debuggability that Jordan was speaking about. So it was more of which is seemingly the one that fits best from the existing ones. So maybe we don't have enough types for representing that. That's something I would like to bring up as a question here. And second part is, when it comes to the range error and differentiating it to type errors, I do feel that RangeError is often used as a subgroup of the TypeError when it comes to input validation. And because it is more specific, it is really about numbers in this case, or some kind of range that you can represent as such. So that's easy for a human to understand what it represents. And I believe that that should be the focus of the classes that we have. + +RGN: Well, our own guidance does not limit RangeError to numbers. Nor does our long-standing behaviour. So I think there's support for the case of using RangeError. I don't think either decision is particularly bad. ECMAScript has a long history of very impoverished error classes. That's the justification in part for adding `code`. But impoverished is not the same as singular. We do have these types. We do already use them. And it behooves us, I think, to decide whether or not to continue using them. We have no intention of ever introducing a new source of URIError exceptions. But I don't think that's true for the three in question here. + +CDA: Shane looks like you have the next three topics. Do you want to go in order? + +SFC: Yeah. Just the first one is just my someone asked earlier like, well, about can you explain more clearly the definition here? My fuzzy mental model is that a TypeError is a thing that I should not get if I use TypeScript. But this is not completely exactly correct because there are things that are type errors that are not type script errors. But that's at least for me, that's like when I'm writing 402 spec and I'm like, is this supposed to be a type error or a RangeError? I look a little bit at the ECMA script guidance that was on the slide earlier. But I also just think like, is this a thing that TypeScript would catch for me? And then a RangeError is like, okay, it's the right type. It's a string. TypeScript is happy. But the string is the wrong type of string. And with TypeScript, you can do like string enums. I think TypeScript support has supported those for a long time now. But that's, I guess, my fuzzy that's why I emphasize fuzzy mental model, for the difference between a TypeError and a RangeError. But I think that there is something to go and I think. This topic two, looking at the guidance again, it raises questions about there's some examples where there's a syntax error and I'm wondering whether when we have a grammar and if something doesn't obey the grammar, should that be a SyntaxError? If it doesn't obey the grammar, question mark. Topic three, I've definitely written code and I know a lot of other people write code that when I want to tell when I actually want to branch my code, depending on what error was hit, I never look at type error versus RangeError in general, unless I can. If I can, it's great. But usually, I look at the error string, which is a terrible thing to do. But that's what I've written code that does that. And I know a lot of people write code that does that. So that's kind of the status quo for what people have to do. And it would be great if we could actually give them something better. Like actual error types I think that this example that just got brought up about URIError called, maybe we should be doing more of that. If there is an error type that's not clearly the same in the same class as a pre-existing one, just make a new error type for it. It's fine. + +RBR: I second and have more dedicated error types for some parts, especially when it comes to error classes and different both directly to the formal part. Then you were speaking about exceptions, that are also already existing not only about a specific error type, but I believe also about sometimes something being a TypeError or a RangeError where it doesn't really make a lot of sense. And I believe that's kind of natural. I believe we will always have cases like that. The ecosystem is never fully consistent. And I believe even here, it's sometimes a little bit fuzzy in what is right or wrong or do we always perfectly get it right in the first pass. As long as it works pretty much in most cases for this because these errors will be read by a human ideally. Well, maybe not in the future anymore. But at least for now, still. So therefore, making them easy to understand is what I would target, in average. + +JHD: So I'm going to take a minor risk here and say that this is actually, I think, analogous to the term transpiler. There's a group of people that get angry when they hear that term because they say, no, it's just a compiler. When in fact, it's actually describing a subset of compilers. That distinction may not matter to many people. And that's fine. But it does matter to some people. And that is why the term exists and is useful. Similarly, there may be plenty of people that think that all errors are just errors and there's no point in having subtypes and we should just only have error. And that's fine. In their applications. But the distinction of RangeError may actually matter to some people. And it from debugging, from literally just looking at stack traces, it does matter to me and has mattered to me and many of my colleagues over my career. If you don't want to use the extra information, don't. But that's not an argument to deprive the rest of us of something we find valuable. + +CDA: The queue is exhausted. + +RGN: So one thing I would like to do now, I think, is a temperature check. Just to summarize opinions on the preferred error type when I provide a string that is not in the set of allowable strings. So looking at, for instance, near the bottom here, `Uint8Array.fromBase64("", { alphabet: "WTF" })`. Should that be a RangeError or a TypeError? Let's say thumbs up for RangeError, thumbs down for TypeError. + +\* preparing temperature check * + +CDA: Unbelievable. RPR is not here to tell us a joke while we figure this out. + +\* RPR walks in, tells a Joke, and walks out * + +CDA: All right. The TCQ poll is up. Temperature check. Please indicate your preference. + +**Poll:** Uint8Array.fromBase64("", { alphabet: "WTF" }) (1 min, 24 voters) + +* 👍 RangeError: 18 +* 👎 TypeError: 4 +* 🤷 Indifferent: 2 +* ❓ Confused: 0 + +CDA: You have 18 for RangeError, 4 for TypeError, and 2 indifferent 0 confused. + +RGN: Okay. And the last moments of this topic, now I'm interested in understanding how strong people's opinions are. If anyone is willing to go on the record as objecting to not getting their preferred option, and in the absence of that, then we can do it anonymously via temperature check. + +JHD: I will. So WTF as an alphabet value, is the set of alphabets isn't a type. There's not alphabet types. So I don't think in any way that it should be a TypeError, and I would object to that. + +MF: Okay. I think that this is a longer discussion than we have time for. And I would like to actually have this discussion at one point. The brief form of it is I am of the opinion there is only one type in JavaScript. You can pass any value to any function that expects anything. They're all just values. There are functions and operators that distinguish between some of those values and treat some of them differently than others. That does not make a type. That being said, we can use our intuition about what we feel are things that are different enough and what our expectations are and we can say that is the thing that should be associated with a TypeError. And in that case, I come down on the side of these things producing a TypeError. How strongly do I feel about that? I think it really doesn't matter. But I don't want this to lead to any kind of precedent that we consider these things like separate types or same types or anything like that because I think that is a longer conversation that we should have but we don't necessarily need to have right now. + +CDA: I apologize, but I just noticed that we are past time. So I have captured the queue in case you want to continuation. It might be a good idea. And we must move on. + +RGN: Okay. I think that works for me. I have enough input here that I or someone else can present something concrete for the next iteration of this discussion. And I will probably do so. Thank you. + +### Speaker's Summary of Key Points + +* ECMA-262 describes intended semantics of native error types which are inconsistently followed. +* Older ECMA-262 and ECMA-402 tended to prefer RangeError, even for well-formedness violations. +* Temporal has even broader use of RangeError. +* Other recent ECMA-262 APIs, particularly joint iteration (Iterator.{zip,zipKeyed}) and Uint8Array to/from Base64, use TypeError for strings not included in a finite enumeration of valid values, aligning with WebIDL. + +### Conclusion + +* Regarding the appropriate error for “a string that is not in the set of allowable strings”, a temperature check revealed 18 in favour of RangeError and 4 in favour of TypeError (and 2 indifferent). +* It might be reasonable to seek changes in WebIDL. + +## Iterator Join for Stage 4 + +Presenter: Kevin Gibbons (KG) + +* [proposal](https://github.com/tc39/proposal-iterator-join), [PR](https://github.com/tc39/ecma262/pull/3948) +* No slides presented + +KG: Okay. This will hopefully be quick. Iterator prototype join is at stage three. It is shipping in all major and many minor engines. I believe it's in stable Chrome and Firefox. I don't know if it's in stable Safari, but it's unflagged, so it'll get there eventually. There's tests, of course. There is a pull request approved by four editors. The pull request is fairly small. I would like to request stage four. + +CDA: You have support from DLM and MM. Also from LVU. And JHD. Presumably CM. Yes. Support from CH. As well as YSZ. Do we have any objections to stage four? Also support from MF. All right. Sounds like you have stage four. Congratulations. + +KG: Thanks very much. + +CDA: Oh, also support from CHU. + +KG: The microphones do an astonishing job of filtering out the sound of applause. I appreciate the applause and could not hear it. That was very strange. + +CDA: Well, it was loud in the room, so. + +### Speaker's Summary of Key Points + +* Proposal is shipping in all major and many minor engines, and has an open pull request approved by four editors. + +### Conclusion + +* Iterator Join advances to stage 4. + +## Structured TC39 data status update + +Presenters: Michael Ficarra (MF), Jordan Harband (JHD) + +* [repo](https://github.com/tc39/data) +* [slides](https://docs.google.com/presentation/d/1Qr0soLiTxn6od612KAnkDttMDhyS1BBRmFjmd9ken8Q) + +MF: I wanted to give an update on the topic that we discussed last meeting on representing all of our data that we maintain in a structured machine-readable format. So as a reminder, this is what our goal is. This is what we kind of decided directionally to do last time. We want to have a repository of machine-readable data sets for all things related to TC39 for use in things like tooling, analysis, verification, configuration, integrations, whatever you can think of. Examples of those data sets. We have all of our proposals and their current stages, their associated stage 2.7 reviewers and their tests, their presentation dates. We have our process, how our stages are related to each other and what their entrance criteria are, what their names are. We have all of our delegates, 600 of them, and their affiliations if they are current. We have our specifications and other documents that we publish. We have our normative conventions. We just talked about it in the last session. We have all sorts of roles that delegates hold and then those associations to the delegates. We have our agendas. Meeting dates. There's so many of these pieces of data that can be more useful to us if they were integrated into tooling that we build. So the status is we now have a repo. We've put everything in this monorepo at the moment. I think that's the plan going forward. So this repo is at tc39/data. Here's a quick look at the plan and where we are with things. So I have for now the delegate data in the repo. That's been published to NPM. The first step is we want to just take your existing workflow and have it backed by this canonical source. We have a pull request that auto-generates the `delegates.txt` kind of like you use it right now from that published data. So we're no longer in need of manually maintaining delegates.txt. In the future, we would like to have something more usable than `delegates.txt`. So you can sort and search and that kind of stuff. Like a web UI, but that will be future work. We also have the TC39 process encoded in the repo. And we've published that as a package to NPM. And we have in-progress pull requests for all of the TC39 proposal data. A pull request to add all that data and then also a similar pull request to generate all of the markdown tables that you're used to using on the tc39/proposals repo. So again, the plan that we're trying to follow is to kind of silently swap out all of the things that exist today, very transparently, and have them actually all generated from the structured data sets. And then as a follow-up step from there, make better, more usable ways of interacting with that data. Actually reap the benefits of this plan. + +MF: So I want to talk about a lot of cleanup that I've had to do of this data as I'm processing it. Our data practices have not been good over the years. We have missed lots and lots of things. We obviously have great record keeping with the notes, but actually associating those notes with proposals—it's just ad hoc and lots of it has been missed, as well as a lot of other data maintenance stuff. So as part of this process, I have gone through and with great help from AI assistance, added 600 associated references for proposal presentations to all the various proposals. So now you have what we feel is an exhaustive list of all the times each proposal has been presented, rather than just one or two maybe. There are also lots of broken links that we've fixed. Now all of the proposals have all the relevant test262 links as well. We had lots of missing data on stage 2.7 reviewer assignments. During this process we've also actually defined the inactive stages that we have. I'll talk more about that in a little bit, but we have an inactive proposals table and they are at the moment assigned to these different stages that I want to formalize. There's also, in the `delegates.txt` file, there are delegates whose names are no longer the preferred names of those delegates. So based on the GitHub data that we now have associated with them, I've gone through and cleaned that up. I'll talk more about that one as well. Oh, yeah. The affiliation with the Ecma member was previously only available through the GitHub Teams that people are assigned to. That's now also available in there. And I was able to associate 442 out of the 581 GitHub handles with delegates, which is actually, I think, a really, really good result. We can't get to 100%. Some people probably don't even have GitHub handles. Remember this committee predates GitHub. So as you know, not all 581 delegates are active or even recent at all. So I think we may be at the point where there are no more to discover. So that's all really handy information to have. + +MF: So on that first topic, I wanted to cover in more detail acknowledging de facto inactive stages. This is what the inactive proposal table looks like today. As you can see there's a rationale column. And there's a tag at the beginning of it. See: withdrawn, rejected, postponed. So we, as a matter of fact, have these additional states that proposals enter when they are no longer being worked on. So as part of this presentation, I would like to reach consensus to officially acknowledge these states. So it doesn't have to be exactly this. I'm open to changes. In fact, I don't think it should be this. But these are the closest to what we have already assigned these in our current records. So again, just when you're doing this data cleanup and you're trying to make everything regularized, you have to make things fit into your system. And this is the best fit that I see for the data that we have today. I personally don't think there should be a difference between abandoned and withdrawn. That's a conversation to have in the future. This closely matches our data today. So I'll come back to this later and we can read the exact descriptions together if you want. But that is something I would like to ask for consensus for. + +MF: And yeah, we can reference this if you want. These are how the proposals that are currently inactive fit into those buckets. Again, we can reference this slide later. On the delegate name thing, + +JHD: I just wanted to point out this stuff, it was very ad hoc. I was just trying to organize the proposals in the inactive proposals table. And so I came up with these terms. So if they're not ideal, we can totally change them. It is literally just I decided to do it and I did it because I wanted to put more context in there. So if you have any thoughts about how to improve this stuff, that's more thought than was put into naming it in the first place. So please let us know. + +MF: Yeah, yeah. Personally, I feel like we should take this kind of staged process with this. Kind of like what we're doing with how we consume delegates.txt and stuff, where we just try to transparently swap out what we have and then work on improvement later. So I think we should just try to match what we have as closely as possible and work on how we can always reclassify these things later if we have a better formulation. + +MF: So for delegate name updates, we have generally two sources of data for delegate names. We have the data that was entered into `delegates.txt`, usually by that delegate themselves at the time when they first participated in the committee, and basically never gets updated. Then we also have information on almost all of those people from their GitHub profile. That would be how they would like to present themselves on GitHub, which they are allowed to update at any point. This could be a very difficult process, but I think luckily it actually fell into—it was rather straightforward because everything fell into these simple buckets. So where those names differed, they were one of these cases. So many of them were just abbreviations like somebody only providing a first name on GitHub. That kind of thing. So those were easy. You just take the person's unabbreviated full name that was provided. There were cases where the delegate's GitHub name matches or contains the GitHub handle in which case that was assumed to be a pseudonym. So again, taking their delegates.txt name. There are cases where there were just styling or capitalization differences which were probably inconsequential, but also easy choices. And then there were cases where there was a completely different name. And in those cases, you prefer the GitHub name. Because again, it's the way that delegate likes to present themselves to the world today. The only case that I thought was questionable was this one. I don't know who Subo Zheng is. This was the only thing I felt was a judgment call. If anybody knows who this is or how to contact them, I would love to use their preferred name. But because their GitHub name was an English word, I figured it may have been a playful name and kept their delegates.txt as the more reliable fallback. So anyway, I know that names are a very sensitive topic. I am trying to do my best and be as respectful as possible in this process. The end goal is to just have more delegates referred to by the names that they prefer to be referred to. There's like 600 people on this list. I can't reach out to everyone who would be affected by this. The second source that we have is GitHub just because we have the handle available for most delegates. Happy to use other sources if we have those other sources for these people. Yeah, during this process, I tried to not make any assumptions. I think luckily I didn't really have to other than that one case. Oh and I think that this is an important problem to solve because the status quo includes names that people would specifically not like to be referred to such as the names they were born with or their deadnames. But if you have any concern about any of these choices or you have any more information about them, reach out. We can try to improve it. Yeah, and examples of sources you can provide for these things: if they have publications or a personal website, a portfolio, LinkedIn, these kinds of things. We can use those as additional source evidence or we could, if you have contact information, we can just reach out to them. Oh, so yeah, this is not a perfect process. I think it's possible that we have actually succeeded at being 100% aligned with what people's preferred names are. But I think that it brings us to a much better place. I think it's an improvement and that was why it was worthwhile to clean up this data. I wanted to show this trolley problem picture as well because I think this is kind of where we are. We know that there are more cases—well, sorry. I am highly confident that there are more cases where somebody prefers their GitHub name and would not like to be called by the delegates.txt name than there are people that prefer the delegates.txt name and would not like to be called by their GitHub name. And there's no virtue in not doing anything here. It's actually—by not doing anything, we are making the choice that more people will be referred to incorrectly in these documents and within committee. So I think we should act here. And then JHD wanted to jump in. + +JHD: So I also want to point out that the delegates.txt listing in the majority of cases actually didn't involve the delegate in question. Anyone that predated that file we just summarily added and unless they thought to check it might not match what they want. Additionally, the typical process is that the person who is inviting somebody to be a delegate like the main point of contact for the company is the one who makes the pull request to the notes doc and the delegate themselves is rarely even involved in that PR. So certainly we want everyone to be described by their preferred name. But it has often been a sort of ad hoc decision by not that person. Additionally, in notes, I always try to change references that say "Jordan" to be "JHD". Because that way I'm consistently referenced. But I don't do that for everyone else because it's too much work. So there are a lot of cases where names will appear in notes if you're the presenter, certainly, but also if you're just mentioned in conversation. That as is mentioned on the queue, that if your name changes, that's a lot of places you might need to go update. Whereas if we only use the abbreviation, you wouldn't need to. So there's a lot of just as MF said, this is not getting us to a perfect place. This is getting us to a better place and we can iterate here. As needed. + +MF: All right, so continuing the presentation, how do these changes affect you? If you're just like a person who's consuming this, as I said, we're trying to be super transparent with this and there should be no change to your process. You just open up delegates.txt and it uses the data source from the data set. You open up the tc39/proposals repo and you look through the tables. They'll just be much more complete and accurate now. So yeah, the vast majority of you, I think, it's not going to affect at the moment. Hopefully in the future, you will actually have a much improved process once we start actually generating better things than the simple text files and Markdown files that we have today. For people who are authoring proposals and stuff and for JHD, the structured data is where we should maintain stuff. Don't directly update it. Update the sources of those now-generated files. They're not technically generated now. They're still landing in PRs. But very, very soon they will be. For chairs, we need to work through updating our processes because right now our onboarding process is—part of it is adding to delegates.txt. We need to say add to the structured data instead. So we'll get those worked out. We'll make sure all the processes that the chairs use are accounting for the new structured data sets. And yeah, similar thing with affiliations. We have to track it on GitHub. Unfortunately, that is a place where things are going to be duplicated. There's no way to avoid that because a lot of GitHub permissions stuff is managed through the GitHub teams. Going forward, I still do think that this is something that the committee shouldn't really try to micromanage. If this is the way that JHD wants to present our records to the world, I think that we should allow the administrator to do that. But of course, if we ever take issue with it, we have the right to get involved. So these are the things I would like to talk about. Very strong preference of doing things in this order. So I think I'm going to strictly manage the queue. And yeah, so first thing, I would like to have any necessary discussion about the inactive states and then get to a point where we can make a call for consensus on that. Because I really expect it to be uncontroversial. + +CDA: Shane has a question. The answer is that it's public. It's already public. + +MF: Yes. We have Chris with stage or status? + +CDA: Yeah. So I don't want to recognize these as stages. Like in the formal way that we have stage one, stage two, stage three. Because it can't be a state machine. Because if you have a stage two proposal that's just been abandoned, it's still stage two, right? So I would like to not think of the mental model of these should be a state or a property but not a stage. + +JHD: So when I was thinking when I made this column in that table was trying to convey information about why a proposal is inactive to people who have ideas, whether it's delegates or not, so that they know if it's worth trying to pursue them or not. So for example, when I put withdrawn, I was implying that anyone who wants to could bring it back. And when I put rejected, I was implying you really should understand and research and talk to people before you waste any time trying to bring this back. I was not trying to imply that something that's marked rejected can't be brought back. I was just trying to save time for the person who wanted to. So I kind of agree there that I don't think we need to adopt this as a state machine thing. Maybe just lightly agree that we're okay with some sort of labels here to convey why something is inactive. But it doesn't but be very clear that that doesn't lock anything in. + +CDA: Yeah. No, all of that sounds great to me. I just don't want these to be actual a stage with a capital S. There's a reply from Ashley. + +ACE: Maybe they already but can these be derived things so we can actually based off the data rather than a separate field? I think if one of them was it wasn't stale. It was similar. That sounds like the type of thing that can be derived from the fact it hasn't been presented in so much time as opposed to something that we actively mark and yeah, I kind of also share I think some of Chris's concerns. + +MF: So all of the ones that are listed there, have happened that transition, you can point to a topic in committee where the committee discussed that and that happened. + +ACE: You can't point to something being stale. It's derived from the fact it hasn't been talked about. But we don't officially abandon things. + +MF: Yes, we do. + +ACE: Especially when I'm not taking notes right now. We can just maybe have officially withdrawn things, but we also have a lot of things. And Peter does a really good job of once a year let's do a cleanup and go through things. There are proposals that we haven't officially withdrawn. But clearly no one is working on them, at least not publicly. + +MF: Yes. There is a difference between when the champion group has come to committee and asked to officially withdraw a proposal and when somebody else from committee has come to committee and asked is there anybody still participating in committee who is part of this champion group? Or who would like to take over this proposal? And if nobody steps up to that, we consider that abandoned. So these are two separate kinds of—I think that that's an important distinction that should be communicated. So that's why I have those two stages. + +ACE: Yeah. I think you are saying what I'm if every status is tied to a concrete thing, as opposed to it just being its own field, then yeah, I think that satisfies my desire. + +JHD: So yeah, anything that is in the inactive table was a result of either a committee decision or an explicit statement by a champion somewhere, even outside of meetings. So I didn't just arbitrarily put things in that table. I only did it when I was told to, basically. + +MF: I can also show the text. It might be a little bit small on here, but it kind of clarifies that. You can read there if you want. + +CDA: So we are technically at time, but I just extended the time box by 15 minutes. And cannibalized my topic. So let's continue. Peter. + +PKA: Yeah. So I'm trying to figure out how we decide something is rejected versus withdrawn. I feel like there are a lot of cases where things are, let's face it, rejected. But what happens is that somebody I mean, we just saw earlier today RGN put something forward for a consensus. Keith spoke strongly against it. And RGN said okay. And there was sort of an implicit rejection. And maybe also implicit withdrawal in the face of implicit rejection. So I'm just wondering how do we deal with that? I would prefer to err on the side of being really explicit and saying what really happened and people not getting the wrong idea that like, oh, we just decided we didn't want to do records in tuples anymore or whatever. So yeah, just curious. + +JHD: So the difference that I used when I just applied the label is I put rejected when the committee wasn't interested in solving that problem any further or wasn't interested in the only form of the solution that seemed viable. By my reading of the notes or my participation, yeah, whenever it was simply so in this case, for RGN's case, I would not put that as rejected if it were a proposal. I would put that as I don't know. I don't know what I would put that as actually because it's not necessarily withdrawn. It's also not rejected though because it was it didn't achieve consensus, but that's not the same thing. So just to be clear, that's I wasn't envisioning rejected as somebody said no. I was rejecting it as enough people said no that please don't bring it back. It's a waste of time. + +MF: Right. So I don't want to get too into the nitty-gritty details of this. The thing I totally get is that these are not ideal. And this isn't me asking to—we could totally have this conversation. But this would need hours, right? And all I was asking for here was if, as the data is described today, we could just acknowledge that as a committee we had consensus. If it's too difficult for that, I can skip that. But I don't want to go into actually what the ideal is because I agree it needs further refinement. + +CDA: Yeah. Excuse me. I had a reply on the queue. Yeah. I agree. Some things are maybe some grey area. You pick the best effort one and hope that you're describing it in the most accurate way without getting into too much nuance. And I think that's fine. RG is making me read this. In all caps, saying we are not done with tail call optimization. Peter is next from the queue. + +PKA: Yeah. So this is more just pure bike shedding. Subsumed doesn't quite seem like the right word to me. I feel like that means one proposal got fully absorbed into another one. I feel like maybe preempted is the right word there. Because there are we go back to the list. There are some that were really different proposals, but they just don't make sense anymore. They're just rendered moot. Mooted maybe. + +API: Mooted. + +MF: Okay. So again, I don't want to get into this conversation. I don't want to get into that. + +PKA: I can open an issue. + +MF: Please. Yeah. Yeah. If we cannot adopt these exactly as-is, I'll come back a different time. We just don't have the time to cover that in this conversation. So I guess it might be ambitious, but I should try to get to the second bullet point. So the first bullet point would be—you know what, let's skip the—I'm not even going to ask for consensus then for the first bullet point. It seems like we have difficulty with that one. So I would like to hear-. + +CDA: Can I ask that you do? Because I don't think that I think we should try. + +MF: Okay. Even with you as well. + +CDA: As long as we don't call it a stage. + +MF: See, okay. + +CDA: Because if we are we often reconciled that? + +JHD: So more like consensus to continue with the current labels until better ones present themselves. Which are not stages. They're not changes to the process. They're just changes to the way we describe proposals. + +CDA: Isn't that the status quo? + +JHD: Yes. + +MF: They're listed in the table. + +JHD: Affirming that we can keep the status quo as we migrate from one markdown storage to JSON storage. + +CDA: Okay. Do we have consensus to continue down that path? I support it. + +RKG: Sounds good to me, modulo bikeshedding. + +JHD: Bike shedding is welcomed outside of plenary time. And we can iterate on that as long as it's not a blocker. + +??: And I will bring this back for our topic to actually see what you want to do further down the road. + +CDA: The bike shedding will continue until morale improves. Do we have any objections to that? Seeing nothing, hearing nothing. Okay. I think we're good. Should we move on with the queue or? + +MF: Can we have any topics on the data cleaning process for proposals? \[silence] Okay. Do we have any feedback on the data cleaning enrichment process for delegates? + +CDA: Yep. I think that's the next topics. The first one is mine. So I think broadly, I think many of those changes are fine. But I understand and agree you're not going to reach out to hundreds of delegates from the past. But for delegates that are currently active and are subject to some of those changes, it would be great to get informed consent. I don't know why it would be controversial that we would display their GitHub favour that. But SFC is one of the individuals affected by that. DLM is another one. I don't see why they would find it controversial. But I still think I would feel better if they gave their thumbs up about that. So SFCs name going from I think he's just adding the initial. Right? Sorry to put you on the spot. Sorry about that. I'm also on the topic after you for kind of a similar reason, which is that yeah. The name that I have on GitHub is the one I use in different contexts, right? Some are more formal than others. I consider my position here to be a more formal position. So I'll use my middle initial. And that also goes along with my GitHub handle, right? But then in an informal a less formal situation, I don't do that. And then I have a different name for that context, right? So I think my comment here was especially for newer delegates, the process has been that the delegate themselves opens the pull request against delegates.txt. And then they get to choose what goes in there. And I think that that's good. I hear that a lot of the older delegates that have been in there for a long time, maybe delegates.txt is not the best source of truth for those delegates. But if this is all being tracked in a new repo called TC39 data, then it still gives delegates the chance to update that source of truth. So yeah. I think I guess it makes it a little bit harder to do. But I would say that at least in my opinion, for any delegates added to delegates.txt in the last five years, use that name. And then maybe before that, use the GitHub name. But that's the end of my comment. + +MF: That is, I mean, that's good feedback. That may be fine. I think we still might run into people who have entirely different names that they prefer nowadays. Even within that range. But also, that was a smaller group of people. It's more feasible to reach out. + +CDA: Yeah. I have a clarifying question. Is the change to the existing names in delegate.txt a one-time thing? Or are you going to come back a year later to see if their GitHub name has changed? And what I'm getting at. + +MF: We are free to do that at any point. This is kind of just a parallel to getting it structured. I was going through delegates.txt to make the structured delegate data. There are some names in there that are obviously not people's preferred names. I do not want to include that in the TC39 data repo. I think it's disrespectful. I think that those names are very important for us to change them. I think it's not great that they are still currently in delegates.txt. So maybe I took this process a little bit too broadly. But I wanted to be as generally respectful of people as possible and apply those names. We should probably regularly update this data. But that'll be on us, right? It'd be nice to have continuous communication. But sometimes we fall out of communication with people. I don't have a good solution for that. + +CDA: Okay. Shane? + +SFC: Can we just open PRs? I know it's a little bit more work. But it should be easy to automate. Can we just open PRs to update delegates.text line by line when there's a change? And then have the person approve the PR if they're okay with it? + +MF: So do you mean sending 300 PRs to and then tagging everyone? + +SFC: I don't know how many exactly. But something like that. And I mean, that seems like it's something that would be easy to do. I could just ask my jet ski or anti-gravity to just do that, right? + +MF: I don't have a full number for it. A lot of them were just Dan versus Daniel or something. + +CDA: I have a reply on the queue. I think we can make I would suggest I like the idea. And I think that we should do something like that. That or a variation. And really just focus on active delegates. As long as the change is or not for any reason appears to be controversial for delegates that are long gone. And we're just putting an initial from their GitHub name. I think that's probably fine. But it would be great to get approval from current active delegates like yourself and Daniel Minor who are impacted by the change. + +MF: How about this suggestion? Since the delegate data now also has affiliations that are only present for current delegates: for any of those who have a name in the delegates data which differs from delegates.txt, I will add a line comment in GitHub mentioning them, asking them to confirm that this is preferred over what they had originally had in delegates.txt. That will probably be a reasonable hand-doable number of interactions. Does that sound good? And then for the people who are long past, we just go with the heuristic I had presented. + +CDA: Okay. + +MF: Okay. That was great feedback. Thank you. Oh, where are we with—I know we've gone over. + +CDA: We have a few minutes left. Sorry. + +MF: We're still within the extension. Okay. + +CDA: Maybe we can get to my last QR. + +MF: Yeah. The fourth one. Yeah. So I think we kind of have a plan for this. Once that delegate data—once we are happy with it, we've given enough time to get feedback from current delegates, the plan is to start generating the delegates.txt file from that structured data. We have a commit to do that already. Can we start doing this? Does anybody have a problem with that kind of, again, transparent swapping out of the delegates.txt with the structured data source generated via script? Chairs? Nothing? + +CDA: Are we decoupling that from the changes to the names? + +MF: Yeah. Assuming that we are all done. We get the data merged. Having now the process of generating delegates.txt? + +CDA: So you're referring to the process change to change the source of truth, basically. + +MF: Yes. Yes. So having the official place be the new JSON file rather than delegates.txt? Which will then imply that we will work to update our processes for onboarding and stuff to ask people to make PRs to that instead of making PRs to delegates.txt. Whatever else is in your process. + +CDA: I mean, that seems fine to me. As long as my second topic here is as long as we have all our ducks in a row and before we make that shift. + +MF: Yeah. Yeah. Yeah. Timing-wise, yeah. Do you want to speak to that? + +CDA: Yeah. Okay. So switching the source of truth necessarily means that delegates onboarding new delegates or new invited experts now are doing something different. And so the instructions on onboarding and issue templates need to be updated to be accurate. And so that people know what to do. And don't do the old thing, which is create PR targeting delegates.txt. So as long as all that stuff is in line, I would support it. Yeah. + +MF: Yeah. Great. And I will work with you on timing for when we can actually do that. And of course, JHD will help with that, I'm sure. Okay. So final topic. When we last discussed this, there was some concern expressed about when we go to actually improve the experience here, that there may be some delegates who don't want their affiliation with the Ecma member to be more discoverable than it is today. + +MF: So I would like to open the floor to a discussion on that. Does anybody know of anybody who has an issue with that? Or themselves have an issue with their affiliation being very visible, if we make a new web UI where you can sort by company or when we link that to the proposals, having your company name next to your name. + +CDA: Nothing on the queue. So I see Shane is on the queue. + +SFC: I can. I mean, we have a lot of delegates who change companies. I can definitely imagine that for a proposal that I wrote, when I was at Google, I wanted Google represented there. But if I were to just change affiliations at some point, I would want my contemporary affiliation to be the one associated with the proposal. + +MF: Yes. Yes. We've discussed this. LGH suggested the last time that we have historical affiliations as well and time ranges so that you can properly—if a proposal was worked on while you were at one company, and then you have a different proposal, somebody clicks through to you, they wouldn't want to assume that you were representing that same company while you were working on the previous proposal. That is a potential problem. It's just that we don't have that data at the moment. As I said, we're doing the best with what we have. Our data practices haven't been very good. I don't have historical affiliation data. So going forward, we can probably record that. But it's still problematic about going backward, right? And if we have that information going forward, then that may give even more of an implication that that affiliation is for all of those previous proposals where we don't have your previous affiliation. That's a difficult problem to solve. I'm not sure if we have a concrete solution. + +CDA: So we are past time. + +MF: Yeah. + +CDA: We already extended the time box by 15 minutes. If the presenters are okay with it, I would like to schedule a continuation if we have time to get through the rest of the queue and any remaining things that. + +MF: Yeah. I'm fine with doing a continuation at the end of the meeting if we have time. + +CDA: Great. Thank you. + +JHD: But just a heads up, if you make PRs to the spec and you have made your TC39 GitHub org membership public, which is not the default, then you automatically get previews on your PR. So if you don't object to people knowing you're in TC39, it's probably cool if you make that public. Thanks. + +### Speaker's Summary of Key Points + +* `tc39/data` provides canonical, machine-readable committee data for tooling, analysis, and integrations. +* Delegate and process packages are published on npm; pending PRs add proposal data and generate `delegates.txt` and `tc39/proposals` proposal tables. Alternative interfaces are planned for later. +* Cleaned up and enriched proposal histories, test262 links, broken references, identified missing reviewers, and linked delegate records to GitHub accounts and affiliations. +* Inactive proposals carry over the status, roughly as listed in the inactive proposals table. Proposed that we officially acknowledge these proposal statuses, which we can refine at a future meeting. +* Delegate name cleanup uses GitHub profiles and heuristics to replace outdated names, with feedback welcomed. + +### Conclusion + +* Consensus to retain existing inactive labels during migration. Terminology can be refined outside plenary; PKA offered to open an issue. +* MF will ask affected current delegates to confirm name changes via GitHub line comments; the presented heuristics will apply to former delegates. +* MF will coordinate with CDA and JHD to switch `delegates.txt` to generated data after updates to onboarding instructions and issue templates. +* Affiliation visibility and historical attribution remain unresolved; a continuation was requested. + +## Iterator Includes for Stage 4 + +Presenter: Michael Ficarra (MF) + +* [proposal](https://github.com/tc39/proposal-iterator-includes) +* [slides](https://docs.google.com/presentation/d/1uLfWHUpPjWWjPQTaiuhIAT9WdFO7pAroKlY049rkGJA) + +MF: Okay. Iterator includes. As a reminder, this is what `Iterator.prototype.includes` looks like. It is modelled after `Array.prototype.includes`. Which is the only reason why it also contains a second parameter for how many elements to skip. Again, matching `Array.prototype.includes`. If you don't remember, it gives you a Boolean that tells you whether a value that you pass to it is yielded by the iterator. I have a pull request to the spec. We have implementations. All three major browser engines as well as QuickJS-NG, Kiesel, and Boa. And they are all shipped. So I would like stage four for Iterator.prototype.includes. + +CDA: Support from KG. Also from YSZ. LVU. Mark. DLM. CHU. And somebody else in the queue. JHD supports. LEK supports. Do we have any objections? All right. You have stage four. + +MF: Thank you. + +CDA: I like the quick and easy ones. + +### Speaker's Summary of Key Points + +* `Iterator.prototype.includes` returns a Boolean indicating whether an iterator yields a given value. +* It is modelled on `Array.prototype.includes`, including an optional count of elements to skip. +* A specification PR is ready, and implementations have shipped in all three major browser engines, QuickJS-NG, Kiesel, and Boa. + +### Conclusion + +* Iterator includes advanced to Stage 4. + +## Iterator Chunking for Stage 4 + +Presenter: Michael Ficarra (MF) + +* [proposal](https://github.com/tc39/proposal-iterator-chunking) +* [slides](https://docs.google.com/presentation/d/1K9Hf1w5tYEbU2o5CUZPj1m0JtBmKcugVf-_OfGW1jms) + +MF: Okay. Iterator chunking. As a reminder, this proposal adds two methods to `Iterator.prototype`. The first is `Iterator.prototype.chunks`, which takes a chunk size and yields arrays of that size and these are non-overlapping windows into the sequence of values yielded by this iterator. There's also `Iterator.prototype.windows` which similarly takes a window size, as chunks took a chunk size, and yields overlapping chunks. God, I described chunks as windows and windows as chunks. You get the idea. Non-overlapping versus overlapping. I have a PR to the spec. We have two browser engines that have implemented and shipped it. V8 has a tracking issue with no information. There's no public information about their plans. And we do have two other implementations, one from Quick JS NG and from Kiesel. So I would like stage four for iterator chunking. + +CDA: Nikolaos. + +NPU: Let me first say that I definitely support going for stage four. I would like to update on V8’s implementation. Iterator chunking is very straightforward. What is not very straightforward is iterator windows. And probably that's not straightforward because of the way that this thing was designed. It was actually designed in such a way that an implementation always needs to allocate a quadratic number of bytes if the iterator is exhausted. So it is a challenge to have an efficient implementation that works for both small window sizes and big window sizes, and also that works for, let's say, primitive types that are returned by the iterator or object types that are returned by the iterator. I was wondering if other implementers had similar issues and how they resolve them, but maybe that's not the topic for a discussion here and now. In conclusion, we are definitely implementing this and it will be shipped shortly. + +CDA: All right. Sorry. We have a lot of support on the queue as well. DLM. LEK. YSZ. CHU. And JHD. Do we have any objections? All right. You have stage four. + +MF: Thank you. + +### Speaker's Summary of Key Points + +* `Iterator.prototype.chunks` yields non-overlapping arrays of a specified size, and `Iterator.prototype.windows` yields overlapping arrays. +* A specification PR is ready, and implementations have shipped in two browser engines, QuickJS-NG, and Kiesel. V8 has a tracking issue but no public implementation plans. + +### Conclusion + +* Iterator chunking advanced to Stage 4. + +## proposal-nonextensible-applies-to-private: check extensibility only once for private methods + +Presenter: Olivier Flückiger (OFR) + +* [proposal](https://github.com/tc39/proposal-nonextensible-applies-to-private) +* [slides](https://docs.google.com/presentation/d/1AZYPsiU0LEwI-Hh4zRrW23DvwCMUF5wHjPS4pFh4j6E/edit?usp=sharing) + +OFR: Okay. Non-extensible applies to private. So I initially put a pull request on the agenda. Then I thought some more about the pull request and then I probably overthought it and now we have a slide deck. So here we go. So basically this was just a recap. So what is this proposal about? It's about preventing this. So if you have a non-extensible object and then you inherit from that object and then you stamp a private property on it, then currently this is allowed by the spec. And this proposal was to disallow this. So that non-expensible really means non-extensible. There were two motivations, I think. Please correct me if I'm wrong. I'm actually not a champion per se of this proposal or maybe was, I should say. So one reason is security. Language in language security. So frozen really means frozen. The other point was also evolution. Language evolution. So maybe in the future if non-extensible really means non-extensible, we can have something like a type with meaning. I'm trying to go through the slides maybe and then have a discussion. So unless there is something super unclear, interrupt me, but otherwise I will just continue and ignore the queue if that's okay. So our first try was to just say like, okay, private field add we're just going to put like a check there. And we put this check there. And it turns out that proxies don't have this slot here. So that's not possible. Then the first try to salvage it was this we just do what we do everywhere else. We have this abstract method is extensible. And that is defined for proxies. So all is good. So again, I feel like we need some background here. So it's actually you can observe partially installed private properties. So for example, in this snippet here, the constructor will fail to install the field two. And so it will have an object with only one field installed. So that's already something that exists. Nowadays, right? But what actually I think Yasuke discovered when trying to implement it is what now can happen is you can inherit Proxy and then the Proxy can tell you that it's not extensible starting from property two. And now this also applies for method. So what can happen is we can install one method and then fail to install the second method, which is not great. It's actually extremely terrible. There is even a note in the spec that says that it is designed such that any given object has either all or none of the private methods and accessors defined by a given class so that implementations not require tracking each method or accessor individually. So we definitely do not want to break this. Okay. So and this is pull request 12. My idea was like, okay, this is easy to fix, which is pull out this check out of the methods, which is already an atomic step. So I showed you before installing properties. It's not atomic, but installing methods is atomic nowadays. So we just pull it out. Check first and then install all the methods in one go. So problem solved. It's still kind of opening a new loophole that didn't sit easy with me. Which is like nowadays if your initialization statements are pure, then at least in this case we nowadays know that you will not have partially constructed objects. But it's not true anymore with this proposal. Now I could do the same trick as before, have a Proxy that says after installing one property, this is now not extensible anymore. And now even if I have all pure right-hand side right-hand sides, I have a partially constructed object. So it's also I don't know, uneasy with it. So here's a way to big table. Going step by step. Sorry, I couldn't make it appear line by line. So don't read ahead. So first line was the original proposal. Basically the second column shows you how many traps we would execute. The second column, how many target object checks of the Proxy we would execute. And so the first line initial proposal that's not possible because it's not even defined on proxies. Then the second proposals, the second try breaks implementations. Pull request 12 does one trap for all the methods and then one trap for each property. And I think this is the simplest solution that is kind of workable, but as I've shown, it allows you to inspect partially constructed objects through proxies. Then TG3 had a suggestion, which was to just call the trap once and then cache the result and just use that as the extensibility throughout constructor. I think that's not a good solution either because it basically allows you to add like if we did that, then we would also change the case where we don't have proxies involved and suddenly you would be able to install properties on a non-extensible object. So I don't think that that is a good idea either. But what I think what we could do is we could do the combo. We could say like first we call a trap, let the Proxy decide, and then after that we only look at the target object for the properties. So we could do one trap upfront and then one check for each property. But only check the target object in that case. It I don't know. Yeah, I'm not sure if it's a great idea. It's possible. + +OFR: But at this point, I was also like, okay, maybe we should pause this is more complicated than we thought this whole thing is. And so there are also other options that we could do. We could just special case proxies. We could just say like, okay, proxies. I mean, that's basically going back to the original design. We just say like proxies only look at their target objects and that's it. We don't ask the Proxy. And I think there are some good reasons to do that because in a way, there is like no trap at all involved with private properties at the moment. So there is no get trap, there is no set trap, there's no has trap, nothing is trapped when it comes to private Symbols. So it's kind of weird that now this extensibility we actually do a trap. This was initially rejected because of shadow proxies. The argument was what if the target object is somehow not initialized? But yeah, I don't know if that's really is a good argument against it because in a sense, we're also not doing anything to the target object. We're not going to install a property on the target object. So why would that be a concern? The other alternative that I thought about was that is in a sense the opposite. So basically a Proxy has its own private elements. So we install private properties on the Proxy itself. The easy extensible trap, on the other hand, talks about the extensibility of the target object because we check it when we want to install properties on the target object. So maybe it's just a nonsensical question in the first place and we should say like proxies are always extensible or never extensible, modules are, but that's probably not web compatible. So yeah, so those are kind of that's kind of the range of possible solutions. I already see it on the queue. Yes, pull request 12 is also favoured by TG3. And I think it's workable. Still, I would like before we go into the discussion, I would suppose I would suggest that we do this temperature check and just get an unbiased account of where people feel where we should go. Can you add these four options? Okay. + +MM: I think it's premature to do a temperature check. I suspect most people are not very are not really that oriented until we have more of a discussion. + +OFR: Yeah, the idea is to have an unbiased one and then we'll do one again. This is just for starting the discussion. + +MM: Okay. + +**Poll** (1 min, 11 voters) — @ctcpip + +* ❓ underlying: 6 +* 👍 combo: 5 +* ❤️ PR12: 3 +* 👀 never: 3 + +OFR: PR 12 is one trap for all the methods and then one trap for each property. The combo is one trap upfront and then only look at the target extensibility for properties. + +OFR: I think we got all the information that I wanted from this, the information is like it's completely unclear which direction. So let's go to the discussion. + +CDA: All right. Mark. + +MM: Okay. So I want to take one thing off the table. I'll just announce that if it goes if the direction goes there, I would object and it has nothing to do with the purpose of this proposal. Which is having an is extensible check punch through the trap, ignore the trap and go directly to the target or have a Proxy always be considered extensible or have a Proxy never be considered extensible. I would object to any of those. Those are nonstarters for me. And the reason is membrane transparency. And it's exactly the issue that you mentioned that you said you didn't. Why? So if you could return to that slide okay. Initially rejected because of shadow proxies. There's no such thing as a shadow Proxy. You probably meant shadow targets, correct? + +OFR: Yes. + +MM: Okay. So the way membranes work is that there's the; I'll just do it with colours. There's the blue world. Let's say inside the membrane and there's the yellow world outside the membrane. And there are yellow proxies for blue objects and there are blue proxies for yellow objects. Now, if someone is holding a yellow Proxy for a blue object and then due to activity inside the blue subgraph, an object becomes right. A right. The real target meaning that the terminology on targets is so screwed up. I apologize. But the object that the Proxy is trying to virtualize is I'm going to call it the real target, which is traditional, the terrible. And the thing that's part of the Proxy mechanism, which is held by the Proxy, is the shadow target. And the difference is that the real target is all blue and the shadow target is yellow. So if the real target due to autonomous blue subgraph activity becomes non-extensible, and then somebody in the yellow subgraph asks the yellow Proxy for that object, is the object extensible? Well, if you punch through to the target, what the target you're punching through to is not the real target, not the one that autonomously became non-extensible, it's the shadow target which is the thing that does the bookkeeping to ensure that the Proxy honours its stability demands. That's the main purpose of the shadow Proxy. And the shadow Proxy was last updated when the blue real target was extensible. So it's extensible. If you just punch through to it, you'll find out I mean, it'll report that it's extensible, which is breaking transparency, which is breaking virtualization because the object of the Proxy is trying to imitate is now non-extensible. That's why you have to have a trap so that the handler has a chance to look at the real target update the shadow target to reflect the real target before the real targets attributes are checked. So we cannot break that. Okay. Now, the I'm sorry. I saw somebody say lost blue yellow and then it disappeared. Could we take that offline? Or did everybody miss it? Did anybody get it? + +OFR: I mean, I think I can try to rephrase it and then you can tell me if I got it. So basically the objection is that the underlying target object of the Proxy might be out of sync with the thing that you actually want to Proxy. And so if we just look at the target object, then you cannot use the Proxy anymore to basically ensure this state synchronization between the actual thing that you use as the target object of the Proxy and the thing you want to synchronize it to. + +MM: Yes. Yes. That's the whole point. So you got it. Thank you. So now a little bit about TG3. Yeah, we did our first TG3 session on that. We talked for an hour and I think I got us going on the wrong track. I heard somebody explain the PR. I had not gone and read it in detail. Then we discussed it and somehow I had I was framing it as Olivier's trying to have one extensibility check and amortize it across all the privates. And then we tried to analyze that and it just became a deeper and deeper mess. So we ended up being pessimistic about what we thought the proposal was. Then we found out that the actual proposal PR 12 does what you explained. I personally love it and I think I'm speaking for TG3 to say that everybody who had an opinion of it also thought that PR 12 was the right solution. And then finally, on the motivation for the overall proposal, the main motivation, the thing that got Shu and I together to put the initial proposal together and then for me to fight for it, was a virtualization failure. At Agora we're doing and now at MetaMask we're doing an object-oriented virtual memory much like in the old small talk tradition where we're basically have map-like collections and set-like collections that spill objects to disc so you can have collections that are bigger than RAM and likewise we have class-like abstractions where you can have more instances than fit in RAM. And it's amazing how straightforward it was to do this in JavaScript. The one we do is we deny the virtualized world access to weak refs or finalization registries. So they're living in a world where they're already supposedly designed to deny the ability to detect garbage collection. We replace their weak maps and weak sets with virtualization-aware weak maps and weak sets so that if the representative object that's in RAM disappears but is still represented by a copy of that object on disc waiting to be paged back in, without replacing weak maps and weak refs, that virtualization does not work because the same object at the virtual level of abstraction doesn't index to the same entry in the weak map. So the one place we were able to do that because weak maps and weak sets are replaceable and that was the one thing we needed to virtualize. Until I think it was Matthew who noticed that the return override means that classes are a weak map reachable by syntax or sorry, return override combined with stamping private properties. Is a weak map reachable from syntax our virtual objects for lots of other reasons have to be frozen so they're necessarily non-extensible if non-extensible objects cannot be keys in implicit weak maps reachable from syntax then the virtualization problem is repaired. This is a life and death thing. And with this repaired, we can just do the virtualization and it's impossible to detect. + +CDA: Mark, was that your second topic? + +MM: Yeah. Yes. I'm done. + +CDA: Yep. Thank you. Ashley. + +ACE: And I was curious. I'll leave the your feelings on PR 12 when you thought about it some more. You were saying how you didn't like that if all the right-hand sides were just pure values then it's still observable to observe the torn state. Is that just an aesthetic like feels wrong? + +MM: You're asking about why we disliked? + +ACE: He didn't like it. I think it doesn't I don't like it either aesthetically, but I'm like okay with it because you can't if these things weren't pure and they do reference this, then you can easily do it. I was wondering if is there actually like an engine reason why it's also bad like the fact that you can see that they're just static literal values you perform like an optimization and you can't. + +OFR: Right. So I think the reaction to it I had was there is nothing currently that would break with this. It's kind of blocking a future avenue for optimizations maybe. I'm not even sure about that, but it seems like theoretically possible that you could say like, "Okay, there's nothing that can happen currently between installing these fields so we can do it atomically and use that somewhat to our advantage." Whereas if there is a Proxy trap there, it will be significantly harder because it's like almost impossible to prove that there is no way that you can get back a Proxy from a supercall, right? + +CDA: Matthew. + +MAH: Yeah. I mean, partial initialization is only surprising if you ignore that to get into this situation in the first place, you need to have a return override in the superclass. So as soon as basically you enter in a return override, the world you could just disable any of these optimizations you are already doing something weird. I think all bets are off. + +CDA: Justin. + +JRL: Hello. Can you hear me? + +CDA: Yes. + +JRL: Perfect. I haven't spoken yet. So going back to MM, question specifically back to MM. When you're describing the yellow blue membrane stuff, I get that. What I don't understand is why making a Proxy always extensible but like—only for private properties and installing onto the private property would break membrane transparency. Because the Proxy itself can't be transferred across the membrane. And it's like as you were describing Proxy sorry, a. + +JRL: Properties essentially a weak map essentially. And it's like giving proxies the ability to deny being added to a weak map now. + +MM: So the I think I'm let me ask some questions to clarify what question you're asking. The are you suggesting a change to how extensive how proxies handle extensibility testing in general? + +JRL: No. Only specifically for private properties. + +MM: Okay. So I so first of all, let me admit that the case I'm about to raise is obscure, but it's the kind of failure of blind composition that bites programmers when two pieces of correct code are composed creating a bug that nobody knew to expect even if they were paying attention to everything that they should be paying attention to. So one piece of code uses return override to take some object provided by another piece of code and add private properties to it. That's a perfectly imaginable thing that that's that somebody writes such a piece of code where the object being extended using return override is an object they're receiving from elsewhere. The elsewhere let's say was originally designed to be the objects themselves but for some reason as the code evolved, that subgraph of objects including the object that is given to the first piece of code all of those objects get put into a membrane and now the Proxy so now all those objects are blue the class code with the return override is yellow and now the code that was giving one of the objects from that subgraph to the class override code the return override code is now giving it a yellow Proxy for a blue object. Now, if the blue object becomes non-extensible in the middle of the instance field initialization, then the Proxy must report that it is non-extensible. Otherwise, you get a failure of the virtualization safety property which is now you're adding private fields to objects that told you I'm sorry, to objects that were supposed to report that they were non-extensible but failed to report that because you punched through to the shadow target rather than letting the Proxy reflect the real target's truth onto the shadow target first. + +JRL: Okay. I agree with that. And I think the case that you've outlined here is essentially there's a yellow Proxy and a blue Proxy and the target is now a Proxy wrap for another thing that exists on the other side of the graph. So it kind of mixes it up a little bit whether it's a Proxy of a Proxy now. + +MM: But I wasn't going that far. We can go that far if you want. That's not the case I was raising. + +JRL: Okay. I agree that we cannot directly go to the target. Because the target is not going to be the shadow target that represents the actual state of truth in this membrane example. So I don't think that the number four here is the way to go here. + +MM: Good. + +JRL: But it's always extensible explicitly only for private properties. I can't think of a scenario where this fails. Because it is essentially a weak map. + +MM: Okay. So always extensible does pass the virtualization safety because it just prevents I'm sorry. I'm sorry. Hold on. Are you suggesting that proxies in general when asked if they're extensible always report that they are extensible? + +JRL: No. + +MM: Okay. How do you get. + +JRL: Is extensible check always does behave like it does now. It taps the Proxy trap whatever it is and that can check the default to the real target or if you've overwritten the trap it can do whatever. What I'm suggesting is that private properties are not observable by proxies. They can't be transparently done you can't do anything with them besides install the private property directly onto the Proxy. It never goes to the target and it can't go to the shadow target because we do not provide traps for you to get that information. + +MM: Yeah. I mean, it's the weak map model of private fields. It works perfectly when the key is a Proxy. + +JRL: So I think for this PR 12, if we change the semantics explicitly say if it has the Proxy internal slot, meaning it is a Proxy, then you're allowed to install private properties onto it because it could never not be extensible. + +MM: Right. + +JRL: So we are. + +MM: No, but no, but hold on. If you're saying you can install private properties? + +JRL: Onto the Proxy itself, not to the target it represents. + +MM: Okay. Then you're losing the so a conclusion I left to earlier is wrong. Let me backtrack. Then you do break virtualization. You do expose you do enable code to detect garbage collection even when it has been denied weak ref finalization registry and the original weak map and weak set. + +CDA: All right. I'm going to have to jump in here because we are pretty much at time. Sounds like we will need a continuation if we want to get to the remaining items on the queue. So + +MM: Can I just ask Molly, are you okay with PR 12 being the answer? + +CDA: Are you asking. + +OFR: Yeah. I mean, I'm pretty sure we're going to get to a continuation, right? And or yeah. So yeah, yeah. I mean, like if you go one like this is my next question. So anyway, I'm okay with PR 12. Okay. + +MM: Okay. PR 12. + +CDA: All right. Thanks everyone. Will this brings us to our break. + +### Conclusion + +*For summary and conclusion, see continuation on 30 September* + +## The chairs get cheeky + +**Poll:** are the chairs doing an EXCELLENT job so far? (16 min, 8 voters) — @ctcpip / @robpalme + +### Conclusion + +* 💚 10/10, no notes: 5 +* ❤️ yes, absolutely: 3 +* 🧡 of course!: 2 + +## Task Group Reports: TG4: Source Maps + +Presenter: Nicolò Ribaudo (NRO) + +* [repo](https://github.com/tc39/tg4) +* [slides](https://docs.google.com/presentation/d/1M0kBO3jeYm-aBO0WxoJkoEF6sPyEnD5yInbTbgi2bzM/) + +NRO: So this will be quick as usual. This update for what we are doing in DG4. As I know, previous updates are working mainly on two proposals, range mappings and scopes. Range mappings currently at stage three. It's been implemented across various debuggers and build tools. We have already released implementations in WebKit and in MagicString. MagicString is like a code transformer library used by different tools such as Rollup. There is a complete pattern released implementation in Babel, and an in-progress implementation in Chrome DevTools. Reminder that for TG4, we have a slightly different process than TC39. So for us, the requirements to go to stage four is not to have just two implementations in general, but we want to have two implementations in tools that consume source maps. Such as browser interactive debuggers and two implementations in tools that produce source maps. + +NRO: So we're getting close here to reaching those requirements. But there is a note here that is, when it comes to build pipelines, tools need not only to be able to generate source maps with some new feature, but also to consume it when you have multiple tools running after each other. And the proposal is not there yet. + +NRO: The other proposal we're working on, scopes, it's also stage three. It is still in a much more active design phase. Because after we reach stage three, other implementations that were waiting on us to stabilize a bit start experimenting with it. They found significant possible areas of improvement. When it comes to the performance of consuming those source maps that use scopes, and so there is still major changes now that have been done to it. For the reasons implementations are in progress, but not as advanced as for range mappings, we have I guess here Terser should have been orange, but we have I believe a complete but experimental implementation in Chrome DevTools. And then we have implementations in Firefox DevTools and Terser. Which are much more experimental and as far as I know, not complete or not up to date. + +NRO: And that's it. Other than that, we keep meeting monthly or twice a month. We have a meeting specific for scopes, and you're all very welcome to join our meetings. Thank you. + +### Speaker's Summary of Key Points + +* TG4 continues meeting monthly, and all delegates are welcome to participate +* Work on scopes and range mappings continues, both have experimental implementations + +## Dynamic Code Brand Checks for Stage 4 + +Presenter: Nicolò Ribaudo (NRO) + +* [proposal](https://github.com/tc39/proposal-dynamic-code-brand-checks), [PR](https://github.com/tc39/ecma262/pull/3294) +* [slides](https://docs.google.com/presentation/d/1oYsZ-6CLpTv971nXYgWIgFGIz5VAyz11pUxsCpO0mXY/) + +NRO: Well, hello again. So this dynamic code branch X for stage four. In the past, this proposal has had multiple names. So if you don't remember what dynamic code branch X is, you might remember it as code-like objects or providing more context to hosts in `HostEnsureCanCompileStrings`. Or the way that web developers know it, which is “trusted types”. Specifically, the trusted types integration with eval and `new Function`. Trusted types itself is a larger web platform future feature that also integrates with HTML stuff. And the so the way trusted types needed ECMAScript to be extended for their goals is to provide some more information about the objects that JavaScript code is trying to pass to eval and `new Function`. This is because trusted types allows wrapping some strings in some special objects to mark them as coming from a trusted source to allow dynamic code compilation of those where normally weight varies CSP policies. It will be disabled for security reasons. So the host HTML, well, CSP in our case, needs to know where these strings created by Stringify in the parameters to new function originally came from. + +NRO: So if it was coming from one of these trusted objects, and something similar for eval, except that eval does not Stringify its arguments normally, just returns them as they are. So the proposal implements these requirements on the web. It is now implemented everywhere. It is baseline since February. Chrome has had an implementation for a very long time already. + +NRO: So it's already used in production on many major websites. I was already planning to bring this for stage four in May. We had a presentation that was like stage four or normative change. And the reason of the time was that there was some consensus we agreed on a few years ago, but then it was not fully reflected in the proposal. We noticed this in May. So in May, we updated the proposal to match the original consensus. It was specifically about whether toString is called on this trusted types object when passed to `new Function`, or whether we just ask the host to give us the trusted contents stored in the object. That last change that we confirmed in May is already shipped in Firefox. It has been implemented in V8. It's not released yet. And there is an open patch in WebKit. Sorry, this comment at the bottom of the slide was something I was meaning to delete and then forgot. But thank you. V8 for landing the patch since this is when I first put the slides on the agenda. And also I want to thank Cornelius, who is an intern at Igalia who worked on the implementation across these three agents. And so yeah, we have two implementations. One is already shipped and enabled by default. So I want to check if I have consensus for stage four now. + +MM: I just I just want to confirm with you that this has a property that I think we both consider important. One of the goals of compartments is to emulate one host by JavaScript code running on another host. And it'll never be perfect, but right now we have a shim of compartments that shims eval. It can only shim indirect eval. It can't shim direct eval. I from what I see, there should be no difficulty extending the compartments shim to shim this enhanced eval and enhanced function constructor. And the equivalent of blessing a type is just in the creating code, the code that sets up the compartment. There's just a weak set or weak map of the blessed objects. Does that all make sense to you? And do you see any problem with it? + +NRO: Yes, that's all correct. You didn't have weak map going from this blessed objects to the actually blessed string. And then in your replacement for new function and eval, you would consult that weak map before doing the normal thing that it otherwise does. + +MM: Perfect. I support. + +RPR: Thank you, MM. We also have support from DLM. Do we have any objections? Stage four. No. So congratulations, Nicolo. You have stage four. + +\[Applause in room] + +NRO: Thank you. I'm going to assume there are applauses, but I cannot hear them. And if there aren't, please don't tell me. + +### Speaker's Summary of Key Points + +* The proposal and implementations have been updated following consensus from May meeting +* Latest semantics shipped in Firefox and shipped in Chrome; overall the proposal is shipped everywhere + +### Conclusion + +* Stage 4 + +## Stage 2 proposals missing Stage 2.7 reviewers: collection-normalization, pipeline-operator, module-declarations, jobcallback-module + +Presenter: Michael Ficarra (MF) + +* No slides presented + +MF: This one's fairly self-explanatory, I think. So, in our process, for a proposal to move from stage 2 to stage 2.7, it has to have reviews from its assigned reviewers. We almost always assign these reviewers at the time that the proposal moves from stage one to stage two. We have four proposals in our data that are missing assigned 2.7 reviewers. These are presumably active because they're not inactive proposals. And they have no way to advance to their next stage without these reviewers being assigned. So I would like to have a resolution for each of these four proposals. It is fine to assign reviewers; it is also fine for those champions to ask for the proposals to be withdrawn. It is also fine for those champions not to be active anymore and for us to consider the proposal abandoned. I think that these proposals are kind of in an invalid state at the moment. Do we want to just go through them one by one, or does anybody have any hands they want to throw up right away? + +CDA: It's kind of off topic in the time box. It's not long, but we usually call them stage two reviewers. Can we just decide. + +MF: It's a fence post problem. It's one or the other we're talking about the same thing. + +CDA: Yeah, yeah, yeah. I just feel like we should decide which one to call it. + +MF: I don't. Names are usually unimportant to me for these kinds of things. Okay. Is anybody present a champion of any of these four proposals? I think we do have at least pipeline operator, right? + +RPR: No hands are going up at the moment. Would anyone like to reveal themselves as a champion of one of these? + +MF: RBN should be online. + +RPR: RBN is here. RBN is somewhat affiliated with pipeline proposal. And NRO has module declarations. RBN, did you want to talk about the pipeline reviewers? + +RBN: I'm not sure I can be authoritative related to the pipeline operators proposal. I haven't been directly involved since it switched over to Hack-style Pipes. I know there's been recent discussions within the past few months mostly still on the same topic related to the topic variable or symbol that needs to be used. So I know that the proposal is still somewhat active. But I haven't seen much involvement from Tab, who's one of the champions. Although I believe there's been some discussion from, I think it was, JS Choi. So we could probably ask for reviewers. I'm not sure whether the proposal is in a state where it is ready for review. + +MF: It sounds like it's not clearly abandoned, though. So I would like to ask if anybody would like to sign up as a stage two or a stage 2.7 reviewer for pipeline operator. + +RKG: This is for pipeline? + +MF: Pipeline. We're talking about that one right now. + +RKG: Yeah. I need a microphone. If it is actually intending to go to 2.7, I am fine to review. But very unclear on that. + +RPR: I think Michael, you're just trying to get people assigned there's no indication that they begin work on this now. + +MF: That is right. Yes. So presumably, if you are the assigned reviewer, when the champion group feels that the proposal is ready to advance to 2.7, they will ask for your review first before they bring it to the whole committee. It should have been done when it was advanced to stage two. Our records do not have anybody assigned in the proposal table. Also having gone through all the previous notes, I was not able to find any information about this. So it was probably never asked for any of these. + +RKG: Sure. + +MF: So if we want this proposal to be able to advance at some point in the future, we will need to assign these. + +RKG: Understandable. Though I am a bit doubtful about the state of pipeline at present, I would be willing to review as long as it gets there. + +MF: That's great. Typically, we look for two. If we get a second, that'd be great. Having one. Okay. + +RKG: I would also prefer not to be alone on that. + +MF: So it looks like we have Ross (RKG) and Christian (CHU). Thank you both. + +NRO: Yeah. For module declarations, there has been some the proposal has not had updates in a couple of years. There has been some interest in multiple parties lately, even if not super high. So at this point, it is not fully clear guys saying that well, at this point, it's not fully clear who would champion the proposal. Because I mean, there is a small number of people that are very expert about modules. And so usually, we try to find a champion and a reviewer within the group. So we can't assign reviewers now. But when a proposal actually gets a reboot strap, it's possible we'll need to maybe change champions there. And so the reviewers might not be viable reviewers anymore. I see Guy is on the queue. Do you want to speak, Guy? + +RPR: Guy, did you want to speak? You've said you're happy to be a reviewer. + +GB: But assuming I'm not going to be the champion. + +MF: Yes. That's clear. This is just a request for assigning the reviewer. In answer to SFC's question, the answer is yes, that the pipeline, the previous one, we assigned Ross and Christian there. + +RPR: And RGN is also on the queue volunteering for model declarations. + +MF: Great. Moving on because we are running out of time. We have collection normalization. Actually, I don't know. I should have prepared. Who is the champion for that? Is that still BFS? No champion listed? Oh, no. No, we're here. + +RPR: Would you like to show the explainer for this? For the collection normalization? Would you like to just bring the explainer up just to remind people what it is? + +MF: Give me a second to do it. Looks like BFS was the champion. + +RPR: Should we be fishing for champions before we fish for reviewers? + +MF: I believe BFS is the champion for that. I think the data is just bad on the proposals. I can look in my structured data. I'm almost sure that BFS is the champion. But also, BFS is not active in committee anymore. So that is not a thing that we've resolved yet. There are plenty of proposals that are active whose champions are not active, that we're not going to resolve today. But if we are resolving the lack of stage 2.7 reviewers, would anybody like to volunteer to be the assigned reviewer for this proposal, collection normalization? + +ACE: I think I actually would. I would not mind being. + +JHD: I would also. + +MF: And I actually would as well. That is great. Thank you, JHD. + +MF: So we have Michael (MF), Ashley (ACE), and Jordan (JHD) for collection normalization. + +RPR: And in answer to SFC, module declarations is GB and RGN. + +MF: And finally, we have proposal job callback module. I don't even know this proposal. Propagate active script or module with job callback record. CZW is the champion. CZW is at Bloomberg, right? Okay. Yeah. Well, yes. But what I'm saying is I'm turning to a Bloomberg person and saying are you aware of the proposal and— + +NRO: I think I can speak for that. + +MF: Okay. + +NRO: That proposal is because right now, there is some dynamic scope being on when you pass eval to Promise 10 due to how HTML does some things. I think I can volunteer to be a reviewer there, and it would be great to get a volunteer from TG3 also. + +MF: Great. Thank you, NRO. Anybody who is a participant, a regular participant at TG3 want to be assigned reviewer on this one? + +CDA: Sorry, which one? + +RPR: We're talking about job callback module. I'm looking for one more reviewer. + +MF: The full name of it is propagate active script or module with job callback record. Anybody who does not regularly participate in TG3 want to be the second assigned reviewer for this? This is the final volunteer that we're looking for. CDA? Okay. Sounds like we have Nicolo (NRO) and Chris (CDA). Thank you. We have assigned all of the missing stage 2.7 reviewers to stage 2 PRs. + +RPR: And Shane is correct in listing the collection normalization reviewers. Michael, Ashley, and Jordan. + +CDA: Are you going to create an issue on these repos or something to indicate or is this going in the TC39 data repo? + +MF: No. I'll update the TC39 data. We'll regenerate the proposals table. It'll have all this information now. And then that's our official record. + +CDA: Awesome. + +MF: And I'll make sure I do it from the recorded notes. + +RPR: And in answer to Shane's question, yes, Nicolo and Chris are job callback module reviewers. So we're all done, Michael? Excellent. Thank you. + +### Speaker's Summary of Key Points + +* Four active Stage 2 proposals lack assigned reviewers required for advancement to Stage 2.7: collection normalisation, pipeline operator, module declarations, and job callback module. +* A resolution was sought for each proposal through reviewer assignments, withdrawal, or abandonment. + +### Conclusion + +* Pipeline operator reviewers: RKG and CHU. +* Module declarations reviewers: GB (conditional on not championing the proposal) and RGN. +* Collection normalisation reviewers: MF, ACE, and JHD. +* Job callback module reviewers: NRO and CDA. +* MF will update TC39 data from the recorded notes and regenerate the proposals table as the official record. + +## `JSON.parse` Options for Stage 2.7 + +Presenters: Peter Klecha (PKA), Ashley Claymore (ACE) + +* [proposal](https://github.com/tc39/proposal-json-parseimmutable) +* [slides](https://docs.google.com/presentation/d/1xNMjd3p8wo4NqtuBCOu-We_lFWX0SWI36721xmjlSHQ) + +PKA: This is `JSON.parse` options for stage 2.7. So first, some background. The original state of this proposal was it was originally part of Records & Tuples and it was spun out of records and tuples into its own proposal called `JSON.parseImmutable`. The idea being that it would be a version of `JSON.parse` that would return a record or tuple. But records and tuples was withdrawn. We then recently determined that there's still interest in this proposal. Particularly in Bloomberg, there's still interest. To maybe have this as a more generic function that returns some kind of immutable thing, we determined that that thing should be a deeply frozen object. And so there was support, general support from the committee for that to happen. + +PKA: In the most recent discussion, of this proposal, it was determined there's sort of emerged a consensus in the committee that we should—excuse me, I shouldn't say consensus. Most of the people at the committee seemed to be generally in support of the idea that we should instead just overload `JSON.parse` and instead of having a separate function that would return an immutable thing, that we should overload the second argument, allow passing an options bag to basically say instead of passing in my own custom reviver, I'm sort of asking the runtime to give me a reviver or some set of revivers itself. So this is the now the new state of the proposal. + +PKA: We have an overload of the second argument of `JSON.parse` you can pass in an options bag. This options bag currently has two properties. Freeze and prefer null prototype. If you put freeze = true, then you get a deeply frozen object. If you get pass prefer null prototype true, you get an object whose non-array objects have no prototype, have a null prototype. And also freeze = true implies prefer null = true. So this is the state of the new proposal. Benefits of this creates a native, presumably optimized path to deserializing JSON into frozen objects, improving on the current technique of using a reviver that just calls `Object.freeze` on everything. Likewise, for creating unfrozen but null prototyped objects, which I think we heard at the previous meeting that there was there were use cases for. + +PKA: This also opens up this new direction opens up for some possible extensions, which I should stress are not part of this proposal. We could add other keys to this options bag for handling bigints or dates, lowercase d dates, other extremely common reviver patterns. And this also allows the use of these reviver patterns with JSON imports which obviously can't support a reviver function but can support string values. Excuse me. For import attributes can support string values, not our function. But that's potentially a follow-on. + +PKA: There are some small decisions that we have tentatively made since the last meeting. First of all, names for these properties freeze and prefer null prototype. We don't really think there's a good one for that second one. That's the best we can do. And another issue that came up during the spec review is the coercion behaviour. So if you pass something other than a boolean for either of the flags, either of the options, the current state of the spec is that we do not coerce non-undefined non-boolean values to boolean. We instead throw. There's an earlier state where we did coerce. We made the in response to feedback, we switched to throwing. We've made these choices, but we are open to feedback from the committee. We're not tied to any of these things deeply. + +PKA: So modulo, those questions. We would like to request stage 2.7 oh, I should add. Also, we got our stage 2.7 or stage two reviewers have reviewed and signed off on these. Those are RKG, JHD, and EAO. So unless anybody wants to discuss the issues that I just raised, is anyone interested in stage 2.7? + +DRR: All right. I think we can make it to the queue. One moment. So first up, we have Olivier. The clarifying question. + +OFR: Right. Since this came up when talking about this proposal, so what if a function has these properties? + +PKA: Yeah. The state of the spec is that if the thing is callable, it will treat it as a reviver. And not the options bag. This does make it—sorry, maybe this is tangential to your question—but this is technically a breaking change; there could be web compat issues. We don't think there will be. Precisely because if you pass, for example, `Object`, which does have a `freeze` member—but because `Object` is a function, it will be just treated as a reviver. + +RBR: Yeah. I was wondering if the null prototype option is against prototype pollution. And because if it is, then I wonder if we not only want to look at underscore underscore proto underscore underscore, which is probably the main issue in this case, no? + +PKA: No. + +RBR: Okay. So that was the first part. And then second, I would just use the shorter name for it. Probably instead of `preferNullPrototype`, if we go for an options bag, it would probably just go for `nullPrototype`. + +PKA: So the reason we didn't choose `nullPrototype` is because arrays will have their prototypes. So we wanted to somehow signal that it's not just null prototypes across the board. + +ACE: And there's no change in behaviour for `__proto__`. If you parse a JSON string that has that key, you will still get an object back that has that key and then if you assign that into something which is then going to trigger a setter, then yes, it will happen. It doesn't prevent that being a parsable property. + +DRR: If we are done with the current topic. We have one from MM. + +MM: So the immutability issue that's motivating this doesn't mean anything for `JSON.stringify`. But the general notion of adding an options bag by replacing the function parameter, by overloading on the function parameter, makes sense to overload the replacer as well. It doesn't need to be in this proposal but if this proposal proceeds, then it acts as precedent does all of that make sense to you and do you see any problem treating stringify likewise with the replacer being optionally an options bag? + +PKA: It does make sense to me what you say. It seems natural to me that someone might be interested in adding options to stringify. That is not part of this proposal, as you say. I haven't thought deeply enough about it to know whether there might be some problem with doing the same on stringify. I don't see it as necessary. We could have one on parse and not stringify, so if there turns out to be some fatal flaw with stringify, then I don't think that affects this proposal. + +MM: Okay. You've satisfied my question. I support. + +PKA: Thank you. + +DRR: Okay. Olivier, take it away. + +OFR: If we're already adding an options bag, we could think about adding a `reviver` option there that kind of make it, I don't know, uniform, I guess. Yep. + +PKA: I think it was KG who said this at the last plenary that it's sort of instead of the reviver because you're sort of saying, "Here's the reviver I want." It's not just a general options bag. It's saying, "Hey, runtime. Here's how I want this revived." So it makes sense that it's *instead of* but you're also right that we could totally add a reviver. You could also have a custom reviver in addition to these things. Maybe raises some of the thorny questions that we were originally wrestling with that led us to go in this direction, which is that it is unclear how to handle a reviver in conjunction with a freeze everything semantics. Because it's like, do you freeze it first? Do you require that the custom reviver return a frozen thing? So that's a question. But you're right that it's compatible with this. + +DRR: From JHD, we have a plus one. + +ACE: To adding a reviver option, is the idea that it could make sense as a follow on or you would want to see this in the proposal before it goes forwards? + +OFR: I don't know. It was more like if I would propose this, then I would propose it this way because it kind of makes sense to me. But and also just to make it clear, I was thinking of a reviver or the other things, not that you can combine the reviver with the other things because that, I think, would be quite hairy. So it's more thinking that you can just write the reviver instead of inside the struct instead of putting it naked there so that it looks the same in both cases. + +JHD: And yeah, for my plus one, I think because of that interaction and I don't think it's actually clear whether they should be mutually exclusive or whether they should alter the arguments the reviver argument the reviver function gets or test the return value or I think that makes sense as a follow on proposal. + +DRR: OFR, you have exclusive or is your top reply? + +PKA: I think he said his yeah. + +DRR: Gotcha. MM says, I prefer not adding a reviver option in this pull request, end of message. + +MM: Yeah, it's sort of on a YAGNI basis. It might just not come up as needed, in which case we just happen to skip it because nobody was interested. But if anybody is interested, it's very natural how it goes in. So I prefer just leave it out of this one. Keep this one minimal. + +DRR: All right. KM. + +KM: Yes. One note on there's in the overview describes this as a performance improvement. I would expect for—I don't want to say the foreseeable future, but probably a significant lag until it becomes popular enough to even use this, it will still probably just go down basically the same path as the reviver. And you will not probably get most of the other optimizations that JSON parse has of whatever intense things that we don't bother doing with on the reviver path. But just not as a mean that it won't mean that we preclude optimization so there's still some theoretical value in the future, but I just want to make it clear to the committee that I would expect for us and many other engines, it will not be tuned in the near future. + +DRR: CDA? + +CDA: Have the editors signed off on the spec text? + +PKA: That's a great question. + +CDA: Because that's one of the entrance criteria for 2.7. + +PKA: You raise a great point. Yeah. Have any editors? + +MF: So I was out the last couple of weeks while the editor group was doing approvals. So I didn't do any of these last reviews this last week, and I won't be able to speak to whether the editors did. So if you don't have confirmation from anyone from the editor group that they've done their reviews and we don't have anybody else on the call, then we won't be able to have that confirmation. + +CDA: Well, I hate to be the bearer of bad news. Doesn't sound like we can advance today. But hopefully, maybe we can get an answer before the end of the meeting—a positive one because I would like to see this advance. + +DRR: Shall we proceed with the remaining queue items in the meantime? + +CDA: Yeah. NRO. + +NRO: Yes, please. + +NRO?: Just I don’t know if he signed off on it, but Linus did review this proposal. So we just need to confirm with him. + +DRR: All right. RGN. You might have a preference on this one. + +RGN: I have a preference that it not be called `preferNullPrototype`. We can definitely bikeshed on what it is, but the current name fails to communicate that it's actually always null prototype, but only for non-array objects. It's not blocking 2.7, but I think we can probably do better. I do support Stage 2.7. + +DRR: CM. + +CM: Yeah. Just a clarifying question. Which RGN's question prompted. Does `preferNullPrototype` come into play for anything besides object literals? + +PKA: No. + +CM: Call it `nullPrototypeObjects` or something? + +PKA: Well, the thing is that arrays are objects. + +CM: Oh yeah, you're right. Fair point. + +ACE: If we change arrays to not inherit from objects first. Quickly whizz that change through. + +PKA: Oh, yeah. Whizz that proposal through. And then do that. + +CM: Yeah. + +PKA: We can get right on that. + +PKA: Trivial add-on. + +CM: Okay. Thank you. + +DRR: Jordan, with plus one, should do this. Prefer is a should, not a must, and a message. And Jordan, with another topic. + +JHD: I think given the import type JSON is meant to be it basically does a `JSON.parse`. I kind of feel like we should add import attributes in this proposal for these options. They're already going to be part of the cache key, so that I think that part is already handled, right? If you import it once frozen and once not, those are two different objects and once frozen and once not and so on. But yeah, it seems like a good idea. + +ACE: It's an annoyingly slightly bigger change than it sounds because right now we say import attributes should only be string literals. So this would be the first time we would say it's okay to have a literal true and I feel like that is a little tiny keyhole that blows out into a bigger discussion. But I definitely want to do it, but I would want to do it as a separate proposal. + +JHD: Yeah. I mean, it's fair that there might be some discussion about, do we only want literally those four or five characters present without quotes and stuff. And but that to me does also seem like they're straightforward answers, but that instinct doesn't often bear out in this room, so. + +(laughter in room) + +DRR: We have a plus one from OFR. And then RGN. + +OFR: Maybe add a bit. I think it's actually I think it would be even a bit more than nice to have it. So thanks for raising it. I actually had it as feedback, but forgot to mention it. So yeah, I think that would be nice to have it. And I can see why procedurally you would want to split it into two. So maybe if you want to make it such that we absolutely believe you that you will do it, you can already start it now. + +RGN: Yeah, that makes sense to me also. Pursuing import attributes is an obvious next step, but let's not blow up the scope of this on resolving the open questions that we know about already and that we're plausibly going to discover as it proceeds. + +ACE: But say we could always choose the let's not eagerly ship the `JSON.parse` one, hold it in stage three while we just… + +RGN: I think it's got enough value that yes, let's go ahead and eagerly ship it. It's fine to have imports lag runtime evaluation of a built-in API. We went so long without having import type customization at all. It's totally fine for this to lead. And it provides value without affecting the imports as well. + +DRR: NRO? + +NRO: And just a historical note here. Boolean attributes were discussed in the context of the import attributes proposal. And the only reason it's not there is not because of any disagreement. It's just that the use case we had at the time was passing a string, and so there was no need for the proposal to support booleans. But the idea at the time was already that we would add booleans as soon as there is a use case for it. + +OFR: I was too slow to hit the reply button on the optimization topic. We discussed it, and we were actually thinking that this might turn out I mean, not making promises, but I can see this landing somewhere in the middle between the optimized path and a random user-defined function that does something so even from the performance point of view, I think this proposal makes sense. + +DRR: KM? + +KM: To clarify, I'm not saying that it wouldn't be faster than the slowest thing because you don't have to make a call from basically whatever your native thing is in most implementations back to JavaScript just that it would not necessarily benefit from all the optimizations that would exist in the normal fast path. + +DRR: RBR? + +RBR: Sorry. Since this is a performance API in general, using an out prototype will prevent for example, in v8, it's a dictionary mode in most situations. So you have a slow access afterwards. And this can have a huge penalty. So it's kind of a weird API for me where you want to make something faster and at the same time, it's almost guaranteed at least as of today. I mean, maybe there are future optimizations, but as of today, to make things almost certainly slower overall. + +DRR: OFR? + +OFR: It's funny that you mentioned this because it's actually coming it just came up. I was just in a discussion about this. So just to make this clear, it's only slow if you create a so basically, if you create an object literal and the prototype is null on the object literal, then it directly goes into dictionary mode. And it has a historical reason because this is how basically, this is to detect when objects are used sort of as dictionaries. And so yeah, it might change, but basically, it's not going to affect this API because we can decide it's not that all objects which have a null prototype are in dictionary mode. It's more like using the null prototype in an object literal, we use as a heuristic currently that this object will be used in a dictionary mode. And it's actually hard to deprecate, or it might turn out to be a hard to deprecate heuristic, because we even advertised it in the past as do this if you want this behaviour. So we'll see where we land on that one. + +DRR: I'll give a quick time check. We're under five minutes now, but it seems like the queue has shrunken. So that's good. RBR? + +RBR: Since I maintain something like I maintain a JSON stringify implementation where there are multiple options and I'm curious if you looked at the ecosystem for requests for similar functionalities because freezing a null prototype is something that at least I personally have not really heard of as a feature from users as I said, it's JSON stringify, not JSON parse. So it's a different part of the API, but for there, what is common is definitely BigInt, for example, number one kind of that's like everyone wants to handle it one way or the other. It doesn't matter if it's like a string or bigint. Some have one perspective, one have the other. And there are a couple more of these or how to throw on particular things and to have a safe stringification. That's something common there. So how's that in this proposal coming by? Is this really a frequently asked for thing? + +ACE: It's frequently asked for by Bloomberg delegates. We like immutable data. We operate one of the largest JavaScript code bases in the world. + +RBR: Maybe it would be nice to get some data besides Bloomberg. + +ACE: So I think what's important here is we do two things. We can either look at what the ecosystem is doing and then mirror it, or we can innovate in a way that we think people should be doing. Maybe something isn't common…yet. Most code does `JSON.parse` and they don't then go through the hassle of freezing it. Because it's extra stuff. I think sometimes just because something isn't happening isn't because people don't want it. It's just because it's not convenient. You have to write a function or pull in a library. So I think sometimes things will only become popular once they're in the language. But I completely see what you're saying. And I think the BigInt one, 100%, we want to see that as a follow-on as well because we do see that in the ecosystem. One of the most common use cases for the reviver is BigInt. I think the date one is more complex, but the BigInt one I think is straightforward enough that we should really do it. + +DRR: All right. + +RGN: Also in a separate proposal, right? + +DRR: The queue is empty. And with a minute and a half to spare. Shall we figure a conclusion here? + +PKA: What did we hear about—Did Linus say that he or did NRO say that Linus had reviewed it? + +NRO: I think Linus did review this, but he did not approve it. So we need to wait for Linus to confirm whether he's ready, was done. + +PKA: Got it. Okay. So yeah, can we do a follow-on at the end of the meeting to see if we've got a review? Thank you. Okay. Thank you, everybody. + +### Speaker's Summary of Key Points + +* The proposal has incorporated the feedback from the previous plenary +* It now overloads the existing `JSON.parse` to take an options bag +* There is desire to improve on the naming of the 'preferNullPrototype' option + +### Conclusion + +* Stage 2.7 was not requested due to waiting for an editor's sign off + +## [Intl Sequence Units](https://github.com/tc39/proposal-intl-sequence-units) Stage 2 Update + +Presenter: Shane Carr (SFC) + +* [proposal](https://github.com/tc39/proposal-intl-sequence-units) +* [slides](https://tc39.es/proposal-intl-sequence-units/slides/stage_2_update_2026-09.html) + +SFC: So sequence units are for measurement systems that employ multiple units in a sequence to express a single magnitude. So for example, these are some common ones you'll see. If you're trying to measure the length of something, you might measure it in foot and inch. It's very common in countries that use those measurements. And then meter and centimeter. Meter and centimeter is common and also in some countries for measuring person height, for example. Mass, pound, and ounce, kilogram and gram. So a common misconception is that this is just an American thing, but actually this is used in other places as well, even in the metric system. So that is what our sequence units. + +SFC: So this is just a stage two update. There's been a few things you've been working through in the TG2. The first and probably the biggest change is this one here, array as input. So we discussed along with the numerics champions about whether to use object versus array and for various ergonomics reasons, we switched over to using an array. And this is what it looks like. So the stage two proposal that was approved used the syntax on the left, but now the spec is using the syntax on the right. Or at least the spec in an open pull request is using the syntax on the right. So that's the first update. + +SFC: I'll go through all the updates and then go to the queue afterwards. The second one is significant digits. Good. We can digits, but we weren't able to come up with a cohesive definition of how to define how significant digits should work, because one argument is that you could say, well, you like, you have a running total of significant digits and you deduct from that total as you render numbers. So, for example, like, if you're trying to render 5 foot 11 inch, you might render as 5 foot 10 inch, because that gives you 2 significant digits if that's if 2 significant digits is your target. But that is kind of doesn't make I don't think anyone thinks that that's a good idea. So another approach is, well, what if you just apply it to the smallest unit? That's how we do it with fraction digits. Why not do that also with significant digits? But that produces cases like this, which 3 feet and 0.18 inches is much more precise than you, I think, were intending, when you said just give me 2 significant digits. + +SFC: So given that we're not able to come up with a well-defined definition for this, the recommendation is we throw an error and it could be a TypeError or a RangeError. I think I actually opened an issue after that discussion earlier. But it'll throw an error of some type. Of something. There. It'll throw and just as a reminder, fraction digits remain supported. They modify the smallest unit in the sequence unit. Cool. So that's this one. + +SFC: Issue 8. So in the July plenary, I had an agenda item where we discussed time and duration units, and during that slot we got a little bit of input from the others in the plenary. So one realization I had looking back through the notes was that, there are sort of two perspectives here. One comes from the INTL side of things, the INTL point of view, which is that—we spent a lot of time designing INTL duration format. We should use the INTL duration format. And then the other point of view is, but we have this Amount thing, which is going to be super ergonomic and should support units even if they're supported elsewhere. Just because they're supported in CLDR. Like, a time unit is a time unit. It shouldn't be a special case. + +SFC: So given this, my suggested path forward here is that we stick with the sequence unit proposal as written, which does not have time units for formatting. But then Amount can go and do its own thing. Amount, if it wants to support time units, it's fine. And one suggestion that Eemeli had made which I'll put on the slide here, but it needs to be discussed in much more detail. And amount is out of scope of this presentation. So I'm sort of giving this 3-line snippet and it's out of scope of my presentation today is that perhaps amount could delegate to INTL duration format so that you can still get 2 locale string that just works. So that's my suggested path forward. So the impact on this proposal, which is INTL sequence units, is that we just continue with the status quo, which is no time units in INTL number format for sequence. + +SFC: So those are the 3 issues. 16, 14, and 8. This is this gets us to the bottom of the open issues on the repository. So this proposal is going to be getting pretty close to stage 2.7. I'm not asking for stage 2.7 today because the spec text wasn't quite ready and I wanted to make sure that we are happy with all of these changes and then according to the notes, EAO and DLM are the stage 2.7 reviewers. For this proposal. Cool. Are there any comments? + +WH: Where would degrees, minutes, and seconds fall into? Would they fall into any of the domains of the upcoming proposals? + +SFC: The question of arc, minutes, and arc seconds was brought up a couple of times a couple of presentations ago. We have an open issue for it. We decided it's out of scope of the current proposal. It could be added in a follow-up proposal. We currently have the unit degree, but we don't have the unit arc, minute, and arc second currently in INTL. So at a point at which arc, minute, and arc second are added to INTL formatting, then they would be added also to the sequence units list. Once that gets added. But since we only have degree. There's no need to add degree to the sequence units table because we only need to add them if there's at least 2 in the class. + +RGN: Yeah. Just a clarifying question; what kind of feedback are you looking for right now, given that this was an update? Do you want plenary discussion of the issues that were on the slides? + +SFC: Yeah. I'm so in TG2, we discussed all 3 of these issues also in the numerics champions call. I'm looking to see if plenary is happy with these changes to the proposal. And then so that when we come back for stage 2.7, it's more like okay, this is the state of the proposal. It hasn't changed in the last stage 2 update. So if there's anyone who has comments on these or wants to dive in and dig into any of these 3 issues and the current proposed solutions, then this is the time to do so. + +RGN: All right. In that case, I don't remember the full details of all of these. So just speaking to what is on the slides, accepting array inputs, I am definitely in favour of. Disallowing significant digits by throwing an exception, I’m also in favour of. And excluding time sequence units from number format still seems reasonable, especially because that decision can be reversed if and when the use case presents itself. + +DRR: The queue is empty. Do you have anything else that we want to conclude with, Shane? + +Summary: Three in-progress PRs were discussed. + +### Speaker's Summary of Key Points + +* The temperature was positive on all proposed changes: array inputs, disallowing significant digits, and excluding time sequence units. + +### Conclusion + +* Will return for Stage 2.7 in a future meeting. + +## Intl Unit Protocol Stage 2 Update + +Presenter: Shane Carr (SFC) + +* [proposal](https://github.com/tc39/proposal-intl-unit-protocol) +* [slides](https://tc39.es/proposal-intl-unit-protocol/slides/stage_2_update_2026-09.html) + +SFC: All right. INTL unit protocol stage 2 update. So similar kind of thing. As a reminder, INTL unit protocol. A number ought to be annotated with the quantity it is measuring. Which is important for MessageFormat. This is also part of the motivation for Amount. But the idea with INTL unit protocol is we need to have some way to express a number annotated with the quantity that is measuring. And we can think about the shape of that input in terms of the ergonomics when passing it into INTL number format. So currently, you can do what's currently shown on the left of this slide. Your you pass a unit into the constructor. + +SFC: The this proposal allows you to pass the unit into the format function. Instead of only into the constructor, because this allows the unit to be selected at format time instead of at construction time. So here are some issues that came up with INTL unit protocol. So ACE made a good observation that in order to retain additional backwards compatibility, we should be we should think about exactly the conditions on which we sniff for the protocol. So if what I mean when I say sniff for the protocol is when you pass an object into INTL number format prototype format, currently, we call `Symbol toPrimitive`. And we should continue to do that because that is how INTL number format has worked for a decade and a half. But what we want to do is that if you pass in an object that conforms to our protocol, the INTL unit protocol, we want to be able to detect that as INTL unit protocol. So we went through this in with some level of detail in multiple TG2 meetings. + +SFC: And this is the current proposal for how to do this. So if input is an object, so we said if input is object, then we call the then we get the 2 fields value and unit. And then if both of them are not undefined, then we assume that it's a unit protocol object. So that is the current behaviour. I just want to emphasize that this also has the implication that the dimensionless or non-unit formatting is with the null unit. Not undefined. If you explicitly opt into undefined, as the unit that is considered as the field non-existing, we had a discussion where we went back and forth on should the thing on the right for print 333 instead of 111. Like should the existence of the property somewhere in the prototype chain trigger the protocol? And we decided no. It's just if you want to do that, you use unit null, not unit undefined. So unit undefined will be the same as if that field did not exist. So that's what this slide is all about. Oh, no. This slightly spilled off the edge of the slide. Open question coercing the value field. So I opened a question on the GitHub about coercion because this has been a topic of a lot of interest in this committee. So the question is in the INTL unit protocol, should we call `Symbol.toPrimitive` on the value that's passed into the INTL unit protocol? Currently, we call `Symbol.toPrimitive` on the arguments to the format function. But do we want to also do that on the value? So currently, in the spec, we do that because we use the same abstract operation for both. So we use the abstract operation, which calls toPrimitive. And this proposal only deals with taking the argument in the format function and moving it into the value field. I'm sorry this pulled off the bottom of the slide here. + +SFC: Oh, there actually is darn. Can I there's 2 yes/no with pros and cons. And they spilled off the bottom of the slide. I'm going to like present the markdown version of this so you can see it without it spilling off the bottom. And I'm going to figure out how to do that right now. Preview. Open preview. + +CDA: If you want it, I don't know how quickly you can fix your slides. But if you want to take a couple minutes, we can afford you that luxury. Up to you. + +SFC: Okay. How many times do I have to click OK in order for it to share? I have to click like 3 times. Okay. So here's the is it sharing? There it goes. I'm going to zoom in. I'm going to zoom in over here so you all can see it better. Okay. So this is the slide without the slide view. I'm trying this new thing where I'm using markdown to make my slides. But then it means that it's not WYSIWYG. And I don't catch these types of issues. Until I'm actually trying to present them. So should two into mathematical coercions. So here's the arguments in favour of that. So the argument for yes is that it uses the standard abstract operation, the same one that we use in the format function without the arguments. It means that the unit that this proposal, the INTL unit protocol, deals only with the unpacking of the value and unit fields without changing the semantics of how they behave. And it seamlessly supports custom numeric types. We can agree to disagree on whether or not that's intended behaviour. But it does currently work. You can have a custom decimal class that when you pass it into an INTL number format, it just works if it implements a Symbol to primitive that returns a string. That will just work. And it seems nice if it just works in INTL number format currently, that it should continue to work if you're using INTL unit protocol. The reasons to disallow it are that it aligns with the stop coercing things. But it does make the format function self-inconsistent, which is kind of, again, repeating what it says above. So the only reason to disallow it is because it aligns with that principle. But an exception to that principle was if there's a strong reason to keep consistent with how things are currently behaving, then maybe that's the reason to do that. + +SFC: So there's also one more open question over here that I have. Maybe I could switch back to the actual slides for this one. I want to switch back to the actual slides for this one. Okay. Switching back to the actual slides. Open question. Non-unit formatter. What should happen when passing a protocol to a non-unit formatter? So if you have this call site. What should be the behaviour of this block of code? Should it throw a TypeError? Should it format the 333, the value? Or should it format 111? Currently, the spec is doing the 333. Because it always reads the protocol. All the time. And then we'll just ignore the unit because it's null. But no, actually, this slide says oh, sorry. It actually does the first one because there is a unit. The unit exists and then it sees that it doesn't match because the formatter is the wrong type. It wasn't configured with a unit field. So this is another open question for which direction we should take this. Whether we should be where we should see that the protocol is there. We didn't expect the protocol. So throw or whether we should only read the protocol if the formatter supports the protocol. In other words, if it was configured with style unit or style currency. + +SFC: Thank you for the little bit of a detour. I'll fix the slides and republish the slides later so that people looking at this later can see the slides the way they're supposed to be seen. But I am quite interested in a discussion on these issues. So let's go ahead and dig into the queue. + +SFC: Okay. Plenty of time for people to go and voice opinions on this. And especially on the coercion thing. Because I know a lot of people in the room have strong opinions on coercion. + +DRR: Do we have strong opinions on coercion? + +SFC: I don't does anyone have any opinions on the other parts, the easier parts, which is the protocol sniffing behaviour and exactly how we handle null versus undefined? Those are the easier ones. I would assume. But maybe they're not. This group often surprises me. And then coercion, I expect to be the hard thing that people have opinions on. But I could also be surprised. + +JHD: I put two on there. I'll do the easier one first. I think null is better than undefined. Because the language has already embedded that as a precedent with default parameters. And we already have added affordances to make it easy to treat them the same. Nullish coalescing and optional chaining. So that was my easy one. And then the other topic was I just think we shouldn't coerce. People shouldn't be still relying on coercion. Anyone using TypeScript isn't. And anyone using linters or following best practices isn't. And so I just don't think the inconsistency is going to matter. And I think people should just if somebody is intentionally relying on coercion, I feel like my response would be “too bad, write your code cleaner”. And that's obviously an opinion. And not an objective thing. But I'm not really worried about a consistency issue there. Because the majority of people, I think, are already going to be passing the right type of thing. + +DRR: From Christian, we have plus one preferred null over undefined. End of message. + +RGN: Protocol sniffing feels right to me. We were willing to pursue a strategy that involves prototype chain interrogation, but landing on one that doesn't require it is more satisfying. + +DRR: We have exhausted the queue. I believe a little more time for other people to provide some thoughts. Suggestions, opinions. And they're coming in. + +SFC: Maybe it's better instead of asking for opinions if I say what if I don't hear any opinions, the thing that I will bring back for advancement next meeting, maybe that will get more people to speak up. So I intend to bring this thing with unit null. It sounds like we mostly agree on that. I would like to bring for coercion, I would like to use Intl Mathematical Value because that's the current abstract operation we have. I think that the advantages are stronger here because the making the function be self-consistent. I think is important. And making unit protocol be scoped to just the unit protocol and nothing else. I think is a cleaner proposal than trying to also modernize other parts. Because the two Intl Mathematical Value does a lot of stuff. And coercion is one of the things it does, but it does a lot of other things. And I don't really want to open that can of worms I just want to keep Intl Mathematical Value working the way it does. So that's my opinion here. And then my opinion on this one, I think that changing the scope so that we only read the protocol when the formatter is of a shape that needs the protocol. I think is it also a direction that I would like to pursue. That is option three. So if that helps, that's my preferred path forward. Does that make anyone else join the queue? + +ACE: What coercion is it expected that these values could legitimately be strings in cases? Is that if someone's trying to represent a string with a certain number of decimals in that it's not. + +RGN: Strings are explicitly supported. And we spent a lot of time to make them work well. + +ACE: So to me, there's coercion where it's like, they're giving us the wrong thing, but we're going to make do. And then there's they're passing in a value that's yes, it's a string, but it's a string that we explicitly expect and are supportive of. But it sounds like this would also bring in the other type of coercion as well where people. Actually passing in values that we would frown upon but still it would work. + +SFC: It's really the only question is, do you call `Symbol.toPrimitive` or not? It's kind of that's because the converting the number to a string is a thing that we need to do anyway. And there's not really a good way to avoid that. But again, it's maybe there should be. Maybe we should make a sanitized to Intl Mathematical Value. I don't really want to have to explore that. I just want to use the thing that's there that we've worked a lot of time to get it to do what it does. + +ACE: Yeah. This sounds okay. This to me sounds like not the bad type of coercion. This sounds more like correct conversion. + +RGN: Yeah. We're already on the right slide. I prefer the first option here. I'm very much against ignoring the unit protocol fields because that creates a forward compatibility hazard. If we ever wanted to introduce support for them, then now we deal with yet another scenario where existing code has to change in backwards incompatible ways. As opposed to using the thrown exception case allows us to address that much more conveniently. + +SFC: How do you feel about the fact that right now we're changing a we're already changing a non-exception case to have new behaviour? + +RGN: I don't want to stack those changes one on top of the other. Right now, we're biting the bullet because it gives us significant new functionality. And we should be prepared for future evolution rather than repeating the mistake that bound us into backwards incompatibility in the first place. + +SFC: Cool. If there's no one else on the queue, I'm happy to yield the floor. I think I got what I needed to get out of today's discussion. + +DRR: Okay. Can you restate the specific conclusions of what you're intending for the next meeting and decisions you're leaning towards? + +SFC: Yeah. So the conclusion here is for the protocol, we'll use the spec, which is currently in the repo and presented on the slide, which requires the presence of both the fields and that they must be not undefined. And which means that the lack of a unit is represented as null. I'm currently leaning toward the current spec text on coercion, which uses the existing two Intl Mathematical Value abstract operation. The way that it currently works and then I am based on RGN's feedback, I'm going to go and likely keep the current spec behaviour on how non-unit formatters interact with the Intl unit protocol. So that is all to say that the spec that's currently in the repo is a spec I'm going to be pretty happy with. And I intend to come back in a meeting in the near future to ask for two seven. So thank you for your time. + +### Speaker's Summary of Key Points + +* The temperature on the currently specified coercion behavior was positive. +* RGN pushed back on ignoring the protocol for non-unit formatters. + +### Conclusion + +* Will return in a future meeting for Stage 2.7 + +## Active proposals missing champions: `function-sent` (Stage 2), `collection-normalization` (Stage 2), `destructuring-private` (Stage 2) + +Presenter: Michael Ficarra (MF) + +* No slides presented + +MF: Similar to the last topic I brought, we do have three proposals that we do not have current champions listed for. They are each stage two. And I wanted to resolve this again either by marking these as abandoned or by oh, share the proposals explainer? Oh, each individual proposal's explainer. One second. I have so many tabs open. Okay. Here's the first one. + +MF: Here's one of them. This is the destructuring private fields proposal. This was originally championed by Justin. Actually, Peter had brought this up at a previous meeting where we could not find anybody who was willing to champion it. And we discussed possibly bringing it to a future meeting to mark it as officially abandoned or request withdrawal, whatever. Since then, KG has actually reached out to me. KG, are you here? He messaged in the chat. But he wanted to volunteer as champion for this proposal. I believe his words were "if nobody else does". + +DRR: May not be here. We do have a clarifying question from CDA. + +CDA: I'm just curious. Why these three specific proposals? I'm thinking about how when we were on the topic of looking for reviewers, one of the proposals champion was clearly not really in committee anymore. That could have been on this list. I'm just sort of… + +MF: It is on this list. Yes. And this was just according to the data that we had recorded on the proposals table. + +CDA: Thank you. + +MF: Again, we're working with—we're getting to a really good state, hopefully. So yeah, this is just the first tab I could find. So this was the one I did first. So would anybody like to rush in front of KG to champion this proposal? + +ACE: I want KG to champion this because of how close it related is to KG's other proposal. I think it makes sense to have a coherent vision of the two. + +MF: Sorry. Yeah, great. I'm sorry I did not sync up with you before this then. I just—that was also my same conclusion. Okay. So for this, it sounds like we have—and I'll go back to the matrix to confirm—but it sounds like we have KG volunteering to take this over as champion. I'll link to evidence for that following this presentation. The next one, let me go back. Collection normalization. + +DRR: Just really quick. I mean, Chip, do you want to still ask about this? + +CM: Yeah. I'm just kind of puzzled. You said there's no champion because Justin was the champion. But Justin is actually on the call. + +MF: Yes. We established at the last presentation that Justin was not interested in continuing as champion. + +CM: So he said he don't want to do this no more? + +MF: Yes. At the time, we did not say that we are going to ask for the proposal to be withdrawn. + +CM: That clarifies it. Thank you. + +MF: Yes. Okay. We have collection normalization. This one, we talked about earlier. It did not have stage 2.7 reviewers assigned. And it also formerly had a champion who is no longer active and our data has BFS removed as champion. So would anybody like to volunteer to champion the collection normalization proposal? Again, if nobody does, I am planning to move to mark this proposal as abandoned. So we did have three people sign up as stage 2.7 reviewers for this. I'm one of those people. Ashley or Jordan, are you interested? You'd have to step down as 2.7 reviewer, unfortunately. + +JHD: If no one else is willing to step up, I can certainly look into it for a future plenary. + +MF: That was a very weaselly answer. + +JHD: Yeah. I mean, I have to page it. I have to page it back into context and look at the notes and get a sense for myself of how of what the obstacles are in front of me for the proposal and all that stuff before I want to commit to it. So that's why I gave a very vague answer. But assuming it seems viable, I would definitely like to continue pursuing it. + +MF: Okay. It sounds like you're not volunteering immediately as champion, but you would prefer that I not move to mark it as abandoned at this meeting. + +JHD: Correct. + +MF: Okay. That seems like a fine resolution for that one for now. It's still in limbo. And finally, we have `function.sent`. This is a very old one. This should be from, I think, 2015. This is AWB's, right? There it is. + +JHD: The last time I brought `function.sent` up, the only person who was interested in there was non-zero people who I think were interested in seeing it land. But the only person who was interested in putting in work was JHX. And I don't believe there's been any work put into it since that time. + +MF: Yeah. + +JHD: Just to provide some context. + +MF: Yes. I mean, yeah. I think that this is a good proposal. I think it's valuable. I'm not willing to champion it. Is there anybody on this call that is willing to champion it? I will unfortunately ask to mark it as abandoned if there's not. And again, I am a supporter of this proposal. I'll give it an extra long pause. + +SFC: I assume abandoned. I assume abandoned means that it can be picked up later at the same stage if someone wants to pick it up later. It's just being explicit about the status. + +MF: We are never beholden to our own rules. We can change our rules at any time. So yeah. So yes, we can transition from any stage to any stage if we want. + +JHD: But yes, the intention of abandoned is that the only reason it's not advancing is that nobody's putting the work in. And therefore, that anyone who shows up can just pick up where it left off. If that's if there's pushback, then that might warrant a different note. + +MF: Yeah. The difference from something like rejected or withdrawn is that those are positively indicating that the committee does not wish for this to proceed. Whereas abandoned just means that nobody has indicated a strong enough desire for it to proceed. Okay. It sounds like nobody is willing. So I would like to ask for consensus that after many, many years, function sent is marked as abandoned. + +DRR: Quick thing. Chris's topic, I think, just go ahead, Chris. + +CDA: I would still like to voluntell Michael to do it, but can't have everything. + +**Poll:** should MF champion this proposal? (1 min, 14 voters) — @ctcpip + +* ❤️ Strong Positive: 13 +* 😕 Unconvinced: 1 + +DRR: And then from Peter, plus one, I support this in a message. So yeah. And then. + +CDA: Sorry. Is that support for voluntelling Michael to champion it or for marking it as abandoned? He's nodding his head for abandoned rather than. + +DRR: Yes. I'm not sure. I assume either way. Leaning towards abandoning. RGN's also saying he's a big fan of MF just picking up the work. End of message. I think that actually warrants its own proposal at this point. But I don't know. + +MF: So I guess for the record, for any future delegates who are looking back at the history of this proposal, it sounds like there's currently a decent amount of very weak support for this proposal. And it has a high likelihood of moving forward if you want to put in the work. But it sounds like we do have consensus then to mark it as abandoned. + +CDA: I just want to try one more time. If I volunteer to be a reviewer, will you champion it? Meet me in the middle. + +MF: It really sounds like people do really want this. Why is nobody—the only reason I'm not championing it is I have other things I have to champion. + +CDA: What if we did so some people have left the meeting because time zones. We could do a continuation and see. + +MF: Fine. Yes. I support that. Let's add a continuation topic for changing function sent from abandoned back to stage two if we can find a champion. + +CDA: NRO on the queue with, I think, CDA needs to kneel in front of MF and ask again the night is young. Daniel is entering the queue. Sorry. I've you're supposed to be chairing, and I'm stepping on your toes. + +DRR: This is a joke. Don't or is it? Maybe. Okay. We're please direct your attention to TCQ and vote for your choice here. + +MF: The thing is, if I was to champion this, I know I'd be coming back and everybody would be waffling and unsure about the nitty-gritty details of the syntax. You're all so happy and supportive today. It all changes next time when I actually bring it back. So it's just not happening. + +CDA: The committee has spoken very clearly that we all want you to do this, but all right. Thanks, everyone. That is our last topic of the day. That brings an end to day one. Please remember to write your summaries and conclusions if you have not already done so. + +### Speaker's Summary of Key Points + +* Three Stage 2 proposals lack current champions: `function.sent`, collection normalisation, and destructuring private fields. +* New champions or abandonment were proposed to resolve their status. +* The former destructuring private fields champion had stepped down, and KG had offered to take over if nobody else volunteered. + +### Conclusion + +* KG will take over as champion of destructuring private fields. +* Collection normalisation remains without a champion while JHD assesses whether to take it on; abandonment was deferred. +* `function.sent` was declared abandoned by consensus because nobody volunteered to champion it. It remains available for future work. +* A continuation topic will seek a champion to restore `function.sent` to Stage 2. diff --git a/meetings/2026-09/sept-30.md b/meetings/2026-09/sept-30.md new file mode 100644 index 00000000..3175447b --- /dev/null +++ b/meetings/2026-09/sept-30.md @@ -0,0 +1,1786 @@ +# 116th TC39 Meeting + +Day Two—30 September 2026 + +**Attendees:** + +| Name | Abbreviation | Organization | +|---------------------|--------------|--------------------| +| Waldemar Horwat | WH | Invited Expert | +| Richard Gibson | RGN | Agoric | +| Ross Kirsling | RKG | Sony | +| Danilo Tedeschi | DFT | Google | +| Ashley Claymore | ACE | Bloomberg | +| Samina Husain | SHN | Ecma | +| Lea Verou | LVU | OpenJS Foundation | +| Jordan Harband | JHD | Socket | +| Nikolaos Papaspyrou | NPU | Google | +| Ruben Bridgewater | RBR | Invited Expert | +| Jesse Alama | JMN | Igalia | +| Jack Works | JWK | Sujitech | +| Chris de Almeida | CDA | IBM | +| Christian Ulbrich | CHU | Zalari | +| Luna Pfeiffer | LPR | Yavashark | +| Yusuke Suzuki | YSZ | Apple | +| Keith Miller | KM | Apple | +| Istvan Sebestyen | IS | Ecma | +| Ron Buckton | RBN | F5 | +| Chip Morningstar | CM | Consensys | +| Daniel Minor | DLM | Mozilla Foundation | +| HE Shi-Jun | JHX | Invited Expert | +| Justin Ridgewell | JRL | Google | +| Kevin Gibbons | KG | Invited Expert | +| Matthew Gaudet | MAG | Mozilla Foundation | +| Mathieu Hofman | MAH | Agoric | +| Michael Ficarra | MF | F5 | +| Mark S. Miller | MM | Agoric | +| Nicolò Ribaudo | NRO | Igalia, S.L. | +| Olivier Flückiger | OFR | Google | +| Philip Chimento | PFC | Igalia, S.L. | +| Peter Klecha | PKA | Bloomberg LP | +| Rob Palmer | RPR | Bloomberg LP | +| Shane F Carr | SFC | Google | + +## Amount Stage 2 Update + +Presenter: Jesse Alama (JMN) + +* [proposal](https://github.com/tc39/proposal-amount/) +* [slides](https://notes.igalia.com/p/tc39-2026-09-amount/) + +JMN: Good morning. This is Jesse. I'm at Igalia. Working on this with Google Internationalization. I'm also presenting this on behalf of my co-champion, EAO, who unfortunately could not be here. I just wanted to give a bit of an update about what we've been doing with the amount proposal at stage 2. We have a fairly active community of champions and fellow number nerds who want to talk about Amount and similar issues that all kind of come together here. So I have a couple of smaller items, and somewhat larger item to report. And at the end of the presentation, I'm going to ask for a bit of feedback from plenary. Because there's a bit of discussion among the champions about directions we could take. Having to do with the spec. And we would appreciate any insight that you might have. + +JMN: So first, I just want to present a couple of changes since last time. And then focus in on what is most interesting. For those of you who may not know, just in very briefly, the amount proposal is all about having some notion of a number and a unit together, and supporting unit conversion. So things like feet to meters. Kilometers to whatever. Note that currency conversion is not included there. Because we all know that that's not really a stable data. + +JMN: So just briefly, since last time here, we've introduced a couple of conveniences or maybe bug fixes, you might say. And as Shane was talking about yesterday, we've started to work on the notion of sequence units, which is something that we've talked about and wanted to add to the proposal for a while now. But we are now tackling that in earnest here. Since last time, we've added a somewhat of a shorthand here. Because we expect that most people will simply have some kind of numeric value and a unit. So why not just give them the option of writing exactly that in order with two parameters here, rather than the more official notion, which is to have a kind of option back there where we say, if we want to have 1.23, we would give some kind of option bag with a unit meter there. But clearly, for the main use case here, we have some kind of shorthand there. That was an example with a constructor. The same goes for the convert to, which is the main method here that we have. + +JMN: The biggest thing that we've been working on since last time we presented is adding sequence units. As Shane was talking about yesterday, sequence units, at least for Americans, have a very common use case, but it's not just a US thing. We expect this to be applied elsewhere too. So here, for example, let's talk about 5 feet and 11 inches. You can see that I'm creating an amount here with an array, with two numbers there, two integers. And you can see that we store an array. That wasn't present last time we talked about amount. We can also talk about the precision of sequence units. So precision is one of the main features that amount is supposed to support. The examples I've given you so far just have to do with saying, this is a value, and here's the unit. And that's fine. But we also want to support the notion of precision. Two kinds. Fraction digits. And significant digits. So here, as we were talking about maybe yesterday or hinted at yesterday, we have the notion of fraction digits applying to a sequence unit. So think about specifying 5 feet and 11 inches. With one fraction digit. Just impute that or just say that it has to have one fraction digit of precision. The value that we end up storing there is a bit of a hybrid. So it is an array. That's understandable. But the types of the items of the array are mixed. We store an integer there, a number, that is. And then a string, which carries that precision that was indicated there. And so the precision is going to apply to the final part only. So the idea that precision would somehow apply equally to multiple components we exclude that. It's applying only to the final part. + +JMN: We've also made a decision in the among the champions group to say that every non-final part of a sequence unit is supposed to be an integer. So maybe it might make sense just as a statement to say things like 5.3 feet and 2.6 inches. But that's not what we support. We just support integers for the non-final parts. Just to warm you up and give some examples of converting to something like a sequence unit. So imagine we start with something like meters, and we want to convert to feet and inch. Then we would have the value B, and that's what it would look like there. Notice that when we apply convertTo, we didn't specify any precision there. And so the entire operation there is working entirely in number space. You just get numbers back. Well, I should say you get an array, containing numbers back. In the second example with C, here we're starting with meters and converting to foot and inch. And we're specifying a precision there. And notice what happened to the second component of the array. It turned into a string. Just to make sure that nothing gets lost. So we store the 10.9 there as a string. And the reason why it's a string is to also capture any kinds of trailing zeros and stuff like that, which of course gets lost in numbers. Going the other way around, you can convert from a sequence unit so if we have, for instance, 5 feet and 11 inches, we can convert that to inch. We can convert that to meter. These are just simple units. That's pretty straightforward. + +JMN: We had to make a decision about what kinds of sequence units we'd support. And we made a decision that the units have to be listed in decreasing magnitude. And there has to be integer conversion multipliers between sequential units. So things like foot and inch are okay. I've been using that so far in my examples. But things like inch-and-foot, might make sense in some world. But we've decided that that's not supported. TypeError. We can have a discussion about whether that's the right thing to do. We're open to feedback about that. Please let me roll with that example for now. But foot-and-centimeter kind of makes sense. But we've decided that doesn't make sense. Or at least we reject that. Because there's no integer multiple from which you go from foot to centimeters or from centimeters, rather, to feet. + +JMN: Another discussion that we had is about supporting currency. So the amount proposal does not have a native notion of currency here. But when we try to convert this to a locale string or try to use it in some kind of Intl setting, then we need to be a bit more careful. Because then the notion of currency versus some other unit does actually make sense. And we've agreed on the convention here that in Intl settings, we can use three-letter currency codes, uppercase, and that's it. So for instance, here, look at 12.5 or 12 euros and 50 cents. That gets nicely converted. You can see there, imagine you're working in, let's say, in a German locale. But. The word day, the lowercase D-A-Y, that gets converted in a different way. The German word is Tag. And that's why you see this TG here. So lowercase three-letter units are no longer formatted as currencies. So there are things like that in the CLDR, day, ton, and so forth. Those have to be understood as non-currency. + +JMN: Okay. So that was part one, showing you some of the updates that we've been working on. Here's a request for feedback from the committee. So this is where I know it's a bit early, but I ask anyone who's interested in numbers and calculation and stuff like that to wake up and pay attention to this part. The issue is that unit conversion involving sequence units or compound units, so things like anything like X-per-Y, like meters-per-second-squared or miles-per-gallon, these kinds of things, if we're converting to and from these kinds of amounts, we need roughly speaking more math than converting between simple units. So there's more multiplication potentially more division going on when you convert with these kinds of units. It's bad enough going from, let's say, feet to meters. But it's even worse when you're converting from, let's say, feet to some kind of sequence unit here. So converting to and from sequence units requires multiple mathematical operations. And that's just inherently so. That's unavoidable. If we convert from a sequence unit, then we have to convert each part and then add this up. If we're converting to a sequence unit, well, then we have to kind of convert to the smallest unit and partition and then have a kind of operation that kind of bubbles up potentially. And the issue here, as you might guess, is that more operations means more rounding and more chance for some kind of user-visible error. Where some kind of conversion that might work out very cleanly on paper ends up getting looking pretty ugly when you run it through our convert to function here. We get things like compound units. So things like simple example, let's do meter-per-second. And convert that to miles-per-hour. Now look at that. We have to convert meters to miles, seconds to hours. So there's not one multiply here. The issue is that by supporting these kinds of units, we're just opening the door for more kind of precision loss and user-visible errors. Here's another one as an American living in Europe. I have to frequently do these kinds of mental gymnastics when talking about things like the efficiency of a car or things like how much fuel is used for a certain distance. Because in the US, the typical thing is miles per gallon. For the efficiency of a car. But there are other ways of measuring that. Of course, it doesn't use gallons. It uses liters. And it might not use miles, of course, things like kilometers are used. But even groupings like hundreds of kilometers are used frequently. So this example involves multiple multiplications and divisions just to get the right answer. And so the question for us in the Champions group is, how much precision should the spec promise? When we're doing more than just one simple multiplication, which already has a bit of complexity going on, you may recall the recently proposed FMA, `Math.FMA` proposal from Waldemar (WH). Which makes sense on its own, but it also is directly tied into the kinds of questions that amount is raising. Even before we get to sequence units. + +MM: What does FMA stand for? + +JMN: FMA stands for Fused Multiply and Add. That's a yeah. Yeah. So FMA is an operation that allows us to do multiply and add of three numbers as one single operation rather than the naive combination of two, which allows for more precision. + +JMN: So I'll give you a few options. And I will mention a preferred solution to this. But we're open to discussion about that. So again, we would like to stick to option one. This is the proposal. Is to stick with number-based math and leaning on this new proposal, `Math.FMA`. Fused Multiply and Add. Wherever that applies. Currently, the spec is using mathematical values for conversion factors. So we look in the CLDR table, which specifies the exact or it specifies constants. For converting between to and from all sorts of units. And we just import those into the spec. As mathematical values. And which is already a little bit of complexity for us. But when we add sequence units into the mix, then it becomes even more complex. And so the proposal here is, let's just use number math and `Math.FMA` wherever it applies. And that's as good as it gets. And if someone says, well, there's some rounding errors here or you could have done this differently, we just say, we have to bite that bullet. That's the best we can do. Option two is a bit of a luxury option for the Champions. Which is just to say, we just use mathematical values. Without giving any kind of guidance to implementations. So we, as the spec writers, give ourselves the luxury of just writing down the exact operations in among real numbers. And it's up to engines to figure it out. Test262 will say what's true. And implementers are on their own. They can do whatever it takes to get the right answer. A more drastic option is to say that we don't do conversion for things like sequence units. If someone is worried that a loss of precision or user-visible rounding errors is too bad, they might say, let's just rule this out. We think that's a drastic approach. But it certainly simplifies this discussion. + +JMN: So our preference is option one. So we're really excited about `Math.FMA`. We think that this is a powerful tool to add to our toolbox. That proposal is at stage two, I believe. Or is it two seven? Two? We're happy with that. We think that that's a reasonable choice. It's kind of the best that we can hope for. It allows us to have conversion between sequence units. But with our eyes open, we know that there might be some user-visible rounding errors. But they're at the same level, essentially, as the user-visible rounding errors that you already see in JS. + +JMN: There's a follow-up question to this about rounding. Because even if you were to say, okay, we stick with option one, we trust you, Jesse, and the Champions group to do this. There's another question about rounding, which is something we also support. The question is, how much rounding should we actually support for things like convert to? Currently, our intention is to support the rounding modes that are in ECMA-402. And there are several of them. Another option is to keep some of them. For instance, just the ones that are in IEEE. So a subset. A third option, more drastic, is to just drop rounding entirely. Just like when you do multiplication of two numbers. You can't specify the rounding there. We just do the arithmetic with numbers. Possibly with `Math.FMA`. And that's it. So that's also a kind of sub-question for committee consideration. + +JMN: And then a second question, that I would also like to propose, or invite discussion about, is you might have seen that what's going on with the values in amounts. It's a bit of a hybrid because we have you could have a number in there. It could be a string. It could be a BigInt. Or now, if we support sequence units, now you have an array of these things. So it gets there's another dimension of polymorphism or multi-type values here. And one suggestion is just to use some kind of frozen array. Regardless of whether that's a sequence unit or a simple unit. The thinking being that this just cuts down. Complexity. And there's just one data model for all use cases. We would still accept things like simple values as inputs, but then we would always store these as an array, even for even a one-item array. We think that that's a nice conceptual cleanup of the data model. We're leaning towards adopting this, but we haven't merged that into the spec yet. So that's all I have for you today. The discussion now goes to the floor. So the conversion is what kind of option do we want to do for sequence units and any precision guarantee that they might have or not have? And what about rounding? Do we want to support rounding? How much rounding? Should we drop rounding? And then now, in light of sequence units and the possibility that we have an array, as a value of an amount, do we want to just kind of simplify our lives and use an array there always for the value, even for a simple units? That's all. We can now go to the queue. + +CM: So just to satisfy my curiosity, you specified these rules for what's a valid sequence unit. Are those rules applied at spec time or at runtime? Meaning, for example, you said you could have `foot-and-inch`, but you couldn't have `inch-and-foot`. Is that only `foot-and-inch` makes it into the spec, or could I say, for example, `mile-and-inch`, which would be silly, and expect it to work? + +JMN: Good question. I think we haven't thought about that. Both options are available to us. Because we do rely on static data, essentially, the CLDR database and all the data contains there. We could bake that into the spec, not necessarily by literally importing that data into the spec, but normatively referring to that data. And then make it a kind of compile time, so to speak, error, construction time. Or we could do some kind of runtime checks. I'm not sure. We could do either one. Both doors are open. + +CDA: WH? + +WH: What happens with sequence units when the last unit or the last few units are zero? + +JMN: So do you mean things like 6 feet 0 inches? + +WH: Yes. + +JMN: Yeah. So that gets we keep that as a sequence unit. The zero is retained. Or do you maybe I misunderstand the question. + +WH: Yeah, that is my question. So for somebody's height, you'll get 5 feet 0 inches and not just 5 feet? + +JMN: Well, in the convert to function, you have to specify the target unit. So if you say feet-and-inch, then you will get a zero. There. You'll get an array that has a zero. For the final element. + +CDA: Okay. Mark. + +MM: Yes. First of all, can you hear me? + +CDA: Oh, I'm sorry. Hang on. We just had a late reply come in from Shane. + +SFC: I wanted to post it sooner, but the queue was slow. The question that Waldemar asked about in terms of formatting, that's a question for the Intl sequence units proposal. The actual amounts type supports zero-valued fields as zero-valued fields in the amounts, but then whether or not those get rendered when you call toTocale string is a question for the Intl sequence units proposal. Currently, they do get rendered, but there is some open questions about whether we should add options to make it easier to configure that behaviour. It could also be the case that options in, for example, in the conversion functions, when you call convert to, could optionally include or drop the zero-valued fields. So these are things that can happen via options in APIs, but the actual representation of zero-valued fields is, I think, it is in the Amount proposal. And it is also supported in Intl sequence units proposal. + +CDA: Mark. + +MM: Okay. So first of all, can you hear me? + +CDA: Yes. + +MM: Okay. So just some other examples of where the answer is not obvious to me is what about 5 feet 13 inches or 5 feet negative 7 inches? + +JMN: At the moment, I think you're opening up an interesting other kind of forms. Because at the moment, we don't do any kind of normalization there. Or kind of rounding up. So we would store something that is perhaps a bit nonsensical, 5 feet 13 inches. As is. There is some discussion in another issue about supporting some kind of a normalization or rounding up. Which does tie into this, I suppose. But we haven't yet found a solution for that. We would just store what the user is giving us. + +MM: Okay. And the arrays, whether you make everything an array or you just do the arrays for the sequence units, in both cases, I assume the arrays are frozen. And that the contents of the arrays are only primitive. There are no nested arrays. + +JMN: Yes, that is correct. + +MM: Okay. Thank you. + +CDA: WH. + +WH: I'd like to speak on the precision questions. First I'd like to separate compound units, which are things like meters-per-second, miles-per-hour, from sequence units. + +WH: For compound units, in most cases you can give exact answers by doing the multiplication of unit factors in mathematical rational integer value land, and then using FMA to do the actual conversion. + +WH: For sequence units, you get problems which I can illustrate using an example of 1001 millimeters. If you convert that to meters, you get 1.001m, which is good. If you convert it to centimeters, you get 100.1cm, which is also good. If we convert 1001 millimeters to meters-and-centimeters, then the correct answer would be 1m 0.1cm. That would argue for doing the mathematically correct answer. + +WH: However, if you start with 100.1cm as a Number value, and convert that to meters-and-centimeters, then the mathematically exact answer is 1m 0.09999999999999432cm. So I'm not convinced it's worth it to try to make the millimeter conversion to meters-and-centimeters work exactly while the centimeter conversion to meters-and-centimeters would still appear broken. Thus that would argue for just doing the straightforward approach of using the FMA mathematical value calculations to compute the base unit (100.1cm in my example), and then when you split the base unit value into the various sequence components just use normal Number math for that. + +JMN: Okay. Yeah, that sounds… sorry. Please go ahead. + +WH: Okay. And for the other question, I have a weak preference for not using arrays for simple units. I think that the sequence units are cases rare enough that it would be a hassle to have to deal with arrays for conversions which don't include sequence units. That is a weak preference. + +JMN: Yep. Okay. Thank you. As for the first question about using math FMA, I guess if I understand your suggestion correctly, there would be just one application of FMA to convert to the base unit and then the rest is downstream number. + +WH: Yes. For sequence units, yes. And for compound units, you would cross-multiply the rationals you get from CLDR for all the parts of a compound unit and feed that into the FMA. + +JMN: Okay. Yep. That sounds like a nice hybrid approach. Maybe a bit similar to what we're doing right now with simple units where we do give ourselves the luxury of having mathematical values in the spec. Coming from CLDR. But then computations are done in number space downstream of that. + +CDA: All right. We are past time. We have a large queue. I will copy the queue, and we can do a continuation if we have time later in the meeting. + +JMN: Okay. Thank you. + +### Speaker's Summary of Key Points + +* We presented API updates, focusing mainly on the use of sequence units and consequences for supporting them. + +### Conclusion + +* We will continue to discuss whether to use arrays by default, and how such a property should be called, in the TC39 Numerics champions call. +* We will continue to discuss what to do about the issue of reduced precision of computed results thanks to accepting sequence units as well as normalization. + +## Pulling in AbortController for Stage 1 or something + +Presenter: Kevin Gibbons (KG) + +* [proposal](https://github.com/bakkot/structured-concurrency-for-js) +* [slides](https://docs.google.com/presentation/d/1iRpJ3ADc50ZRUsmwYi9Yp3qjixBq3wMWWx_jw7cFleU/edit?usp=sharing) + +KG: Okay. Hello everyone. I would like to talk to you about pulling in AbortController. I've talked about this briefly in the past, but I want to lay out a more concrete path and talk about how we might actually go about doing this. I've linked the repository for the structured concurrency work that was the occasion for my last presentation on this topic, although that repository is exploring much further in this direction or sort of in a direction that I would like to go, than this talk today, which is only about a core part of it. Okay. + +KG: A reminder of what I'm talking about. AbortController is a thing in the web platform and on many runtimes that is used to cancel work. It's threading the capability to be canceled to asynchronous work, such that the work can then be signaled to be canceled by the controller at a later time. So this \[slide] is sort of the representative use case. You construct in a AbortController, and then when you're doing some work, for example, a fetch, you pass it the signal, which comes along with the AbortController, and the person who created the controller can at any time before or while the work is executing, they can call `controller.abort()`, which will mark the signal as aborted, and if fetch is currently doing something, doing network operations or whatever, those will be canceled when the signal is aborted. And it will throw an abort error, which is not its own error type. It is a DOMException whose `.name` property is AbortError, but we'll talk about that more in a little while. There's a bunch of APIs which deal with these things. This is just a sort of representative sample from the web platform and from Node. But basically, any time you're doing async work, you can very reasonably take an AbortSignal. Also if you are doing some operation which you might later want to undo or uncommit to, with this example with AddEventListener. AddEventListener isn't doing any work. It's just registering something which you might later want to unregister. And you can just as well use an AbortSignal for those cases to say, "I've signed up to be notified of events. I no longer wish to be notified of events." So the main thing I want to establish here is just that this is widespread on the web and on many JS runtimes. Also, the W3C requires using AbortSignal for any asynchronous operations. So certainly on the web it is going to be common and while, of course, the W3C guidelines don't bind us, when we are trying to create a coherent language and many of our users will be using the language in the context of the web or Node.js or similar JavaScript runtimes, I think it behooves us to at least look at the guidelines and try to stick to them when we can. Oh, Mark had a topic. Do you want to get to that before we move on? + +MM: No, we can. So you said uncommit, which sounded very scary, but then the example was an unregister, which sounds not scary at all. + +KG: Right. + +MM: Is there some— + +KG: I should have said unregister. + +MM: Okay. Fine. Good. Thanks. + +KG: Yes. I apologize. Okay. So these are examples of native APIs that consume an AbortSignal, but also user code can consume an AbortSignal. There's a few different ways of doing that, and I think I've highlighted all or at least all of the important ones on this slide. So you can throw if the signal is already aborted, you can use this add event listener machinery which we'll talk about more later to sign up to have a function be invoked when the signal is aborted. You can check if the signal is aborted by reading the aborted property. And if the signal has been aborted, there is an error associated with that, which is in the `.reason` property, and you can read that property so that you can throw the appropriate error. But the main things that you would be doing are throwIfAborted, checking if it's aborted, and signing up to have a function be called when it is aborted and potentially un-signing up for that function. + +KG: Great. Okay. So my position, my thesis, is that consistency requires us to adopt AbortController. Many JavaScript programmers will already be familiar with it. I don't think it's reasonable to ask developers to learn some other cancellation primitive, given that this already exists and is widespread and is certainly not going away. And I think that we are going to want to add cancellable APIs. The link here goes to the concurrency control proposal, which needs cancellation for its own reasons. Although I did also just add this aside here, which is that the `Atomics.waitAsync`, which is already part of the language, is logically a cancellable operation. It takes a timeout, so you can give up on waiting for your atomics operation while waiting for your read to happen. But I think it is reasonable to be able to say, "I no longer care about this," and stop listening to it. And right now, there's no mechanism for that because that would be cancellation, and we don't have cancellation in the language. So I think we are going to inevitably need to have a mechanism for cancellation in the language and I don't think it's reasonable for it to be anything other than AbortController. Therefore, I think we need to be able to use AbortController from our specification. However, it's in WHATWG, and it has a bunch of assumptions baked in with it being in WHATWG. Things like the event target machinery. Which I don't think we could reasonably try to specify all of that, and I don't think we could reasonably normatively reference because we don't actually need almost all of the things that it does. It's just sort of incidentally how it works on the web platform. + +KG: So what can we do? I think the approach that we ought to take is to identify a partial subset of AbortController, probably a fairly large subset of AbortController, that provides the functionality that we need and define host hooks for the parts that we don't want to define. So I mentioned, for example, the abort error is not its own type. It is a DOMException. I don't think we should be trying to specify DOMException in JavaScript, but I also don't think we should be asking the web platform to change the type of error that is thrown. And the way that we would accomplish this, then, is to have a host hook that says, "Construct a new error whose name is 'AbortError' in a host defined fashion," or whatever. And then on the web platform, that would be defined to be a DOMException. On a platform that doesn't have DOM exceptions, it could just be its own error type. We leave it up to hosts. So I think that with a couple of host hooks, we could do this in a way that doesn't actually require changes from anyone who has shipped AbortController. With one caveat, which we'll get to in a second. So my hope here is that, other than this caveat, this can be just something that happens sort of behind the scenes in the specification land and doesn't actually affect users, except eventually users of runtimes that don't currently have AbortController would be able to start using it. And of course, they would be affected insofar as we would be using it within our specification eventually. + +KG: So what's the subset I'm talking about? Well, we definitely need AbortController. We definitely need the signal property. We definitely need the ability to abort on AbortController. We also need the AbortSignals. They need the boolean to check if they're aborted. They need the reason. They need throwIf Aborted. They need some way to sign up to be notified when they are aborted. This does have to be synchronously, unfortunately, it really does. And AbortSignal in particular needs a host defined superclass because on the web that's event target, and I certainly don't want to pull event target into JavaScript. I think that's basically it. + +KG: There's a couple of other things that exist. There's `AbortSignal.any` which is basically like `Promise.any`, except with AbortSignals. Which it turns out to be not implementable in user land with the memory guarantees that you want. I can go into this in more detail at a later time, but basically, neither a weak nor strong reference to the signals that a signal is depending on is appropriate. You really need to be able to reach into the internals of AbortSignal. So we might need to pull in `AbortSignal.any`. `AbortSignal.timeout` is just a convenience thing, and you can implement it on or at least I believe you can implement it on any platform that provides a timeout mechanism. So there's some of these other things we might or might not need to pull in. Which are sort of less core. I think it might be confusing if we don't pull in literally all of AbortSignal if you're on a platform that doesn't currently provide it. On the other hand, there's platforms that don't provide setTimeout, and that's a decision those platforms are making. And I don't think we actually need to enforce anything about that. We can say, "Here's the subset that is part of JavaScript, and people who want to implement more can of course implement parts of other specifications." + +KG: So how do we actually go about doing this? This would be the first time we are pulling in something from the web platform. We've adopted TypedArrays, but those weren't really the web platform—well, they were the web platform, but they were the Khronos spec, which was its own slightly different thing than everything else. Also, it would be kind of weird that we would only be pulling in part of this specification. When we pulled in TypedArrays, we got all of TypedArrays. We didn't have these weird host hooks where we needed to have carve-outs for other specifications to do other things. Actually, that's quite not true, the detaching functionality was a carve-out for hosts to use, but anyway. Obviously, this would need to be coordinated with WHATWG. I've raised the topic on the WHATWG matrix channel, and people Anne at least seemed to think that this was a reasonable thing to do. Kind of an open question of where development would happen after this. Would WHATWG continue adding new things, new utilities like `AbortSignal.any`? Would we add new things? Open question. I think in practice, it would probably be both, which is a little bit awkward, but not the end of the world. I think anything that's more core, like `AbortSignal.any`, would probably make sense to do in JavaScript and things that are more platform capabilities like `AbortSignal.timeout` would probably happen in WHATWG. I know people here aren't always involved in the broader web platform stuff, but especially for browser representatives and anyone who works with people who participate in the rest of the web platform standards world, I would love to hear from those people. So if browsers are able—if the representatives from browsers are able to talk to your counterparts in the web platform parts of your organizations, confirm that this is reasonable and that they would be okay with some development moving over to TC39, that would be great. And then I want to get to the caveat. But before we do, let's go to the queue. + +CDA: RGN. + +KG: Let's see. Let's see. + +RGN: Yeah. So obviously, one of the concerns as soon as the idea was floated of pulling in AbortController is the problem with things like DOMException. A host hook for constructing errors is definitely ugly, but it seems like the right way to resolve that particular issue. I think it is appropriate, and I wanted to commend you for identifying it. + +KG: Thanks very much. + +CDA: MM. + +MM: Yeah. Yeah. So you mentioned a synchronous action, but it was not clear to me if the synchronous action is simply setting the aborted flag, which can be synchronously tested; I have no problem with that at all. If it's a synchronous callback— + +KG: It is. + +MM: Oh, okay. + +MM: Yeah. That might be a blocker, not certainly it's not a blocker for stage one. For stage one, I can already say I approve this. You're investigating this whole area, that is certainly worthy. I also agree with you about the nature of the terrible trade-off we face, which is that there is an abort API that is standard in much of the JavaScript world, i.e., in browsers. And to do a separate one and have them coexist and figuring out how they could even possibly compose seems like a nightmare for users. And I agree with the normal ranking of constituencies. So I suspect that the case for trying to do exactly what you're trying to do here is compelling. I don't see an alternative. But the synchronous callback, I'm wondering if something like the host hook could approach, could also be used to avoid providing a synchronous callback universally. I don't need a detailed answer on that now. + +MM: I was wondering, I'll just take my next question since it's next. Is for existing APIs that are just at the Promise level of distraction, like `Promise.all`, that effectively registers a then callback with all the things being all, one can imagine adding an options bag to it that if the option is signal, aborts the I mean, unregisters the continuation on those dependent Promises. Is that consistent with your view of how to spread the cancellation API, whatever that is, so that it's useful in more places? + +KG: Excellent question. So there's sort of two things there. I do think that something like that would be appropriate, but I actually think that the place that we would want to put it is on Promise prototype then. I think the missing thing here is some way to say, "I no longer care about the result of this Promise." We don't have that. And I think we should. + +MM: Okay. But if you do it so I agree with you about then. If you do it on then, then you also need to do it about all because it's all that does the then registration. + +KG: Sort of, actually. So all is this interesting case because if one of the Promises errors, then you no longer care about all of the other ones. + +MM: Oh, that's true too. + +KG: For `Promise.all` specifically, you actually kind of want the ability to unregister even if the consumer of `Promise.all` didn't pass a signal. But that said, you do also kind of want to be able to forward it. There is this question of, what APIs should pass a signal to their callees? And my instinct is that you probably don't want to do forwarding. You mostly want to say the only things which are doing work themselves should be taking a signal. But `Promise.all` kind of is doing this work itself because of this case where it can get an exception from one and stop listening to the other. Anyway, this is a much deeper topic. The broader answer to your question is yes, I do think that that is the direction we should go. + +MM: Okay. Yeah. And I don't think any more depth on that now. And I'll just go ahead and say I approve of this for stage one. + +KG: Great. Thanks very much. If we have more time at the end of the time box, I'll come back and talk about the synchronous question. But let's keep going through the queue and the rest of the presentation first. + +CDA: Okay. And we have a few minutes. ACE? + +ACE: Yeah. Also, big plus one to everything you're doing here. I'm wondering if you have thoughts about how we would encourage detection. It's very I think it's very common. If you end up with a Promise chain that rejects with an abort error, it's common to handle that separately from other types of errors. So we already have error, obviously an instanceof check is not particularly safe. Yeah. + +KG: An `instanceof` check straight up does not work. + +ACE: Right. + +KG: The only thing they are is DOMException. I think it would have to be the `.name`. + +ACE: We wouldn't want to say there should be an is abort error built in? We would just… + +KG: I don't see a reason to. + +ACE: Okay. + +KG: Yeah. + +CDA: I think I'm next on the queue. I have vague hand wavy concerns about interop. Specifically, how working with AbortController and AbortSignal in strictly in web context and versus the language level. These are obviously not stage one concerns. And I don't have a lot of time in the time box. But I'm sure we can dig into that more later. + +KG: All right. I would love to hear more. But if you want to open an issue or just on matrix or something. Because my intention was that this basically doesn't change anything for anyone. So I was hoping that it was therefore compatible. + +CDA: Yeah. RGN and I were talking about it in the OpenJS standards working group meeting the other week. I'm trying to recall some of the points that we were thinking about. But yeah, I will follow up. RBN. + +KG: Okay. + +RBN: I will say that I do see that this is very or at least somewhat addressed in the slides. So perhaps I can wait until you get to that point. But I do want to point out that there is an existing cancellation proposal. I won't go into too much depth into the history of that proposal. I haven't had the time or inclination to work on it in quite a while due to issues trying to find a path forward for it with WHATWG over the years. But the basic premise was to have something of this nature. So I do think it's valuable to approach this to look at advancing this should it come up in the slides or otherwise. If you were interested in taking over as the champion for the cancellation proposal to bring it up to match this, that would be acceptable to me as well. But I'm sure we can talk more about that offline. + +KG: Great. Yeah. I think that probably this would not be able to go forward together with a separate cancellation proposal. So I think it would make sense to regard this as just a narrowing of focus of the existing cancellation proposal. + +RBN: Yeah. And I would agree with that. I've been fairly critical in the past about the API design for AbortController. I do appreciate that you've made some headway into rectifying that over the years. And they've also made some progress on that API. There are things that I would like to eventually see in AbortController in the standard that still aren't present within the DOM API specification. But all those things could happen later, which is fine with me. + +CDA: Okay. All right. We have only a couple of minutes left in the time box. It is important that we finish on time. So everyone in the queue, please be extremely brief. Mark. Oh, Mark has removed his reply. All right. CHU. Oh, CHU is plus one for stage one. "Makes sense having the same abort building block in language plus web from dev view". And JHD says "the web has many things that should have never been anywhere but TC39. And we should pull all of them in eventually." KM. + +KG: Certainly not committing to anything other than this one. + +KM: I have a +1 from us. So I think I can speak for JSC and I can't speak necessarily for the rest of our web platform people I haven't spoken to about it. But they're probably on board with it, I would assume. But I think for stage one is fine. + +CDA: Okay. Leah says enthusiastic plus one for stage one. And plus one to Jordan's comment. Ron is plus one stage one or repurpose cancellation proposal. JRL is plus one. SFC is plus one. + +KG: I will briefly interrupt and say I asked for this proposal for stage one, but I do agree with Ron that I think that probably we should just regard this as a continuation of the existing cancellation proposal. And so it sounds like everyone's on board with this going forward and agrees that this is the way we would like to proceed with cancellation. So just as a process thing, I think what I would like to do is proceed with this as the cancellation proposal since RBN has graciously agreed to have me take over championing it. + +CDA: Yeah. I agree with you. Mark. + +MM: Yeah. Since both Kevin and Ron are here right now discussing this, what. A salient difference between what we just saw from Kevin and Ron's cancellation proposal? + +KG: So the really big thing is the caveat that I didn't get to, which is why I don't think we can actually pull in AbortController as is, because of this issue about how you register a thing to get a callback invoked. And this was I think the biggest thing that made the biggest difference originally with the cancellation proposal, is that it had a mechanism that was good, instead of the one that AbortController currently has, which is bad. And so my proposal is basically we add the good thing that we need to AbortController, at which point—there are still some differences if Ron wants to talk to them, but I think the most important one would basically be addressed. + +MM: Does this enable JavaScript to avoid the synchronous callback? + +KG: No. + +CDA: All right. We are past time. I'm afraid to ask, but are there any objections to stage one? + +CDA: Okay. Yeah. So the folks who were participating in the conversation, please take a look at the notes and make sure that the attributions are accurate. Are there any objections to stage one? 3, 2, 1. Okay. You have stage one. + +KG: Great. Thanks very much. Mark, I will open an issue on the existing cancellation proposal that talks about why we need the synchronous callback. And I will @ you on GitHub. + +CDA: Good. Thank you. + +### Speaker's Summary of Key Points + +* AbortController is a thing in the web platform and elsewhere, we should pull it into the core language so we can use it, with host hooks to avoid requiring changes. +* RBN agrees this should take the place of the existing cancellation proposal + +### Conclusion + +* AbortController will advance to Stage 1, as a narrowing of focus of the existing cancellation proposal, which KG will champion + +## BigInt from exponential for Stage 2 + +Presenter: Richard Gibson (RGN) + +* [repo](https://github.com/tc39/proposal-bigint-from-exponential) +* [slides](https://docs.google.com/presentation/d/1iHNosyAVvh7Ir8KqGgZ_BTfthEo0W51NcLDVeEHwoYM/edit?usp=sharing) + +CDA: RGN. + +RGN: Thanks very much. I'm going to talk today about BigInt from exponential notation. A recap: this is currently at stage one with the problem statement that exponential notation is useful for dealing with big integers but unavailable for direct use in defining an instance of the BigInt type. Manual conversion is cumbersome and tedious. You can use the BigInt constructor where the number is less than or equal to `Number.MAX_SAFE_INTEGER + 1`. But other than that, in the general case, you have to break things down with a not particularly comprehensible regular expression or some similar approach. This comes up with numeric canonicalization as has been proposed at various points in Amount. Also for parsing JSON source text, because JSON supports exponential notation for any numeric value, integer or otherwise. Also for dealing with financial values, it is particularly commonplace in cryptocurrencies, which have very small atomic units and therefore deal with very large integers. And in working with high-resolution dates and times, there was a need for this observed in the Temporal polyfill and I found a few different libraries that also have similar functionality. A search on GitHub for BigInt then open parenthesis then something other than close parenthesis then digit E digit (`/BigInt[(][^)a-z]*[0-9]e[0-9]/`) gives about 20,000 hits—some of them appearing in the links above, some of them not. We've also got in our own ecosystem a handful of libraries that support exponential notation for producing big integer values, again demonstrating that the need does exist. And actually, not just for big integers, but also for arbitrary precision decimals. Which I bring up, but I'm not pursuing as part of this proposal. + +RGN: In the last meeting, we discussed static versus dynamic use cases. Dynamic ones, such as invocation of the BigInt constructor as a function, are more general but also something of an anti-pattern in the sense that it's requiring dynamic execution for what is statically known at the time of writing. So in contemplating that and in consuming the discussion from last time, we've included in the proposal literal syntax so that you can write out things like 1e6n without involving the BigInt constructor at all. And you still get the expected results. + +RGN: A few questions that are still open, that I would like feedback on in this meeting from anyone who's willing to provide it. First off, what to do about negative exponents? So if you have as shown here, 1230e-1, that represents the integer 123. And if you want to specify the BigInt 123 in literal notation similarly as 1230e-1n, should that be supported? The current specification text allows it, but it seems visually misleading, if nothing else. At least to my eyes, that looks like a subtraction rather than a literal. The value of it is questionable. None of the identified use cases call for this. And we've already had one delegate in the previous meeting raise it as a particular concern. So I'm inclined to drop support for it. + +RGN: The other issue that's still open is about changing the IsLooselyEqual and IsLessThan operations. So right now, you could write something like a million as a BigInt (`1_000_000n`) and double equals or less than equals, etc. to the string “1e6”. Right now, because that string does not parse successfully as a big integer, you end up in string comparison. But the current specification text of this proposal would change that so that it's interpreted as a BigInt and we actually end up with all of these example comparisons being true. That is technically backwards incompatible, I suspect it's not going to break any code. I don't remember ever having seen anything like this in the wild. If it turns out not to be web compatible, we can do a carve-out to preserve the existing behaviour for this, despite accepting exponential notation strings for all other places where a string can be coerced into a BigInt. That's not my preference. I think it would be a little bit surprising. If we can update the operator behaviour, I would like to do it. But again, that will remain to be seen. + +RGN: So with that, I'm formally asking for stage two, sharing the entrance criteria briefly. We need a proposal document to describe the high-level APIs and syntax, we need illustrative examples of usage, and we need some spec text… all of which we have. Should this reach stage two, obviously, we need to identify reviewers. And with that, I'm ready for the queue. + +CDA: Okay. I'm just going to interject real quickly. Thank you for putting this slide up. I think all stage advancement presentations need this slide and also thank you for remembering that we need to ask for reviewers because we serially forget to do that. Jordan, says anything that results in a valid BigInt number should be supported. MM is on the queue. + +MM: Yeah. So the example with the comparisons of the less than and the loose equal, what is the current behaviour on the for those expressions? + +RGN: Current behaviour is that the BigInt is converted to a string as part of evaluation. + +MM: I see. I see. So then it becomes a string comparison. + +RGN: Right. And if we go ahead with this, then instead the string is converted to a BigInt and we do BigInt comparison. + +MM: I see. I see. Okay. Thank you. + +CDA: MF. + +MF: I gave similar feedback during the stage one presentation. I just don't see any—convincing, at least—reason to support a non-integral significand or a negative exponent. The problem, as I understand it, that we're trying to solve here is that you want to be able to conveniently write large bigints. I think it's a very minor problem, but it was enough to convince me that, okay, we can go to stage one to look into that space. I don't think that all this additional stuff, especially changing how the less-than-or-equal-to operator works and stuff, is at all necessary to cover that scope. I think that's well beyond what I would think is necessary. + +RGN: Okay. Responding to the non-integer significand part, that's actually necessary to support the first use case here. When you canonicalize arbitrary integers into standard form, it is very convenient. If you have a single-digit left-hand side followed by the fractional precision, so 1.234000e7, for instance, and although when a human is writing the input, they probably won't be thinking in those terms, when we're producing output that ought to be able to round trip, it really is important to be able to consume them. + +MF: Okay. I guess I'm not understanding that first use case enough. And I'd like to understand more about that. + +RGN: Okay. Yeah. So generally speaking, the purpose of it in the context of Amount is to have something that is basically as simple as possible to parse. That everything is going to have this standard format. Which is, in Amount is not necessarily an integer, although for something that's a BigInt, it is actually an integer. It also is manifest in JSON canonicalization as well, not strictly speaking, just this, where it is the form that allows for trivial consumption, trivial comparison, and doesn't suffer from blow-up. So if you insist that the integers are represented always as whole numbers, then I can provide an input of something like, 1e1000, and or 1.2e1000. You definitely don't want to go out to the full expansion because then that's a denial of service hazard. And if you instead went, 12e999, then you've made the parsing and the comparison, if you need to do it, more difficult. And just generally speaking, the simplest form that it can count on having only and exactly one digit to the left of the decimal point is a very useful property. + +MF: For? + +RGN: For consumption, for comparison, for protecting yourself against that kind of exponential blow-up of space as well. + +MF: Okay. I'm still—I'm going to think about it for a little bit, but you can continue on with the queue. + +RGN: Okay. You also raised another point, which I'm sorry I forget what it was. + +MF: Sorry. Yeah. I think it is possibly an ambitious portion of your proposal here, but the changing of the comparison operators. + +RGN: Right. Yeah. So basically, this kind of falls out unless we do something about it, where what is being changed here is that anywhere that you can currently specify a string in place of a BigInt, that it goes through this StringToBigInt internal operation. That is also true inside of IsLessThan and IsLooselyEqual. So I don't feel particularly strongly. If we were to say, for instance, that when you're doing a DataView setBigInt64, that it applies, but when you're doing a double equals, that it doesn't apply, I think it's probably slightly confusing. But again, I don't think people actually write this code, so I don't feel strongly about it either. + +MF: Yeah. I was going to—okay, so I think this goes back to the point I raised in the previous presentation then that this really feels like a parsing function, rather than a BigInt constructing function. Especially when you say things like that, right? I think those are possibly two different APIs. And maybe we should explore that space of separating them. + +RGN: I mean, they could be. And that's how this started out. But as soon as you bring in literals, then it changes the game. And bringing in literals actually will be better in terms of how things operate. I think it's a valid concern to identify `BigInt($stringLiteral)` and `BigInt($numberLiteral)` and `BigInt(Number($stringLiteral))` as anti-patterns. People are doing it right now, and if they can instead just write the bigint literals, then I think the ecosystem is probably better off. And if we're covering literals, then it just doesn't make much sense to exclude where this started with StringToBigInt. + +CDA: Quick point of order. I just want to test to make sure that the transcription is continuing. And it is. Okay. We're trying to identify the people on dialed in remotely are hearing some sort of clicking. Please, remote participants, make sure you are muted when you're not talking. We don't know if it's you and if we haven't identified the cause, but hopefully we can nail it down. + +RGN: Looks like WH is up next. + +WH: My position is that negative exponents should be allowed. This should accept anything in exponential notation which produces an integer. You might get those as inputs. If you disallow them, you'll get some surprises if you try to use == on them. + +RGN: Would you include that for the literal form as well, what we're looking at here on the top line? + +WH: Yes. It's just simpler to have the same syntax for anything in exponential notation throughout the language. + +CDA: MM? + +MM: Could you go back to your use cases slide? Yes, that one. Second bullet, I just have no idea what you're trying to say there. + +RGN: The JSON grammar for numbers includes exponential notation. + +MM: Yes. + +RGN: And when you are parsing JSON with source text access, for instance because you know that a particular value ought to be represented as a BigInt, then if it comes in this form, it would be better to use the BigInt function rather than converting it yourself. + +MM: My apologies. I had a reading typo. In my head, I saw with and heard it as without. + +RGN: All right. The queue is currently empty. I did want to point out that in my mind, these open questions ought not block the proposal from stage advancement. In stage two, these are the kinds of questions that I would hope to resolve with implementer feedback. And with reviewer feedback as well for that matter. There might be other reasons to object, but these questions as far as I can tell would be appropriate as stage two concerns. So I'm interested in support for advancement. I'm also interested in reasons not to advance. + +CDA: MM, supports stage two. + +CDA: MF. Typing furiously. + +MF: I mean, and this has nothing to do with my opinion on this proposal, but I do kind of feel that both of these are stage two concerns. I think that they're fairly major design forks here. Whether we are considering changes to comparison operators is really significant, I think, to me. I'm having—can you make an argument why you think that they are not significant? + +RGN: Yeah, because resolution in one direction or another I think is still valid under the scope of this proposal. The major semantics really are being able to use exponential notation to define a BigInt. And if there are some places where for compatibility reasons, that doesn't work out, the proposal can be adjusted to exclude them. Again, I don't think anyone's actually writing that code. I think the major semantics are the BigInt constructor handling an exponential notation string, and also in light of the recent changes, expanding BigInt literal syntax for cases that we expect. Any tweaks that come up as a result of this, I think are just part of normal proposal development. They're not changing major semantics. They're just shifting a boundary. + +CDA: Can you reply from PFC? + +PFC: Yeah. I think there is precedent for solving questions like this in stage two. I think we did it in Temporal, figuring out what should the comparison operators do when you have a Temporal operator or Temporal object on one side of the operator and stage two was when we worked out the value of throws mechanism. And I think that's fine for this proposal as well. It's part of the scope and the API design. So I mean, that works for me. + +CDA: All right. On the queue, we have support from PFC, WH, YSZ. Jordan. And Peter. And PFC is entering the queue again. With support. SFC. I have no way of knowing if it's going to be an end-of-message thing. Yes, it is. Plus one. SFC says plus one. Stage two means we want it. Questions are okay. I assume he means open questions. MF is next. + +MF: Okay. It sounds like this has a lot of support. And I don't want to be the only person in the way here. I just do want to call out that we've seen that we are a first mover here. There are no other languages that do this. This is not a small decision. I know that going from stage 2 to 2.7 is really the big jump. That's where we really nailed things down. And that often is most of the work of doing these proposals. But I feel like we are pretty much setting the course here and it's a completely uncharted course. And maybe others have thought more deeply about it than I have and have gotten more comfortable with it. But I still feel like this is kind of really still up in the air. But if I'm the only one that feels like that, if others do have more conviction in the positive direction than I do in the uneasy direction, then I'm okay with it going forward. + +RGN: Maybe ironically, I actually do share that position in large part. This is a simple change, but a significant one. And a novel one as far as I can tell. So I don't want to take it lightly. That is specifically the reason why I'm here asking for stage 2 and not 2.7, because I don't think that we are currently in a position to have definitive answers to those narrow questions for it. And I do expect that there's going to be possibly quite a bit of back and forth in stage two while we figure things out. Maybe someone discovers that, in fact, there is precedent in a more obscure language. Again, looking at the literals in particular, WH wants `10e-1n` to be valid. My inclination, as I said, is to be more conservative. We can always introduce it over time, but we can't back it out. So I do think that, yes, there's a lot of significance here. And I'd like to explore that in stage two. I haven't even contemplated writing tests for this yet because of this kind of concern. Many will be simple, but these edge cases really do matter. + +CDA: OFR. + +OFR: Okay. Just since I just want to voice support for that opinion. I think because we only heard the plus ones so far. Yeah, for example, one thing that we were not convinced by is the use cases that we've seen so far. It's not entirely clear that they're that important. It's not a blocking concern, but some concerns might become blocking from us, for example. We certainly would not want truncation. I'm not sure how we would feel about the minus one and things like that. Especially if any kind of parse-up parse complexity blows up if it turns out to be really complicated to parse and to get the right answer. Yeah. So I want to support this statement. + +CDA: All right. That is it for the queue. So lots of support for stage two, but do we have does the descent amount to objecting to stage two advancement? That is not clear to me. I hate to put people on the spot, but we kind of have to decide. + +MF: Are you asking for me to give consent? + +CDA: I'm kind of looking at you and OFR. + +OFR: As I said, not currently, but I wanted to put it on the record that there is concern here, and it's not just like everybody loves it. + +MF: Okay. And as I said, from what it seems like, it seems like people are—there's a lot of positive support, and some of that support is strongly positive. And in that case, maybe I am fine with it going forward. I'm not going to oppose advancement to stage 2. + +CDA: Okay. So it sounds like you have stage two. Are there any objections? To stage two. Just triple-checking. + +RGN: I do need reviewers. + +CDA: Yes. All right. Congrats. We'll do this in two steps. Congratulations. You have stage two with some dissent. + +(applause in room) + +CDA: And who would like to volunteer as a reviewer? + +(MF raises hand) + +CDA: MF? Fantastic. I feel like it has to be OFR. + +(RBR raises hand) + +CDA: RBR? All right. Thank you. All right. + +### Speaker's Summary of Key Points + +* There are significant concerns from MF and OFR. +* Questions about negative exponents, non-integer significands, and operator behaviour remain open. + +### Conclusion + +* The “BigInt from exponential” proposal is at Stage 2, with reviewers MF and RBR. + +## Continuation: `JSON.parse` Options for Stage 2.7 + +Presenter: Peter Klecha (PKA) + +* [proposal](https://github.com/tc39/proposal-json-parseimmutable) +* [slides](https://docs.google.com/presentation/d/1xNMjd3p8wo4NqtuBCOu-We_lFWX0SWI36721xmjlSHQ) + +CDA: So we have about 30 minutes left. … PKA, JSON parse options continuation? + +PKA: Sure. + +CDA: Was there a queue for that? Let me check. No. PKA. + +PKA: Yes, sorry. It's going to take me a second to bring the slides up, but we now have editorial approval for `JSON.parse` Options. Sorry about not getting our ducks in a row before we came yesterday. So the question was, can we have a consensus for stage 2.7? + +CDA: Yep. So again, yesterday, we could not advance because we did not have editor sign-off or we weren't sure if we had editor sign-off. We do have editor sign-off. So do we have support for 2.7 for JSON parse options? You have a plus one from JHD. MM also supports. LVU supports. RBR supports. Do we have any objections to advancing to stage 2.7? All right. Congratulations. + +PKA: Thank you. + +ACE: Yeah. I'm wondering if, people having had a night to sleep on it, if anyone has had inspiration for the options bag name, because there was not a huge amount of love understandably for `preferNullPrototype`. So maybe with a night of Japanese food and sleep, have any ideas emerged? I would love to hear them because I agree it's not a great name, but I do think it's the best I've heard so far. + +JHD: I mean, in the absence of a better idea, I think just `nullPrototype` would be fine. It's the word “prefer” that I think is the issue because that suggests that it's not a certainty. + +PKA: The question is, how do you signal—unless you think it really doesn't need to be signaled—that it's just for the plain objects and not for the Arrays? + +CDA: MM? + +MM: So just popped into mind just now, `bareObject`. I'm not actually quite suggesting it. Because “bare” is a strange thing to introduce. But if `[some short adjective]object`, works like `bareObject`, that sounds better by being an adjective on “object”, it more clearly doesn't more clearly does not apply to arrays even though technically arrays are objects. + +CDA: LVU is on the queue with “`ObjectPrototype: null`? Could even later be expanded”. RKG is entering the queue. + +PKA: Oh, I like that. + +ACE: I thought a similar thing, LVU. Because I thought that it's kind of a it gives you a lot of expressive ability. Like if you know you’re parsing something where actually the objects should be hydrated with a custom prototype. The only thing I didn't like about it is that it doesn't map as cleanly to import attributes. There where we can't have a dynamic expression. Like we could special case like the null literal to say that just that is supported. But you wouldn't be able to reference any of that's the only thing I don't like about that idea. Otherwise, I actually think it's great. + +PKA: It expands the scope of the proposal that you could do interesting prototypes and not just null. We could maybe only permit null for now and then leave it as a follow-on to think about other prototypes. + +LVU: That's the idea. + +CDA: There's a reply from MM. + +MM: Just what was just said, I support that. I support `ObjectPrototype: null` over `bareObject`. Permitting only null for now. Perhaps permitting only null forever. + +CDA: RKG? + +RKG: I don't have any objection to what was just said, but if we were concerned with not liking “prefer” to the point that we were suggesting just `nullPrototype`, we could consider `nullPrototypeObjects`. Just kind of saying the obvious thing out loud; might have its own imperfections. + +KM: I don't know if this was discussed before. And maybe it has and we've decided to reject it for other reasons. Also, a little late in where we are, but have we considered letting users provide the prototypes specifically as a parameter for objects and arrays individually and then all the ones that are created get that prototype and null is perfectly valid value and they can just have whatever they want? + +PKA: Right. I think that's what LVU’s suggestion I mean, that was just for objects. I guess we could think about it also for arrays. I’ll think about that. + +LVU: (indecipherable) + +JHD: That does have the same problem that it doesn't work with import attributes. So it's fine if it only allows null or undefined slash nothing, but that's not fine for custom objects. + +CDA: Chip. + +CM: Yeah. I'm not fond of object prototype null just because it carries the implied promise that you could put something else there besides null, even if you don't support it initially. And that opens up a whole can of worms and it feels like feature creep to me. If the intention was just to nail down, yeah, we want the prototype to be null, then I suggested yesterday `nullObjectPrototype` instead of “prefer”, and you pointed out correctly to that in fact, that didn't quite apply to array. But all of these other suggestions are also glossing over the fact that it doesn't apply to array. And if we're going to gloss over that one, we just go with the straightforward simple… + +PKA: Something about Object prototype makes it clear to me that it's talking about because the prototype for arrays is called array—I don't know. Yes. Yes, you're right. Arrays are objects. And so `ObjectPrototype: null` has the same problem as `nullObjectPrototype`. + +CM: Yeah. And if you're as I say, if you're going to just accept that, yeah, we know arrays are technically object, but what we're really talking about here is object objects. Then I think not being pedantic admittedly a simplification, but I think it's a pragmatic simplification. + +CDA: KM. + +KM: Maybe I just missed what happened here because I was attempting to get back into the queue and then had problems with my computer. But yeah, is the import attributes problem still a problem if it only accepts the literal null? + +PKA: It's only a problem if you think that the import assertion should behave exactly the same as the dynamic API. + +KM: Okay. Is that a concern of this committee? + +PKA: It's certainly not a concern from Bloomberg. Our interest is in the null thing. + +KM: Do you it is? That it has to be functionally identical. + +JHD: It's not necessarily that it has to be functionally identical. It's that it's a weird inconsistency if it can't be. + +KM: I mean, how would you even—how would it even make sense? + +JHD: No, that's what I mean. It wouldn't. But then you can use it to the extent that it makes sense but you can't use it beyond the point that it makes sense. But like if you typed your import attribute and you put something that in code would reference an object like `Array.prototype` or something, and then you get a SyntaxError. That's just weird and confusing, I think. And that doesn't come into play if it's a boolean. + +CDA: So we have a point of order. Please use the queue. RBR. + +RBR: I do like and just the simplicity of prototype colon null. Because it's also aligning very well with freeze very similar. However, from ship, I also see that point with the API like seemingly supporting many more while it's not. Now, if we would go that path, I would definitely strongly recommend to prohibit any other value to throw an error because even then it's confusing a prompt. Is that important in the future when we don't write code anymore? I don't know. But it's definitely something that would hit people initially, but as soon as they have been hit once, it's probably not important anymore and it's more about like, okay, you're only allowed to use that one value, right? + +CDA: RGN. + +RGN: Having had a night of Japanese food and sleep, I think “objectPrototype” as the name or as part of the name really does accurately communicate behaviour. Yes, arrays are objects, but also arrays have their own prototype. And “objectPrototype” exists in contrast with a hypothetical “arrayPrototype” option. So in that context, it really does clarify it, I think. And that has me agreeing with CM as well; object prototype is the right level of specificity. + +CDA: LVU. Just sorry, real quick. We only have a couple of minutes left, so try to be brief. + +LVU: I wanted to reply to CM. I do agree that object prototype null does imply that it supports mode cases. So you do have a small hit in ergonomics right now. That's the trade-off in these cases where you implement a partial syntax first. That can later be extended. The idea is you end up with a more coherent design if you need to extend it later. At a small cost right now. So the question is usually how likely is that extension in the future. Given the response, in the room, it seems to me that the use cases for hydration using custom classes are likely. It seems that they're prominent. So I think in this case, the trade-off is worth it, but your mileage may vary. And I do agree with the point that many people made around arrays being objects is not something that is likely to confuse actual users, even though it is technically correct. + +CDA: ACE. + +ACE: Yeah. I personally am kind of excited by your idea LVU in the future, maybe allowing it. Though in my arrogance, I feel like a lot of people won't use it correctly—grabbing a prototype and adding it onto an object parsed is only going to work for classes that don't use any kind of private fields or anything but a very simple constructor. It's so it's I think it would be like a power user feature and so my feeling is actually the likelihood of us ever agreeing on adding that and feeling that it could be used well versus just saying to people, no, in that case, you need to use a ride either because you're using a prototype which implies you're using some sort of class which implies you really should be going by the constructor for the instances. Makes me feel like we leaving the door open is a door that will always remain open and doesn't pay the cost. Is my gut feeling overall. + +CDA: All right. There is a reply from JHD, but we are out of time. So I will quickly read the items in the queue. We might be able to do another continuation later, but we'll see. JHD says, plus one to ACE. LVU says, `JSON.parse` object somebody can copy that into the notes: + +LVU: (from queue) e.g. `JSON.parse(obj, { objectProtoype: Reactive })` /eom + +CDA: Object prototype reactive. JRL says, would also be happy with always being null prototype. MM says, Gemini says the primary term for a JavaScript object with a null prototype is a null prototype object. JHD says the term I've used and seen the most frequently is null object. RBR says, I also like the future use case possibilities. All right. For our next topic. + +PKA: So just to be clear, so we have stage 2.7 with what’s on the screen (namely: `preferNullPrototype` as the key name). If we want to make a change, we'll come back to committee for the change. + +### Speaker's Summary of Key Points + +* Editor signoff was received. +* Alternatives to `prefereNullPrototype` were discussed. + +### Conclusion + +* The “JSON.parse options” proposal advanced to Stage 2.7 with `preferNullPrototype`. +* Champions are likely to revisit that name; unofficial consensus in the room was achieved that we should not care about the “arrays are technically objects” issue when determining a name. + +## Continuation: Disallow Adding New Private Fields to Non-extensible Objects + +Presenter: Olivier Flückiger (OFR) + +* [proposal](https://github.com/tc39/proposal-nonextensible-applies-to-private), [PR](https://github.com/tc39/proposal-nonextensible-applies-to-private/pull/12) +* [slides]([https://docs.google.com/presentation/d/1AZYPsiU0LEwI-Hh4zRrW23DvwCMUF5wHjPS4pFh4j6E/edit?usp=sharing](https://docs.google.com/presentation/d/1AZYPsiU0LEwI-Hh4zRrW23DvwCMUF5wHjPS4pFh4j6E/edit?usp=sharing)) + +MM: I'm sorry, what's the topic? + +CDA: It is now on TCQ. + +MM: Okay, thank you. + +CDA: Give me one second to rehydrate the queue. + +MM: Okay. + +CDA: Unfortunately, MAH is on the queue, and I don't think Matthew is here. + +MM: I can represent MAH adequately enough for this. I believe. + +CDA: Okay. So the first one there is always extensible recreates the weak map virtualizability issue. + +MM: The OFR, you were going to you showed me a slide that you wanted to present in this topic came up again. Can you show that slide? + +OFR: Yeah, I'm trying to find them. One second. + +MM: Okay. Because the simple answer with regard to MAH's follow-ups here, let me take a moment. Yeah. For both of MAH's follow-ups, if we can agree on the slide that OFR is about to show, which basically suggests that the resolution be PR 12, then I think that takes care of Matthew's concerns as well as mine. + +CDA: All right. MAH was also the next topic, which is always or never extensible create a partial predicate for testing Proxy nature of an object. + +MM: Likewise. The if we agree on PR 12, that concern is settled. + +CDA: Okay. That's it for the queue. + +OFR: I tried to all right. Yeah, here's the slides. I tried to summarize what we did in the first session. So basically, well, we tried this unbiased temperature check, and it failed it seems like it's hard to rely on intuition here. Then we found out that excluding proxies from this proposal doesn't have consensus. And the reason was that if you treat proxies specially in this case, then they cannot faithfully emulate a normal object. And that would be unacceptable to some delegates. Because it would mean that you could use this property to test whether something is a Proxy or the normal object that it proxies. Then we also found out that probing only the target object with basically bypassing the Proxy does not have consensus. And again, here there is a very specific use case. Where basically the Proxy tries to stay basically tries to keep its target object in sync with some other object that is not accessible. So only the Proxy can mediate between the two. And so if we bypass the trap, then the target object and the object that the Proxy tries to emulate can get out of sync without the Proxy being able to intervene. So that also didn't have consensus. I also found out that basically calling the trap multiple times for each non-method property is okay for the implementers I talked to. And we also found out if we did this combo proposal that I put on the slides where we would sometimes ask the Proxy trap and sometimes go to the target object, sorry, that this would give us yet another way of differentiating between proxies and normal objects in a way. So it would again basically expose the Proxy. So given all these facts, it seems like the initial pull request 12 is essentially the only option that we are left with. So in summary, I would now propose to just go back to that pull request and have a decision on the pull request. + +CDA: WH is on the queue. + +WH: We've been discussing proxies quite a bit, but I'm interested in the other invariant, which is that you don't see partially constructed objects. Which of the options maintain that invariant? + +OFR: So combo tried to maintain that invariant a bit more than pull request 12. However, it's an invariant that is already not present at the moment. So wait, maybe I can let me share the original slides. So basically, already currently, you can observe partially constructed objects when it comes to fields. To non-methods. + +WH: How do you do that? + +OFR: (pulls up a slide entitled "BG: Installing private properties is not atomic") Like this? You just have an initializer that doesn't for example, throws or freezes the object or whatnot. + +WH: Okay. Let's see. This class fails partway through initialization. + +OFR: Essentially, yes. + +WH: I'm interested in the hostile scenario where the class is well-behaved, but can you make the class misbehave from the outside.? + +OFR: Right. This is the new hostile scenario where basically the Proxy blocks the construction midway. And on the one hand, it is opening up basically more ways of blocking the construction midway, but on the other hand, this can only happen if you do this return override thing. So it can only happen if basically your superclass returns you something which is a Proxy. + +WH: Okay. + +OFR: So in a way, it's opening up more ways to block construction, but on the other hand, it's only in the specific case where you're superclass is a Proxy. + +WH: Okay. So this cannot arise if the superclass is not a Proxy? + +OFR: No. As long as all your fields right-hand side expressions are pure. + +CDA: Okay. All right. That's it for the queue. So do we want to talk about PR 12? No, because ACE is entering the queue. + +ACE?: I'm faster. + +CDA: No need. Is that no need to speak? Okay. Right at the beginning. So I can, yeah. ACE says very supportive of PR 12. Do we have any other support for the changes in PR 12? I feel like there definitely was yesterday. If I'm not mistaken. YSZ. + +YSZ: Yeah. I talked to yesterday and I think that pretty much from the engine's implemented point, we are only stamping for private method once and for private field, we are stamping for each field right now in V8 and JavaScript at least. And in terms of implementations, efficacy, I think even if we remove these kind of steps of traps for field, we probably end up just allocating inferred properties size from the code and pretty much we can just make it efficient as is. So then I'm pretty much supportive to PR 12's change features keeping the current engine's efficacy and basically solving this problem. + +CDA: All right. RGN supports the PR as does DLM. And that is it for the queue. Do we have any objections? All right. Congratulations. Do we clap for this one? Maybe a small golf clap. Snaps. All right. We only have a couple of minutes left. So we will just break early for lunch. We'll see everyone back. Oh, + +MM: Chris, is there a resolution on moving the one that Matthew needs to be moved? + +CDA: That is going to be our first topic you're referring to thenable curtailment? + +MM: I'm referring to that one specifically. + +CDA: Yeah, that one is our first topic after lunch. + +MM: Well, Matthew, be able to make that? + +CDA: But that falls within his constraints. So hopefully. + +MM: Oh, it does fall within his constraints. Okay, great. + +CDA: Yeah, his constraint was that he can't be here for this session, these two hours that just are almost finished passing. + +MM: Okay. + +CDA: Yep. Okay. Just a quick thing about your badges. This is just for the people in the room. Please guard your Sony building badge with your life. I see some out on the table just scattered around. That's probably not a good idea. Maybe put it around your neck or keep it in your bag or otherwise belongings. There is a more eloquent comment about this in the Tokyo chat room. Please review that and let us not lose any additional badges. Also, it may jeopardize your ability to go on the tour of Sony HQ. All right. + +### Speaker's Summary of Key Points + +* Special-casing proxies is rejected. +* Any different handling between proxy and normal objects is rejected. + +### Conclusion + +* Consensus for PR12, only checking once for private methods + +## Thenable Curtailment for Stage 3 + +Presenter: Matthew Gaudet (MAG) + +* [proposal](https://github.com/tc39/proposal-thenable-curtailment) +* [slides](https://docs.google.com/presentation/d/1Gs5s56q0znHMX5mfup4PslGUrnM3_ngeaUqXy3STt2A/edit?usp=sharing) + +MAG: We're going to do thenable curtailment, and I'm attempting to get it to stage three today. To remind people, this is a new abstract operation safe Promise resolve. The basic thing is that it does is it will defer by one tick Promise resolution if and only-- + +MAG: So abstract operation defers by one tick if and only if the thing that you're going to resolve could run user code which boils down to the thing is an object that has something on its prototype chain which could be a Proxy, has a then property which is a getter. The spec text is available at the link there for detail-oriented people. Because I'm aware that I'm flubbing things as I'm saying it aloud. Since last we spoke, and I know it was only one meeting ago, we've had more thenable security bugs. In fact, as a result of one of these thenable security bugs, we've actually decided to deploy this as our chosen solution for trying to stop these bugs from happening in our streams implementation. So I supported our streams module owner in deciding this. But it was their decision. So we are going to be as Firefox evolves, I think it's not this next release, but it is the release that is currently in beta will have safe Promise resolve powering streams. So in the streams code, whenever it resolves a Promise, it will use the safe Promise resolve steps by itself. + +MAG: We have the test262 PR. It was written, reviewed, thank you very much to KG for reviewing. Especially reviewing in time for this meeting. I very much appreciate it, especially considering the review queue for test 262. Again, we do have a prototype in Firefox that people could turn on if they felt so inclined. This is the name of the preference in order to turn it on. I have been using this in my main browser since I landed it months ago. I have noticed zero bugs. Which is good. That's the hope. But we will, as we are headed into stage three, we might discover things. But I'm hoping not. At this point, I'd like to ask for consensus for stage three. And I'm wondering if MM has anything that he wanted to try to communicate for MAH because I was surprised by the scheduled request. + +MM: Well, if there are no changes in the proposal from what we saw last time, then no concern. The concern was that if there's an issue, whether it was in what you were coming to the committee with, which you're clearly not, or if something came up in discussion that caused things to change, I would need MAH’s opinion before I could approve it. + +MAG: No, no changes. We resolved everything last time that I need to change. But the spec itself is the same as last time. We discussed. + +MM: Okay. Excellent. We support. + +MAG: Okay. + +RPR: On the queue, you also have explicit support from MAH. + +MAG: Great. Glad to see you. You know what I mean. + +RPR: You also have strong support from KM. Plus one support from Chris. Can I just ask also, obviously, the tests? What's the status of test 262? + +MAG: The PR is approved, but not merged. I believe it's the status. + +RPR: Is there a reason it's not merged? + +KG: Not particularly. As far as I'm aware, I'm the only maintainer who's looked at it, and I just wanted to wait and see if other maintainers had anything to say about it. But I'll bring it up at our next call, and if no one else wants to review, we'll land it then. + +RPR: And CDA points out, please use the queue. ACE. + +ACE: I thought yesterday we asserted that tests being merged wasn't a condition for stage three. + +CDA: I didn't mean to imply that it was. I was just curious if they're approved, why weren't they merged? + +RPR: We've only heard support. Are there any objections to stage three? There are not. So congratulations, MAG. You have stage three. Thank you very much. I definitely oversized the time box. + +MM: Thank you for your flexibility on the schedule. + +MAG: You're welcome. I've got to go to bed after this. + +RPR: That is also the message from CDA. For you to go to bed. + +MAG: I'll put the summary in the notes, but then I will go by. + +### Speaker's Summary of Key Points + +* Security bugs continue to show the need, tests are written and approved, request for stage 3 + +### Conclusion + +* Thenable Curtailment acheived consensus to advance to Stage 3. + +## Private declarations for Stage 2 + +Presenter: Kevin Gibbons (KG) + +* [proposal](https://github.com/tc39/proposal-private-declarations) +* [slides](https://docs.google.com/presentation/d/1uM_nsM0eVc7G0_Pse2JsC5Xn1uBhgfRAgYYOlBY8v8s/) + +KG: Excellent. Okay. Private declarations. Same repository as last time. So before I get into this, I want to start with a disclaimer in the sense of—I wish to disclaim my previous presentation. I presented this at the last plenary with a different syntax and also I did not do a good job of motivating it and talking about what it was and wasn't doing. If you were present for that presentation, please put it entirely out of your mind and come to this with fresh eyes. Do not think about the things I talked about last time. Do not think about the syntax I showed last time. I was, well, A, I was presenting a syntax that I no longer stand behind, and B, I did not do a good job of putting this in context. I had been staring at it too much myself, and didn't present the correct context for the committee at all. So if you were here last time, please forget about everything I said. Just come to this fresh. Okay. + +KG: So where we are with private fields today is, we have private fields in classes. They're great. They have lots of properties that you want. They're unforgeable. They're actually private. They have a privacy model based on lexical scope. So it's a similar privacy model to how closures work. And it's statically analyzable. And minifiable. And they are not reified in any way. You can't introspect on them. Which is necessary for both performance and also keeping them private. Well, not strictly necessary, but useful to that end. So they are an existing thing in the language, a well-used part of the language. + +KG: But there's this oddity, which is that they are restricted to class syntax. The purpose of this proposal is to explore lifting that restriction. And that is the only purpose of this proposal. I explicitly do not want to talk about adding different kinds of private state or changing how private fields work on objects or adding new kinds of property descriptors or reifying private fields or exploring fancy new ways of using WeakMaps or any of that. If you want to do those things, you are welcome to do so. But the thing that I am interested in is taking the thing that we have and removing this weird syntactic restriction that we have for it. I don't think there's any reason that the private fields that we currently have need to be tied to classes. And I want to look into taking the private fields that we currently have and not making them be tied to classes. So that is what this proposal is about. + +KG: So what do I mean by "private fields are coupled with class syntax"? If we're not doing any of the things we were talking about on the last slide, what are we actually doing? What are we actually interested in? What restriction are we interested in lifting? So in a class body, if you have `#x = 1`, this does two things. It makes the name available in the lexical scope so that you can read it and write it and perform membership queries. And it also installs a field with that name on instances of the class. There's no way to introduce a name without also installing it on either the class itself for a static private field or instances of the class. And there's no syntax for creating something that is neither a class instance nor a class itself that has a private field. And so these restrictions are to me completely arbitrary. There's no reason to say that you can only introduce a name if you also are installing it in a class. And there is no reason to say only class instances get to use private fields. + +KG: So okay. What if we lift these restrictions. In particular, what if we add a way to declare a field outside of classes? I think the natural way to do this is with the `private` keyword, although there are other keywords that we could explore. But this is pretty natural. You have, in a similar way to declaring a variable with `const x`, you have to declare a private name with `private #x`. This can't take a value. You can't put an initializer after the X because it's just a name. And to actually use it, you have to put it on an object. So you could continue to put it in a class the way you can today. And in this case, I want you to imagine that the class body would now see that there is a name already in scope and use that rather than introducing a new one. So here you have a scope in which you can refer to the private name. That is not a class scope. But you can use it in nested scopes, including nested class scopes. And just like today, if you try to refer to the name outside of the scope in which the name was declared, it's an early SyntaxError. It's a parse error for the whole program. So I think this is a pretty obvious thing to do. + +KG: Another pretty obvious thing to do is to just let you put private fields in object literals. So you introduce a name in the scope. And then you are able to declare an object literal that has the field. + +KG: And that's it. That is the entire proposal. This is not a new kind of field. They continue to work exactly how they already work. The only differences are that now we have a new syntax for declaring fields in scopes that are not classes, which doesn't automatically install it on anything. And we have a new syntax for putting fields on objects. And in object literals. Not just on class instances. Everything else is exactly the same. In particular, there's no reification. There's no changes to the privacy model. There's no new way to add fields to an existing object as we have been talking about. You can stamp private fields on an existing object using the return override trick. This isn't adding any new way of doing that. And in fact, it would continue to be the case that the only way to add a field to an existing object is using class syntax and the return override trick. And it would continue to be the case that reading a field from an object that lacks it is an error. There is one difference, which is why there's an asterisk in the title of this slide. But we'll get to that in a second. + +KG: So why do we want this? Well, one reason is that some code simply doesn't want to use classes. For example, if your function is returning objects of different shapes, using classes is kind of weird because classes really only have one declarative shape. So you might want to return two different object literals. But you can't do this if you want to have a private field. There's lots of code in the world that for one reason or another simply doesn't want to use classes. But you still might reasonably want to have the things that private fields give you. + +KG: Another reason might be something that people in other languages are familiar with as friend classes. These are two classes where the classes have a close relationship such that it makes sense for one class to be able to introspect on another class's private state. For example, you might have a graph and nodes in the graph such that the graph class is able to connect two nodes. And this would entail modifying the private neighbors sets of each of those nodes. You can't easily write this code today. It's possible to do by nesting these classes and doing some horrible things. But the code that you have to write today for this is quite ugly. Sometimes the natural thing that you want is to just have two top-level classes that have access to each other's private state. And these really do need to be private if you want to maintain the invariants. So the thing you would like to do is to allow these classes to work with each other. + +KG: Similarly, you might want to have friend functions. So for example, just because you are vending class doesn't necessarily mean you want to vend all of the capabilities associated with that class. You might want to have some capability for working with instances of a class, which is separated from the class itself. And again, this is possible to accomplish today, using static blocks for example. But it's pretty ugly. And I think it is much more natural if you can just write the code such that a function outside of the class has access to its field by having a private field which is accessible to both the class and another function. + +KG: Also, you might want to have something like `protected`. This is in quotes because protected in a language like Java means that all subclasses have access. And here, it would just be that you have some fixed class hierarchy. But I certainly encounter this case fairly often where I'm defining multiple classes in a hierarchy and I want one of the classes to work with private state that is defined in the superclass. And again, you can do this by nesting the classes syntactically. But it's pretty ugly. And you would really prefer to be able to write the classes at both at the top level, but this only works if both classes are able to access the same private field. + +KG: Okay. So I had that caveat earlier about, there is one way in which this would change the semantics of existing code. Which is that I said this would make it so that if you see in a class body a name which is already present, then it would reuse that name. This would technically change the semantics of existing code because you can today have an inner class that uses the same name as an outer class. So there is some slight web compat risk to this. + +KG: But as far as I can tell, literally no one has ever written this code outside of tests. I was unable to find any instances of this. And I looked a lot in—addition to the slide, I also did quite a lot of crawling of GitHub. But I also checked the top 17,000 npm packages. And I found almost 700 that have a private field. But it is extremely unusual to have syntactically nested classes at all. And especially in classes that have private fields. And I was unable to find any instance anywhere where there was a shadowed private field. So I don't think this would actually be a problem. + +KG: Yeah. So I think it would be compatible to change the semantics of existing code. And other than that, everything stays the same. I think that the syntax is pretty natural. And much better than the syntax I presented last time. Okay. That's my whole presentation. Let's get to the queue. + +OFR: All right. Yeah. I have one comment to this question. To this initial because you kind of glossed over it when you presented how private fields work. And when you said this is the only proposal that I can pull out Symbols. I think that's a bit simplistic because basically the difference is if where Symbols are created, right? It's very uncommon for people to instantiate the same class literal multiple times. It's very common for people to instantiate the same function activation multiple times by calling that function, right? So we're basically creating Symbols in scopes that are common to be re-executed whereas currently we're only creating Symbols in scopes which are very uncommon to be re-executed. So for example, if you wrap this is a good example. If you wrap this example into a function then you will get back the natural place where I would put private ID without thinking much. I would put it inside the function. But that means I get every time I get back an object literal which has a different Symbol on it. And it's not compatible with all the other object literals. + +RPR: Mark has a request. OFR, can you explain using spec language rather than saying private Symbols? + +OFR: Okay. I don't know. So hash ID. I don't know. I don't get the reply. + +KG: MM, I can probably explain. You can think of each private name as being associated with a Weak Map, right? The point here is that now you need a WeakMap per—in this example \[on slide], you now need a WeakMap per instantiation of `makeWrapper`. And if you remove everything except the class, if you remove the private declaration and the function consume from the slide, then you could write that code today. But the claim was that it's pretty unusual to have this case where you are evaluating a class literal multiple times. Does that answer your question? + +MM: It answers my question. If OFR agrees that what you said means what he was trying to say. + +OFR: Okay. Sorry. I'm confused. So how is `#value` called? That is a Symbol or not? How is that called in the spec? Sorry. + +KG: Private name. + +OFR: Okay. So we're creating a private name here. And what I'm pointing out is that every time you call this function, we create a new name. And the names are not compatible with each other. And it's a detail of this whole system that many people are not aware of because we rarely if ever create the same class twice. And that's why this problem never occurs. However, here now, because now you can stick this creation of this private name almost in any scope, now it's very common that we will have the same it's even that shows how annoying it is to talk about it because we will have twice the same private name but it's not the same. Underlying, right? + +RPR: Okay. There's a very deep queue. So we need to be brief. + +MM: Okay. That answers the question I was asking. I now understand. + +RPR: MF. + +MF: Does this proposal actually need those declarations to be separate private names or could we do a template-object-style interning to have them be a single private name? + +KG: I really don't want to consider any modifications to the privacy model. + +RPR: JHD. + +JHD: So my reply is to OFR. The language already works like that in a ton of ways. That's how identity works. That's how new Symbol works. That's how if you create that class wrapper the instances of from the first call aren't going to be instance of the constructor from the second call, right? So I think in fact I disagree with you. This is something that's widely known. And certainly frequently misunderstood but also widely understood. It's just the way JavaScript works. And I think that's okay. And I also agree with Kevin. I would very much not want to do a template object-like thing. I think that would also be more confusing because it would deviate from the way the language otherwise works in almost every other respect. + +RPR: Okay. KM. + +KM: Is this less confusing if it's disallowed for object literals? Because it'd be the same problem that you have with class literals today. So is the concern mostly just that because we've added the extension to object literals which people use in functions today, that this behaves differently than object literals kind of would today? Or is it just a general statement independent of that? + +OFR: No. It's more the concern that it is it's more a concern about where you're now allowed to put this private keyword, in which kind of scopes. It's more a concern about scopes. So currently you're only allowed to create a private name in a class scope, which most of the time is only instantiated once. And now you're also allowed to put this into a function scope, which is instantiated multiple times. + +KM: So you can only consume the private with a class. + +OFR: No. You can consume it everywhere. No. + +KM: How do you consume it outside of a class? Assuming that you don't allow object literals to have this. + +OFR: That was on the slide here, right? So here you create the private name at the top level and you consume it in an object literal, in a. + +KM: Right. That's what I'm saying. I'm saying if we didn't allow the object literal case, would your concern be less in. + +OFR: Ah. No. I don't think so. My concern is about where you are allowed to write private, not about where you're allowed to consume it. + +KM: But by limiting where you consume it would be the same as using a class body today with private literals and therefore when you have a class inside of a function, each of those classes gets distinct private names. So you would effectively have the same behaviour. You just moved where that name is declared. + +OFR: Okay. I see what you mean. Yeah. Yeah. It would reduce yeah. I agree. I agree. The other way okay. Now I agree. The other way of thinking about limiting the problem is we could also say you're only allowed to write private at the top level. That would be the other way to reduce the problem. And just to state it, I'm not trying to say that this is a problem in how it works. I agree. This is the most consistent with the rest of the language. It's more a problem of how it is explained, I think. I think when we write down this proposal and explain it to people, we need to make sure that they understand that it works and it's not just like, oh, it's like in classes. There is more nuance to it. + +RPR: Okay. PKA says if private was inside the function, you wouldn't be able to consume it in getId. + +KG: In this slide, yes. But in this slide, no. So yes, it's true that if you put it in certain function scopes, you run into this problem. + +RPR: Okay. Let's go to RBN. About friend classes. RBN, are you dialed in? + +RBN: Yeah. Can you go to the slide before this about friend classes? + +KG: Yes. + +RBN: I just wanted to point out that during the class static blocks proposal, this was the one of the specific motivations for that proposal as well with a very similar slide. The difference was that to make the scope of or make the private state that's within node available to graph, it would have used a let variable in the outer scope and used a static block to write an arrow function or something to it so that it could be accessed from graph. So we introduced static blocks as a way to solve this aside from having a private name declaration syntax. So I'm a little bit less convinced by this motivation specifically, but not all of them in general. + +RPR: Jordan. + +JHD: This is certainly a bike shitty question or comment, but so I love the proposal overall. I think this is amazing and we need it. I really dislike using the keyword “private”, I think there's already enough confusion around the fact that JavaScript classes do not have access levels and people think they do and want them to even though they can't. And I would much prefer an alternative keyword. Just so I don't have any suggestions, is there a reason we can't just make “const” and “let” work with these? Since they are basically variables? + +KG: They are not basically variables, oh God. They don't hold values. + +JHD: Okay. That's a fair point. All right. Well, at any rate, so I don't have a suggestion then, but I really don't like the word private. But I love every other aspect of the proposal. + +KG: So yeah. We can definitely bikeshed the name in stage two. I think everyone refers to these as private fields. So I don't think using the word private in the language will make that problem worse. You also had in your question, would this keyword be disallowed in a class body? And I'm not proposing to allow the use of the keyword in the class body so you wouldn't see that. + +JHD: Okay. Given that restriction. Yeah. So given that restriction, I would definitely not block on keeping it to say private. Because the real concern is about the word private appearing inside a class. I still would prefer a different name even though I completely agree that these are universally called private fields. But again, that's like you said, that's very much a stage two discussion. + +RPR: OFR. + +OFR: Can you go to the inner example? Yeah. Exactly this one. So there is a sister problem here. So basically, if you write a subclass that uses the same name, then nowadays it just works because those are two different names again, same problem. But now if you write private on top, you will get a TypeError, I guess. Because you're reusing the same name twice. Do you know what I mean? + +KG: You mean if on line three, I had said `class extends outer`? + +OFR: Yeah. Exactly. If you have “Inner extends Outer”, then it just works. There are two completely separate fields. But then if you write private on top, now you get an error when you try to instantiate inner. + +KG: Yes. That is correct. Again, as far as I can tell, this code has literally never been written. + +OFR: But I thought you were looking for nested classes. And this doesn't require nested classes. + +KG: This does require nested classes. + +OFR: No, it doesn't. So if you have— + +KG: So if you don't currently have a class, which is syntactically inside of the same class as another, then you cannot currently refer to the same name ever. + +OFR: Right. Yeah. Exactly. So if you have a child class that uses the same like the same source name, it will get a different name. So both of these will have two different private fields with two different names effectively. And as soon as you write. + +KG: So you're not talking about quite the example on the slides. + +JHD: Can I—I have a sort of follow-up question. So to rephrase what you're saying, the current example you're correct. Whether it's class extends outer or not, both outer and inner have two different hash x private fields. If you were to write private hash x above line one, KG, the example went away. And you were to then in the same circumstance, I don't even see why that would be an error. I think that that would be my expectation, whether it's class extends outer or not, is that both the inner and outer classes would then have the same hash x private field installed on them. + +OFR: Yeah. Exactly. And that's an error. + +JHD: And that's exactly what I would want and expect by writing private hash x because that you only write that if you're intending to reuse the private field elsewhere. + +OFR: Right. And that's an error. Because if you install the same name twice on the same object, then that's an error. + +JHD: Well, why would it have to be an error in this case. + +OFR: Because that's the current spec. + +KG: So I yeah. JHD, I really don't want to change how private fields currently work. And that is how private fields currently work. You cannot install the same field on an object twice. But I don't have any problem with the code on this slide being an error. I just don't see a problem with that. + +OFR: Well, you can't install the same field twice I hear you. + +KG?: That's what this says. + +JHD: But the syntax hash x equals something is doing two things in a class body. It's installing the field and it's assigning it. Assigning to it. Right? + +KG: So if you just want to assign to it and not install it, then you don't use the declaration form. If you just want the assignment, you write the assignment and not also the declaration. In the class body, you're declaring it. + +JHD: I understand that is currently a requirement if you've set up a scenario where you can refer to the syntax of the same field in both classes. That it will error. I'm saying that in the scenario where you've used this new feature of private hash x at the top, why couldn't we make the hash x equals to in the class B not be an error if it's because the field is already installed? That's not changing how anything works because this is a new scenario. + +KG: It is changing how something works. It is changing how private fields work. + +RPR: I think we should move on. We've got a long queue. And we've already extended the time box. So we've only got five minutes remaining. + +RPR: So LVU has said huge plus one. This solves existing prominent pain points while simultaneously fleshing out private declarations into a first class language concept instead of an ad hoc class syntax. Love it. + +RPR: And then the follow on is also from LVU: is private compatible with TypeScript parsing? I guess so since it's not used inside class declarations, but just making sure. + +KG: Yes. It's totally possible to parse this. + +RPR: WH, please be brief. + +WH: I like the functionality that this is doing; however, I have severe concerns about how this violates lexical scoping. In lexical scoping, when you refer to a variable nested within a bunch of scopes, you look for the innermost scope that defines this variable. This violates that by instead of looking for the outermost scope that defines that variable. And that is a very dangerous thing to do. + +KG: But that is not what I am proposing to do. You would still shadow. The change to how classes would work, in this example, we'd say, it's not that it's looking for the outermost scope. It's saying that the field syntax in a class only declares the variable if it is not already declared. But it's not changing how lexical scoping works. It's not that you're looking to the outermost scope that declares the field. It's that on this slide (4), there is only one declaration of the field, which is on line one. On line four is a reference, not a declaration. It is only installing the field on nodes. It is not simultaneously declaring it. + +WH: Okay. But if you didn't have that line one, then line four would be declaring it, right? + +KG: Yes. That's right. + +WH: Okay. The presentation did not state these semantics. So this is not quite as bad as I thought, but it's still a very significant refactoring danger. To give an illustrative example, people sometimes like to concatenate code. Let's say that both pieces of code have a class which defines `#x`. The front half of the code has some class that has a `#x`, the back half of the code that came from somewhere else also has a class that has a `#x`. The front half also has a top-level `private #x` declaration. If you concatenate those two pieces of code, then the meaning of `#x` silently changes in the back half of the concatenated code even though it was supposed to be lexically scoped. I have issues with that. That's going to bite people. + +KG: Well, I don't think people actually concatenate code anymore. They just use bundlers. And bundlers are aware of this. But you're right that that is a hazard. All previous versions of this proposal have used a keyword like `outer` or something to avoid this problem. And we could go back to that. I just really don't like having a keyword. But we could have a keyword that means I am explicitly only intending to refer to the outer one. The big problem with a keyword is that you end up with these abominations when you have anything other than a bare declaration. You have these `async outer #x` or `get outer #x` or something. This is why I'm hoping to avoid a keyword. But yes, that was the reason we had keywords. + +RPR: So KG, given that we've already extended the time box and we're about to run out of time with a long queue, do you want to ask for consensus now in the remaining time? + +KG: No. + +OFR: Can I maybe? I had something for this exact thing on the queue. + +RPR: The linear? Okay. Let's use the remaining minute to go over OFR's point. + +OFR: Oh, just because now we have it in context. So basically, I want to propose a solution for this problem. So what we could say is that you're only allowed to consume the name once. So you're not allowed to stamp it into two classes, for example. And I think that would remove or not allow to stamp it into two object literals. And I think that would solve most of these problems. + +KG: Object literals is the whole point. That's why I want this. + +OFR: Okay. But you could rewrite this in a way that you only need to stamp it once. If you put the condition inside the value of your object literal, then you only need one literal. And now you're good. + +RPR: So it seems like there's still lots more discussion that's needed on this one. So I think let's wrap this up now. KG, we'll capture the queue. To give more conversation offline. Kevin, are you okay with writing up a summary of what has been discussed? + +KG: Yep. + +RPR: Okay. You've CDA, you've captured the queue. + +CDA: Neo TCQ, if you just go next agenda item, it captures it in the log. + +RPR Amazing. TCQ does the capture by default. All right. Okay. Lots of good discussion there. So yeah, thank you, KG. We will move on to the next item. + +### Speaker's Summary of Key Points + +* Private declarations are restricted to classes; presentation suggests lifting them. +* OFR is concerned this will lead people to getting confused about how class names work. +* WH doesn't like the proposed change to make `#x = 1` in class bodies use an outer name if present. + +### Conclusion + +* Discussion will continue. + +## Composites for Stage 2 + +Presenter: Ashley Claymore (ACE) + +* [proposal](https://github.com/tc39/proposal-composites) +* [slides](https://docs.google.com/presentation/d/1lN-LdmUQ9Nh6bF-5uuuuAQhHtDBTmI9xfYyj6TH_8F4/) + +ACE: Okay. Composites. For stage two. So first, a recap to page everything back in. Because the last time we spoke about this was in July. We also previously presented this November and April last year. And it very much follows on from the very many, many presentations we did about Records and Tuples. So lots of context to page back in. + +ACE: So the core problem space that I present every time so hopefully, this is all very familiar is whenever you're trying to put a richer—you have multiple values that would represent a single key in a map. But I'm just going to use sets for examples because it's easier. Because the keys are all that matter semantically here. If you do something like this with regular objects, it just doesn't work. These two values are objects even though they're frozen and they contain the same thing. Two different objects aren't equal. So we have two items in our set. The most common thing you see code do because it's just right there built into the language is you JSON stringify. So I now have two strings that are the same, and so are considered equal. And I have one thing in my set. + +ACE: But I'm not super happy because JSON stringify is just not great for this. It is impacted by key order. That's the most subtle thing that burns people. It will throw on certain value types like bigints. It will subtly change some things: like NaN comes null, dates become strings, etc. And taking some particular a number with lots of digits and turning it into a string consumes more memory. There's lots of examples here where flattening everything to a JSON string especially if you then put that JSON string into a map engines like V8 will then flatten that string. So it's a lot larger memory footprint. And at the end of the day, you now have a bunch of strings as your keys. So if you want to iterate over those keys and reflect on them and use them, you then need to go back the other way by JSON parsing it. + +ACE: So what this proposal offers instead is a type that gives you what you wanted originally with objects. So when I create these two things, that contain these values X, my X and my Y are the same, then we say they are equal. And as presented last time, the reason they are equal is because the constructor factory function will intern such that these are literally the exact same object in memory. There's no special path we're hitting there with the triple equals. That is the same pointer. It has no idea we're comparing composites. It just says you're comparing something to itself. Therefore, it's true. So naturally, that's just going to considering it's impossible to tell these two things apart because it's the same thing, it will just flow through the rest of the language. So the set will say you've just added the same object twice. I have one thing in my set. + +ACE: So again, core semantics. Again, recapping stuff I've already said before. So this is not a new primitive. You are creating an object here. These things aren't opaque. Like I said, if you have a map or a set, it's very common to then want to iterate on that and not just have a whole bunch of opaque values. So you'll have the keys. And four. They're frozen. Kind of that have to be. They don't have a prototype. So the only values will be accessed on them are the ones that contributed to the kind of its uniqueness. And also as presented last time, the kind of special thing about these that does make them different from other objects is that you can't hold on to them weekly. So that applies to all the weak things. And that language like weak ref, weak map, finalization registry, tokens. + +ACE: So how can you tell if something is a composite? You could pass it into a composite. And if you get the same thing back out, it would the proposal provides a nice way to say if something is a composite. Because it's possibly a common thing you'll want to do. So there's just a built-in predicate for that. What the object you pass in, so you're not converting the object you pass in into a composite. It's just kind of a description of what the keys should be. And it's just the own properties of that. So I passed in a bunch of things here. So the things to pull out of this example be inherited property from the prototype didn't make it in. It's never consulted. And then the order we get back. So it's not the order I pass things here doesn't matter. But what matters is all of the just like a regular object, any of the integer index keys, there'll be ordered numerically. And then all the remaining keys are ordered lexicographically. Lexicographically. Alphabetically. + +ACE: So the emergent kind of equality that's hopefully obvious. So if I say a composite with X1 and Y4 and then have another composite where I've changed the order of the keys, that doesn't matter. So these are equal. And there's no subtyping equality. If even though these two things both have X equal to one, the fact that something has additional keys that's not going to intern to the same thing. So these aren't equal. So it's not like a partial equality. + +ACE: So you can't—I showed what kind of what happens with regular string keys. What happens with a Symbol key? You can't have a Symbol key. And this is this came up with Records and Tuples. There's no way to sort Symbols. So we can't produce a canonical sorting. Therefore, we can't reliably consistently intern. So we just say no Symbol keys. We theoretically could allow some Symbols like registered Symbols or have a string representation. So we could sort those. And you can imagine other various interesting carve outs like if all the Symbols you use have a unique description, then they are sortable. I feel like that I've not been shown a use case where someone wants a Symbol key to kind of name part of their map composite map key. So I think the simplest thing to say to people is no Symbol keys. + +ACE: So that's the keys briefly. What can use for values? You can use anything. For the values. So this is like one of the very big differences from reference and tuples where you could only use primitives. Here, all values are allowed. One change since I presented last time is that the existence of a property being `undefined` is carried through. That's not treated like a missing property. So the fact that you had a U key set to undefined carries through to the composite such that it also still has a U key set to undefined. But the equality of this is not like a—you'll just inherit the equality. So if I create two composites with two dates and they are the same point in time, but two different objects, then they're not magically equal. The equality here is just the kind of equality of those values. + +ACE: So everyone's favourite topic is minus zero and NaN. We know this is everyone's favourite topic because when we did records and tuples, it was the second most commented on issue. The top most commented issue being bike shedding the syntax. The second most commented issue by a high margin. And it's already the most commented issue on the composites proposal. + +ACE: Why do we love talking about negative zero and NaN so much? Well, it's because it's the only two values where we have interesting equality semantics. So we have four types of equality in the language because we love equality so much. So there's loose equality, but loose equality is really just a two-stage strict equality where we try and coerce things to be the same type before checking if they're strictly equal. + +ACE: So if we put loose equality to one side, and we have the three, for every single other value in the language, we agree it doesn't make a difference which of these equality operations you use. You'll get the same result, false or true. It's only for NaN and negative zero where we change our minds and we change our minds differently depending on if it's NaN or negative zero. So that's why they're so very interesting to us. And again, this is all just paging stuff in. What do we do with these values currently in the language? We say that you can't fill up a set with infinite NaNs. There's only one NaN you can put into your set. You also can't put two different types of zero in a set you can only put regular positively signed zero into a set. We normalize it. So if you ask if a set contains negative zero, but it contains positive zero, we still just say that's true because we normalize it. + +ACE: So for composites for NaN, I feel like because we're interning, NaN has to kind of be equal to NaN. Otherwise, if we wanted to say if you create two composites and you say you have a NaN in there and we want to say that's not equal to something else, then we're effectively saying every single time you create a composite with a NaN aspect component, you'd have to allocate a new composite. So if you just looped creating composites with a NaN value, it would just be like a memory leak. So I think it's just especially again, this is all the primary use cases are all about multi-component map keys. If we say NaN is equal to NaN in a map key, then I feel like we should say NaN is equal to NaN in a composite. + +ACE: So for negative zero, I've done the design by committee approach of saying there's an options bag. By default, we again just have the semantics of map keys where we normalize. So negative zero and zero, we say are equal to each other because it's normalized. But if you don't want that behaviour, then you can opt out of that and into saying, no, I it's important to me that the sign is preserved and I want to create a composite that has negative zero. So that's then going to in turn to a unique key that won't be equal to positive zero. + +ACE: Just for again, why this is such a kind of interesting topic, even if we look at other languages, on just how do they handle putting negative zero as a key in a collection, then lots of them say that negative zero is equal to zero. But Java and things that kind of run on the JVM, negative zero, the double value of negative zero has a different hash to zero. So they're not equal. Actually, maybe they have the same hash, but the equality function will say they're not equal. And languages like Rust and Zig, just like statically won't compile. They'll say the floating values don't implement the kind of hash equality interface. So they just say this is banned territory to even go into. But in general, lots of languages say they are equal. + +ACE: So there are remaining to-dos, in my opinion. Of course, maybe there are more things. So I still think I imagine we're going to keep talking about negative zero for the rest of my life. We need to come up with some names for this. And I think realms is an aspect that I've kind of kept shunting that I can't do that forever. So naming things, these are some of the ideas that have come up so far, composites, calling them records, or not creating a new type because these things aren't types you can't inherit from them. They don't have a prototype. So maybe it should just be a utility function. Right now, I kind of like the idea of `Object.for` because there's a lot of relationship between the semantics of this and `Symbol.for`. So that's where I'm currently kind of leaning. But very happy to hear ideas here and get some feelings. + +ACE: And then realms. So in Node, if you use the Node VM to create another context or if you use Cross same origin iframes what happens if you get two different composite factory functions? Did the A share an internal registry or not? The current draft spec says they do share a registry in the same way that `Symbol.for` does. So if I get two different Symbol constructors then if I ask that give me the Symbol for the string 42, they share a registry and I get back the same value. So I think there is precedent for this there being a shared registry. However, I very much aware that this would really not be great at least for SpiderMonkey, maybe other engines because SpiderMonkey has a per realm heap for objects. They have a shared heap for strings, a specialized heap for strings, but saying that composites allocated into a shared heap across realms would be really annoying. So in that case, what they would probably have to do is have a per realm registry that is then made unobservable by saying when you pass things from realm to realm and cross their Think in practice it's going to be very uncommon for people to parse things from realm to realm, so you could then take that either way. You could either say it doesn't matter, we shouldn't have a cross-realm registry because most people won't be doing that comparison anyway, or you could say that the fact that there's a performance penalty of parsing them from realm to realm for engines where they would need to do that doesn't matter because that wouldn't happen. So I think at the end of the day, I think the people that will pay the cost on this the most are the engine implementers, so I kind of will follow kind of their lead. My personal preference is that it is a cross-realm registry, but yeah, very much happy to hear feedback on that. + +ACE: So I know there are lots of things in the queue, but I would kind of like to see, are we at a stage where we've got enough for stage 2 and because we think they're kind of enough of the solution space is there, so here I've kind of paraphrased our requirements for stage 2. We say that we've got a solution space, but they're may still be significant change and I think this is the more important thing is we expect the feature to eventually be included in the standard. Though obviously that's no Promise, especially because the main thing I don't want to happen is I don't want a repeat of records and tuples where it's sat in stage 2 for years and years and years, and then eventually was rejected like I would kind of refer to staying stage 1 if we have apprehension rather than kind of like nervously going to stage 2. Like I'd only like us to go into stage 2 if we're actually like yes, we're confident on this and yes, there are remaining things, but those remaining things we think are very much within our like capability to resolve and they're not things that we think are going to be like impossible. So I think it's important to signal to the wider community if we actually think this is going to move forward. So even though there are things on the queue, I'd still like to at least ask for stage 2 now and people can very happily say no, I want to go through the queue first. + +CDA: I have a quick clarifying question. I think you chose the word significant changes. Could happen after stage 2. How? + +ACE: I didn't choose this—this is straight from our process document, may still change significantly. It's in our process document. I mean, I'm hoping there won't be significant change and the only changes are like the names, the negative zero, the realms. + +CDA: Okay. But you so okay, that's the first box of the process document. + +ACE: Yeah, I think we could change the process document. + +CDA: You would suggest that all major semantics syntax and everything is good and the refining or minor details. Okay. So I guess does anyone it's a weird question to ask, but does anyone object to calling for consensus before further. Discussion? + +KM: I guess I'm probably going to say no on it anyway without I mean, certainly without discussion of my stuff on it. + +ACE: That'd be fine. + +KM: Yeah. + +ACE: And basically I want to avoid like us discussing and then saying we have 60 seconds left and trying to ask for stage 2. I'd rather ask for stage 2 now if we're happy and then just use the discussion. But if there's any apprehension about stage 2, then yeah, let's not ask. Let's discuss. + +KM: Yeah, I think there's apprehension on our end for stage 2. + +ACE: Absolutely fine. Yeah, let's go through the queue then. Yeah. + +CDA: All right. We have a clarifying question from MF. + +MF: You had a slide, I don't know what slide number it was—9—where you had like `Composite(c) === c`, does that mean like you can pass a composite into that position and then it would just return the same composite? Is that what you're saying? + +ACE: So here, I was trying even if we didn't provide a predicate, you can still kind of detect if something is a composite. By parsing it into the function again so letting it be read and then seeing if it interns back to the thing you just passed in. If it is, then you know the thing you passed in must have been a composite. + +MF: I see. So this is like `Object(x) === x`. + +ACE: Yeah. So it's like considering there will be ways you can do it anyway, that's why I'm saying we might as well have a predicate because it's kind of weird to tell people this is the magic trick to detect it. + +MF: Okay, that explains this slide a lot better to me. Thank you. + +ACE: Yeah. Sorry, I explained poorly. + +ACE: MM? + +MM: Yeah, can you return to the one where you're doing the interlanguage comparison? Yes, that one. So for the ones that say true, there's two conceivable reasons why they might say true, and this slide doesn't distinguish them. When you're talking through your JavaScript examples, you also were very careful to then extract the zero back out and see that even if it started as a even if you put in a minus zero, you get a positive zero out. The other explanation of why these things might be true is that they just take whichever zero they saw first and then they just use a SameValueZero comparison. + +ACE: So I did side step the fact that we are the only languages that normalize. And that all other languages you all observe the fact that you've stored a negative zero, but it won't necessarily be—it'll be the last right wins so if I like put a positive zero as a key and then I try to set a negative zero as a key like it would replace the positive zero, and then I would now have a negative zero as the key. So they like personally I think JavaScript choosing to not have that race and to normalize actually. We’re the better language than all the rest and just we're the only ones that really thought about this. And I absolutely assert that we are the committee that have spent the most time talking about negative zero than all the other languages combined. Whenever I try to look through their notes and their discussions, like there was some discussion about negative zero in Go, but like very brief, very, very brief. But we are the weird ones to normalize. You're correct to pull that out, Mark. + +MM: So I have the same preference you do. However, I am not a numerical analyst. So WH, if I can ask Waldemar why do you find it acceptable that minus zero gets stored normalized to positive zero? Isn't that inconsistent with the numerical analyst's need to preserve the difference? + +WH: I do because there's an option to store a minus zero, which was covered in the presentation. + +MM: Not in maps and sets. I'm asking the historical question. + +WH: It's rare to use a set of floating point numbers like that, but for composites where you're passing data structures around, it's important to support the use case of preserving negative zeros. For sets it's less of a concern. + +MM: Okay, good. Thank you. With that clarified, I support your handling of NaN and minus zero. The other thing that I want to bring up, and I'm so glad that you related this to the registered Symbol as precedent. I think that's exactly the right precedent that we should follow in as many respects as possible. And in particular, when you mentioned `Object.for` as the alternate name, my enthusiasm for the proposal tripled, but then you got to figure out, well, what's the equivalent that is composite? But in any case, the important thing about registered Symbols is that the registry is not a communications channel. And we're very, very careful it was, so I want to be as so first of all, I could not spot any violations of that in your proposal. Clearly you intend that to be the case for your proposal. Do you believe that during stage two, you can arrive at similar confidence that there is no communications channel through the registry? + +ACE: Yeah, no, I'm very confident. Yeah, as I said before, like putting a timing attack aside there's no way to observe the registry. And this is so Go has a built-in interning thing. They don't normalize negative zero, but do treat it equal. So there is a like a registry communication channel in Go for their interning that you can kind of if you create something with positive zero, you might get a negative zero back because somewhere else, somewhere in the process, someone interned that value before you. So the fact that we don't do that means that, yeah, there isn't that cross-process communication channel. + +MM: Good. + +ACE: And the fact that the sorting is canonicalized. + +MM: Okay, and finally, I would insist that it were cross-realm. If cross-realm these were not equal I would likely object. + +CDA: KM. + +KM: Wait, sorry, I missed that last part, Mark. What's your comment that if it was not cross-realm, you would object? Or if it was cross-realm, you would object? Okay. Well, I guess that conflicts. With my later point. + +MM: Yeah, if it's not cross-realm, I object. And again, the registered Symbol is the perfect precedent there. + +KM: Yeah, okay, I guess I'll start with the second part, my second point then. But here's the one that's at the top. But I think having a shared registry is like an extreme hazard for huge memory leaks. In our implementation, and I imagine other implementations, every object knows exactly what realm it came from. So like this would therefore know about its realm. And so if you kept one of these around, you leak your iframe— + +ACE: So, sorry to cut you off, KM, just because I know that. So as I presented you semantically, we can say that it's cross-realm, but it can be implemented. So we've got a an example, a Spider-Monkey patch where the actual object allocation is per realm. Actually, then maybe this only works for Spider-Monkey because Spider-Monkey always only allocate objects per realm. So they have a membrane between the realms. So whenever they can they have a one point in the code where you can say anytime a reference from an object goes to another realm, it has to go through this function. And that function can then kind of say, okay, when you're taking composite from this realm to that realm, it gets re-interned so that there are always separate graphs. But maybe for the JSC case, you don't have that work for equality? Does the equality do some deep function call to do equality? No, no, it just you can't observe the equality being different because you can never have a handle to the value that would be unequal to you. + +KM: Yeah, I think that would not work for us because we just have the raw object. So you would just have the raw object and then it's pointer equality. And then you'd end up with the same problem of like, I gave you back an object, you put it somewhere. And now you keep the other realm around. + +ACE: Right. + +CDA: Is there a reply from OFR? + +KM: OFR says plus one to my point. So I guess then I'll move on to the other topic. Of the which I guess got lost. But we don't really want a new enumeration order. + +ACE: There's no new enumeration order. + +KM: There is a new enumeration order because the keys of the object that you pass have to go alphabetically, which means that you need to figure out which keys how to re-enumerate in the order of the alphabetical order. And based on the shape of the API, because it interns, you're incentivized to actually call the constructor repeatedly, which then means engines will be incentivized to optimize for like how to look up enumerate an object alphabetically. On the keys, rather than like what they do today, which is insertion order. To require new caching and all kinds of other things because you're probably going to do this over and over again. You're not going to cache your composite. You're just going to have a factory moreover, I think there's concern that even if you have the alphabetical ordering doesn't solve all your problems because if you have more than one line of code that creates the composite, you need to make sure if you add a new key there, right, that you find all of the other places that could feed in anyway and make sure they also have that key. Right? So if you don't find that place, then your composites don't line up anymore and you still have the same bug of like—your composites don't match when they're supposed to match. So I don't have a particular solution in mind for it. + +ACE: So the way I implemented it in V8 was that there is a cache for when an object there's a cache from the shape of an object to the like alphabetized. So the first time you create a composite from an object, it will then compute the sorted order of the keys. And then put into a cache saying anytime you see that shape, this is then the sorted order of those keys from the indexes. + +KM: I understand that you can do that. + +ACE: Yeah. + +KM: I'm saying that we don't want to start doing other types of enumeration order in a language and have any flavor of enumeration order. I mean, that users would want. + +ACE: Because you think it's can you explain what you mean by enumeration order exactly? Because I was like. + +KM: Because I mean, the order that you look up the keys, right? That's enumeration order, right? Like the order that you look up the keys when you do a for-in today is the order that they were added to the object sorry, for string keys is the order they were added to the object. I was specifically talking about string keys. Sorry. To qualify this whole discussion. + +ACE: So I mean, you the way this spec is written, you read the object in its in its order. Then you sort them. And then you turn the composite to the object is always read in its enumeration order. + +KM: That also feels like a poor performance thing for something that we expect people to call constructors repeatedly. + +ACE: So in my previous presentation, I showed the benchmarks of this and saying if you add that caching layer, this the performance is achievable. This is why I implemented it in V8 to show that what like to prove that I'm not just hand-waving and saying you guys make this fast. Like I think this if I'm not I haven't written C++ for a long time. I feel like if I was able to make it perform well, I think you will also be able to make this perform well. + +KM: It's more of a maintenance order, right? It's not that it's not. + +CDA: Let's not talk over each other. Please use the queue. I appreciate the enthusiastic discourse, but try to give each other a little bit of little bit of room. Thank you. I did not mean to completely stifle the discourse. + +ACE: The reason I've worked on making this be based on interning was based on a lot of engine feedback on you didn't want any customization to equality. So the interning makes equality like the like no changes to maps, no changes to sets, no changing to triple equals. Like the complexity, which I completely agree is there, is contained to just that factory function. And I so it's this is in direct feedback to the previous complaint about complexity. So we could not intern, but then we'll go back to the previous problem of now the complexity is spread across the. + +OFR: I feel like I feel like the discussion is going off in the wrong direction. Because I think like the discussion here like what like basically the question is, should we sort the key in the resulting composites that is the question that we're discussing. We're not discussing should we intern, should we not, should we whatnot. And what you were saying is like it's not a problem to sort them because we can cache it. And you showed it in V8. And let me quickly address that because we do already have as Keith said, and I guess all engines have that. We have an enum cache, which is basically if you do a for-in of an object, then we have to produce a certain order of these things. And we cache that order, right? And it's already a trade-off as it is right now. There are other places where objects are enumerated in different ways. And there are even some kinds of objects where we don't have an enum cache and enumeration is painfully slow. And that's already the case right now. And it's already a trade-off that we make where we say like, OK, this is not important enough to warrant an enum cache because because it's actually something I mean, for one, it's tricky to get right. And second, it's also like it uses lots of memory. So is this one of the use cases where we would say like this warrants a new cache? I don't know. But I I'm not convinced. And so now the question is, what do we gain by sorting the keys? And do we even need it? So why does the composite need sorted keys? Why can't we preserve the enumeration order or as KG suggests in sorry for going skipping ahead, but throw if the keys are not ordered. I feel like there's a whole range of possible solutions to this problem. + +CDA: KG. + +KG: Yeah. So I'm next on the queue. I absolutely insist that they must be sorted, to respond to OFR. I don't think—the problem is that you can construct these in two different places. And from the user's perspective, the same object, but if the enumeration order is different, they're not the same object. They're observably not the same object. And if it just uses whichever one happens to be first, then you have this weird global race where, if anyone on the page ever constructed a composite with a particular order, anything else that happens to use those keys now gets that order. And I would consider either of those to be completely unacceptable. However, kind of a weird suggestion, but we could say that if the objects that you're passing to composite doesn't have its keys like its string keys in sorted order, then we throw. This would be like a really weird thing to do everywhere else. And it would be a really weird limitation of Composite, but it would solve this problem. And since I expect almost all uses of this function to be passing an object literal, it's not that hard to arrange that the keys of the object literal be in sorted order. So like… eh? It's a thought. + +ACE: I kind of love it in that I think in practice, obviously there are cases where that would be really annoying if someone's spreading something. But I think the most common case for this is that I think people will be constructing these things statically with a literal because they want to be very clear about what the key components are. And a linter can see that they're not ordered. And moving all the work to like authoring time I think does solve a lot of the problems. And it's obviously we could relax in the future. So it's like actually kind of like that. + +KM: OK. I guess this is a reply back to what OFR said before, but the queue makes this difficult to do because I can't move at any point I want. But the I can't reply to a reply. The yeah, interning isn't the problem. I don't have a problem necessarily with interning. The realm issue aside, yeah, so that's yeah. + +ACE: Yes. I assumed like the reason we saw is because we're interning, which is so I assumed yeah, I conflated your complaint more than I should have. + +KM: I might have poorly phrased it as well. I'm happy to also take fault. + +CDA: All right. Mark's on the queue with "becomes a communication channel". + +MM: Is that clear? + +CDA: yep. I folks are nodding in the room. So I think yes. + +KM: I guess one option instead of this is I think it's possible. I haven't I forgot that you could actually list the named keys yourself. But certainly if you didn't want the keys you didn't care about the named keys being on the composite, you could create the keyed version of this trivially by just with whatever a small like thin wrapper around an indexed list of the arguments, right? And the upside of having the indexed list is also then you don't have to like do any of the optimizations of like trying to align this object allocation if you're trying to look these up in a hot loop, which is totally possible if you're trying to look up a hash set. And so that in theory is a bit more performant. I'm not necessarily tied to that. I think that also because you can create this wrapper yourself, it may not be so bad. The I suppose one downside of that though is I think it would break the like composite of composite of x is equal to composite of x, right? Because you have an the you'd have to have something special that says a composite maps to itself. Like the underlying values or something because you could have multiple parameters and so you could have because they're indexed, I think I think that might break. I'm not 100% sure. So yeah, but yeah. I agree that's less ergonomic but I think that it would solve many of the concerns that we have and certainly if people really want the ergonomics, they can add it themselves. I guess to restate the point. + +ACE: There's a few reasons why I've gone for named rather than ordered parts. And this one is I really don't want people to think of these like vectors because I think people will think they're optimized like a functional like in functional programming. I think they'll think of these as like a linked list and they'll do things where they loop appending something as a head. And if we're interning every time, it will have this like quadratic cost. So I want people more to think of these things as named rather than things that they can scale up to long lists. And if you have to give them names, it very much discourages these things being long because they very much scale on the number of components. In an exponential way. So the other is that it doesn't scale very ergonomically when you like if you have the x and y case, like a 2D or 3D vector, then it's like obvious that x, y, and z is 0, 1, 2. But in other cases, remembering which one and having to like write helper functions for it and passing them around like starts to become yeah, the ergonomics isn't so much there. I have thought about you could we do like a Python style thing where we do just split the case so it's like a two phase where you first say these are the names of the keys and that again gives you back the factory. So you say I want x, y, and z and then that gives you back a thing that you just pass in. So we basically like we move that kind of like caching step into the language. There's a way of maybe a balancing act of the ergonomics of the names but the performance optimization of not needing to like sort. + +CDA: All right. Just a quick time check. We have under 15 minutes remaining in the time box. The queue looks longer than it really is because there's a lot of like end of message and support for advancement. But let's try to still be mindful because we need to save room for the delicious call for consensus. Oli. + +OFR: Yeah. I think my proposal was misunderstood by preserving the insertion order I would also mean by that that you would get a different composite if you have a differently ordered object. And I don't know. I feel like that would be way less bad than all the other options. + +ACE: One of the points to this proposal is to avoid that issue. I have seen that come up, like it's not a theoretical case with `JSON.stringify` cases that have that issue of the key order. Like it's such a subtle thing. I think that I would really like that to not be how this because I think it I really want that to be a problem we solve rather than carry on. Yeah. As I have a strong personal preference there but it's I appreciate there's a lot of things we're trying to balance here. + +RPR: WH. + +WH: I also have a strong aversion to making the key order significant. It appears to make sense for literals but as soon as you generate objects programmatically where you have several different ways of generating some kind of an object which might add properties in different orders then you'll just get subtle breakage. I don't want to go there. + +WH: My question is whether the sorting order is strictly alphabetical or are numeric properties in any way special? + +ACE: Yeah. So because even if you create like a regular object, you know the fact that we treat the index numeric keys differently and the fact that that is very much reflected in implementations that those keys are stored separately that that is what you'll get back especially if we don't do that it's impossible to implement this in a polyfill because you can't unless you you would have to use a Proxy for all of these to be able to your customize that key order. So the fact that if you try to implement this just using regular ordinary objects this like matches the internal method of an ordinary object's key order. + +CDA: OK. Keith. + +KM: Yeah. I guess on somewhat similar to this point I guess the case where I can imagine where you wouldn't just have an object literal is like suppose you have I guess maybe this is a bad example now that I think about it like a point class and you have a 2D point and a 3D point your 3D point you want to add the third coordinate I mean it is z so I guess that's awkward and that actually it's sorted but imagine a different world where they're not actually that way. But like you'd end up with was it something out of order? Yeah. RGB or something and then you want to add alpha and now all of a sudden your keys are out of order. And you can't use the same constructor and then you need to duplicate constructors and then you have all the hazards of duplicating the constructors which so I would make me uncomfortable with that. + +CDA: All right. Let's go through. SFC says plus one on `Object.intern` makes it super clear what is happening. Intern is a word used in other ecosystems for this. + +CDA: Next. MF says I actually love the name composite for this. Let's not call it object.something and imply it's just a weird kind of object. DLM is on the queue. + +DLM: Yeah. Sure. I'm just wanting to say thank you for the presentation. Yeah. We're happy to support stage two for this. I guess all of our earlier concerns have already been addressed. The only thing I wanted to bring up is I'm not sure to what extent the per agent versus per realm thing registry has been fully decided but as alluded to earlier a per realm registry would definitely simplify our implementation and make our garbage collection people a bit happier. + +CDA: All right. Next. LVU says regarding Symbol keys are rejected there is no canonical sort order across all Symbols sorting is in implementation detail not part of the core use case so that's not a user facing reason it seems that all you need is a stable order which seems doable also plus one on the name composite. + +ACE: To just reply, they get this came up time and time again with records and tuples like we could come up with a stable ordering for Symbols but it just it just gets rejected and every single time we tried because you could say like the orders in which the Symbols were constructed is their order but now that creates this communication channel or you could just say the very first time you put Symbols into a composite there's this hidden cache of that's the order and every single idea people have just gets rejected like I think there's no way we can say we could also just hand wave it and say it's an implementation detail which is again something that's been like said is unacceptable. So I think for Symbols that have no like string part there is no way we could define a sorting order for them. + +CDA: MM says "exactly stable ordering for Symbols leak info". JHD. + +JHD: I really don't like the name intern. I don't know what interning is; I don't want or need to know; and I think most JavaScript developers are in that same bucket. I think it'd be really confusing to name it that and the C++ experience in this room I think is not representative of the wider ecosystem. That's an easy bikeshed during stage two though. OK. Now I feel really I have a lot of feelings about negative zero—I'm very unhappy that maps and sets chose same value zero by default I think that the rarity of negative zeros appearing at all it means that people just aren't going to get bugs with them unless they're trying to use them and then the current behaviour gives them bugs. I believe the current proposal—I was out of the room for a minute—has an option that lets you switch between SameValue and SameValueZero. The existence of that option is very good. I still kind of prefer the default to be same value but yeah just wanted to make sure it's on the record that like I effectively insist that there be a way to preserve negative zero and I strongly prefer it to be the default. + +KG: I feel even more strongly that we must normalize. Negative zero comes up all the time, you just don't ever think about it because you never have to because it's triple equals and because Maps and Sets normalize, but it comes up all the time. If you're rounding, like round(-0.1), or you're multiplying by a negative number, you will end up with negative zeros in your code. You just don't have to think about it because Maps and Sets normalize and because -0 is === 0. So the default absolutely must be to normalize. That said I'm fine with there being an option. + +MF (on queue): as someone who regrets SameValueZero in Maps/Sets, default should unfortunately probably match those; having an option is great though + +WH (on queue): +1 Kevin's comments + +CDA: All right. That is pretty much it. The rest of the queue items are about stage advancement. + +ACE: I love all the support on the queue. What makes me very nervous is that I think we've heard from all of the engines they would prefer per realm registry and Mark has said he'll block unless it's cross realm and what I really don't want to go into stage two in a place where it seems like we have opposing blocking concerns because I think it sends it I can't see a way part like unless we think there's any wiggle room on either side we'll just never going to get past it so I'm very hesitant to I don't want to move into stage two if we don't think there's any wiggle room on either side. I'm obviously not asking people to like promise, but. + +MM: When you say wiggle room I don't see any incremental steps away from the position. Two opposite positions and there's nothing in the middle. + +ACE: Yes certainly from like there's certainly no wiggle room in design like either it's cross realm or it's not but yeah. + +JHD: I have a thought. Let's say we introduce the composite constructor as the way to make these what if instead of having a null prototype they have a prototype of composite dot prototype which itself has a null prototype and composite dot prototype can even even be frozen if you want and that way there is an easy observable difference between composites from different realms they can naturally be per realm like every other object is and we don't even like need to think of it as a registry although of course would be. Is that at all viable? + +MM: I think not. To me, one of the requirements of this proposal which the proposal was satisfying is that the actual composite object does not have anything observable that ties it to the realm of origin. + +CDA: What we need to make a decision here on whether you're going to ask for consensus now or not. We might have time if we make up time from other topics to do a continuation? + +ACE: Yeah I just don't feel comfortable asking for stage two. I think it's the wrong reading of the temperature and the. + +CDA: We have a couple minutes remaining. I know OFR has replied but KM was on there. I don't know which one is more timely. I will defer to Ashley. + +ACE: Sorry. Just KM— + +KM: So yeah I thought this because you mentioned the Python thing of like constructing it. Would it be possible—I haven't thought about this really at all but just as an idea of having the interning cache be explicit as like a registry in the same way kind of like finalization is a registry and then when in your factory you say I actually want it to go into this interning registry and then that would hopefully you wouldn't be able to share hopefully I wouldn't create a communications channel because you have to actually have the object to put it in that interning I don't know if that's all everybody's problems and makes everybody happy. + +ACE: I do think that is a it leaves the door open for there being like an option to say I want to access the cross realm registry like but we initially the initial proposal is a you know composite dot create registry is the only thing so you could do like composite dot create registry and then yeah the only things that can use that have a handle to it and then but in the future we could have composite dot global registry as the so I think that is a way we could potentially meet both sides. + +MM: I'm very confused about this. Does that mean you have to have the registry in order to intern something in the registry? + +ACE: Correct. + +CDA: We are pretty much out of time. OFR do you want to be brief in your— + +OFR: I mean I just don't understand the problem, like why would you block a cross realm? I'm not sure there is actually a problem—like why does it have to be cross realm? So I don't know. I kind of question that absolute point. + +MM: OK. Because a composite is in most ways value like you know you've removed the identity and you've only allowed in you know things that are well it's shallowly value-like. + +OFR: But that's more philosophical. Like I'm trying to find the actual thing that really blocks it. + +CDA: Sorry to speak over you. We are out of time. We can continue maybe asynchronously via GitHub issue or something. And maybe if we think we can have a productive conversation at this meeting and we have time we could maybe discuss this if time allows. But we must move on. + +### Speaker's Summary of Key Points + +* Started with a reminder of the proposal +* It is now based on an interning strategy, based on the conversation from the previous plenary +* We still need to decide on: naming and if the registry is cross realm +* There was discussion on the implementation implications caused by the need to sort the keys + +### Conclusion + +* The Composites proposal did not call for consensus on Stage 2 advancement as there are still opposing views on interaction with realms + +## Continuation: Establish normative conventions for invalid input strings: RangeError vs. TypeError + +Presenter: Richard Gibson (RGN) + +* [proposal](https://github.com/tc39/how-we-work/pull/176), [narrower proposal](https://github.com/tc39/how-we-work/pull/177) + +RGN: The previous session was sufficiently productive that I am able to come back with something concrete. Brief recap for it. The the temperature check that we ran produced 18 votes in favour of RangeError for the specific case that we were looking at, which was a string enumeration and input being a string not in the enumeration. 18 for RangeError, 4 for TypeError, and 2 indifferent, which is a pretty strong signal in support of RangeError. But we weren't really able to move forward decisively because there was nothing concrete to look at. So given that poll result, I've just now opened a pull request to update the normative conventions with what I believe is the result corresponding to that temperature check. And we can now take a look at it. What I have done here is define appropriate use of RangeError, and also SyntaxError as well for completeness. Hopefully this is not controversial. + +RPR: And has this link been publicized? + +RGN: I don't think it has yet. I will add it to the notes shortly. + +RPR: Thank you. + +RGN: It is the latest pull request on how on TC39 how-we-work. + +RGN: So yeah, picking back up. If SyntaxError is controversial, hopefully we can figure something out over the course of this discussion. But briefly, the appropriate use of SyntaxError is I think for well-formedness violations. Where valid input is a set that is so large that we describe it practically as a grammar or a pattern or something along those lines. Where a string is to be evaluated against that (in the sense of we either received a string directly, or input was coerced to a string). And when the result of that does not conform with the constraints, then that's a scenario where our convention would be to throw a SyntaxError. So some examples, all of which are already the case given the current specification, would be the BigInt constructor, `JSON.parse`, and `Uint8Array.fromBase64`. These are I think in every case described grammatically, and obviously the set of valid inputs for all of them is logically unbounded. Technically strings have a maximum size, but it's so large that we would never describe any of these by enumeration. And when the input is a string but does not conform with that syntax, we throw a SyntaxError. + +RGN: Moving on now to RangeError. It seems like the predominant opinion, which I happen to share, is that RangeError is appropriate for other validity violations where the language type matches. So where valid inputs are a strict subset of all values of a particular language type or a union of language types, and the input is of an acceptable type but not in that valid subset, that's when we're looking at RangeError (except where SyntaxError has already covered the scenario). The cases that I found which were worth describing are **bounded numeric intervals** like 0 to 100, **half-bounded numeric intervals** where you've got a minimum or a maximum but not both, for example “non-negative”, **sparse subsets of numeric intervals** like “integral numbers” or “integral multiples of 0.5”, and finally **string enumerations**. And I've also provided examples here of current code that would encounter this convention. Number toFixed requires that the input be positive, so `(1).toFixed(-1)` gets you a RangeError. BigInt exponentiation requires non-negative also, so `1n ** -1n` gets you a RangeError. BigInt with a number input must be integral, so `BigInt(3.14)` gets you a RangeError. And as we discussed in the previous session, String normalize has just the four Unicode normalization forms, so `"ü".normalize("custom")` gets you a RangeError. I've maintained the pattern of documenting when guidance was established so that people don't complain if they find an existing part of the language that doesn't conform with it. I'm not interested at this time in strong enforcement, just documentation of the convention for going forward. And if there's anything recent that we want to revisit, that's out of scope for a pull request against how-we-work. With that I'm ready for the queue. + +RBR: I remember when I implemented the error types in Node. And I believe RangeError pretty much represents this already well. But for example the types I'm not sure and like TypeError was often used for let's say you would not have custom for normalize but you would have five. What would that be? + +RGN: According to these conventions that would still be a TypeError. + +RBR: All right. But then it's actually representing that as as far as I can tell. That was pretty much my question also if it but did you check how the ecosystem as a whole normally handles it mostly? Because I believe that is pretty much also that as such. + +RGN: How would you scope the term “ecosystem” in that context? WebIDL definitely collapses a whole lot of stuff into TypeError that ECMA-262 does not, for instance, which motivated `Iterator.zip` handling. ECMA-262 is not even itself fully consistent, even in the old stuff. But this is attempting to match our intuitions in the room, plus what's already documented, plus a little bit of subjective analysis. I think Node.js is at least comparably consistent with this. And then on the web they've got a large collection of paradigms and errors reflected in what they consider legacy and what they don't. So it would be difficult to derive principles from that or or really measure any particular specification against it, given how much they carry around. And even there, a lot of them are a DOMException with a particular name rather than an instance of one of our native types. + +RPR: So we've got five minutes remaining and seven people on the queue. So let's try to be quick. Shane says 402 is self-consistent using RangeError for string enumerations I wouldn't support deviating from that convention for 402. Over to you WH. + +WH: Scroll back to the SyntaxError definition. I don't like this definition because it's gated on the cardinality of the set of valid input strings, which is the wrong thing to base this on. To give an example, the set of valid dates is far smaller than the set of non-negative BigInts, but a malformatted date should be a SyntaxError, whereas a negative BigInt should be a RangeError. So it's not the set cardinality—it's not how big the valid set is that matters. What matters is the syntactic complexity of the set. + +RGN: Okay. So you're just suggesting an alteration of this specific word from “large” to “complex”? + +WH: Yes. + +RGN: Okay. I'm fine with that. + +CDA: Jordan. + +JHD: Yeah. So first I want to preface by saying that when we're define when we're creating words that JavaScript developers are going to interact with we should make them match the definitions that JavaScript developers are most likely to assume. So if you're parsing a string that means the string has an expected format and if you do the wrong format that's a SyntaxError. That's how that's what syntax is. If you have an enumeration of options since we don't have an enum error and it's out of that range of enumerations then it's a RangeError just like 402 does. And if it's not the right type using the definition that JavaScript developers will use which is typeof modulo null then it's a type error and it seems pretty straightforward to me. So I haven't reviewed the PR of course in the specific wording but I'm I haven't heard any convincing arguments for not necessarily phrasing it the way I'm phrasing it but for of wildly different approach. So I think I generally like your PR but I have to look at it first. + +RGN: Okay. Great. + +RPR: Michael says what does valid inputs mean? + +RGN: Okay. This is something that we could clarify if need be, or we could use alternate wording. As I have it here it is precise in a way that is encountered elsewhere, in particular I think Unicode do a good job of defining well-formedness and validity, where the former is a syntactic match and the latter means it is fit for purpose. + +RPR: One minute remaining. Please be really quick Michael. + +MF: I just want to acknowledge that this PR was opened very recently. I don't personally have a problem with the first of these two on such short notice but I think the second of the two I'm going to need a little bit more time to consider. Not that I'm opposed or anything, just that—even tomorrow I could reconsider that but I had no notice of this. + +RGN: What I'm looking for here is agreement in principle. I'm not asking anyone to push the merge button right now. I just want to know if it is directionally correct or if people have relevant tweaks. WH’s feedback was exactly the kind of thing that I was hoping to receive. + +RPR: We are at time. And I think we should proceed to the break. RGN are you okay writing the summary of what we've got to? + +RGN: Yeah. + +RPR: And the queue is also captured as part of TCQ so that can get copied into the notes. + +### Speaker's Summary of Key Points + +* Per the temperature check onh 29 September, [tc39/how-we-work#176](https://github.com/tc39/how-we-work/pull/176) specifies when to use SyntaxError, and a general pattern along with four specific cases for when to use RangeError except where already covered by SyntaxError (bounded numeric intervals, half-bounded numeric intervals, non-contiguous subsets of numeric intervals, and string enumerations). + +### Conclusion + +* [tc39/how-we-work#176](https://github.com/tc39/how-we-work/pull/176) remains open, along with a narrower [tc39/how-we-work#177](https://github.com/tc39/how-we-work/pull/177) that only specifies RangeError for numeric intervals + +## Normative: Change KeptAlive semantics to strongify particular WeakRefs + +Presenter: Keith Miller (KM) + +* [proposal](https://github.com/tc39/ecma262/pull/3974) +* No slides presented + +CDA: All right. People in the room? Please be seated. Please disperse. People in the room. We are getting started. Please take your seats. Michael, Leah, Shane, Andrew, Ashley, Ross, please be seated or at least be quiet. We begin, of course, with the call for note-takers. Who is willing to help take notes for the final one hour and 40 minutes of today's meeting? Thank you, CHU. Can we get one more individual? To help with the notes. Once we have a volunteer. We can get started. Our first topic will be KM with: [Normative: Change KeptAlive semantics to strongify particular WeakRefs](https://github.com/tc39/ecma262/pull/3974). + +CDA: Okay. + +CDA: But we no. + +CDA: That is eligible on the room screen. + +CDA: Oh, yeah. That is the problem. We do need we still need somebody to volunteer to help with the notes. + +CDA: One individual. To help with maybe somebody that hasn't helped at this meeting yet. Could be JHD. I don't know. But we do need somebody. So the notes can be accurate. You will be making small corrections. And doing attributions. Sorry. What? Oh, thank you so much. The screen looks somewhat clearer. + +CDA: It's still kind of blurry. + +KM: I guess this is the biggest downside of not making slides. Apparently, that I was not actually prepared for. + +CDA: Oh, clear. Clear. + +KM: Oh, okay. That seems fine. Okay. Great. I'll start then. Okay. So as a summary, WeakRefs are a feature that we had during the WeakRefs discussion, there was a lot of talk about keeping a lot keep alive semantics. The goal of the keep alive semantics is that within a synchronous execution, when you look at a WeakRef, you will forever be and you see an object come out, you will still continue to see the object as repeated anytime you ask again, you deref that same weak the WeakRef. There was during the many parts of this discussion, there was it was I guess we never really discussed how multiple WeakRefs should interact during the period. I looked through the notes. I couldn't find anything. As a result, the current specification says that if you deref a WeakRef, any other WeakRef that points to that same target must forever and always return back that object to you. This makes it very hard for engines to ever actually collect any objects in the same turn. As a result, engines other than JSC who implements a slightly more who already implements this proposal. We already implemented this proposal. If you keep creating WeakRefs in a loop in the same turn, you will eventually oom and your page will die. + +KM: This is good example. Describing this. Down here. Keep scrolling. Keep scrolling. Keep scrolling. It's a lot harder to find this now. And I don't have a thing. So I think there's like a relatively straightforward explanation for why this happens. Of the three properties on the screen, you can only have two of them basically. You either cannot oom you can have you don't you can choose to not have WeakRefs inherently guarantee derefing one WeakRef inherently guarantee another WeakRef returns you the value. Or the garbage collector cannot make like local decisions in the in its garbage collection process. And what I mean by local decisions is that it cannot depend on what other objects did other objects that are no longer live in that same cycle. I think to see this, you can look at this example here. So you have this turn. You make these WeakRefs. You then turn you do do a turn of the event loop. You do a WeakRef deref and then discard that WeakRef and you deref another WeakRef without run A. When you collect the you don't have line one. Then you the target is dead before you do the WeakRef. And so you can you can return undefined. In run B, if you do have the WeakRef, at the GC point right here, the reachable heap is identical to the run A. But the semantics are different. So the only way you can know is through some other data outside of what the local heap is telling you. So in order to rule out also, I guess there's going to be specific about the three parts. + +KM: So if there are questions in here and this is unclear, please ask me. Now, I guess I'd like to be interrupted. Also, because I expect that I'll have to come back anyway. + +KM: So there needs to be some external state that the GC is aware of when it's doing things. And that GC state to rule out B, you have to leave a keyed target around somewhere and then find it. Yeah. The there is an alternative in theory, which is that every object that the GC allocates has some state in it to observe that it has been a target of a WeakRef deref. And when the GC sees a WeakRef, it looks at the target of that WeakRef and sees that it's been derefed and then marks it strongly. That would be we no engine would do this because there's no space to actually record that information on the actual object as the target of a WeakRef itself. And we certainly would not want to that would be very unpay as you go for the WeakRefs proposal as a whole. So we don't want to do that. So this proposal changes the semantics of WeakRef so that when you deref a WeakRef, as long as there's some hypothetical execution, where you could deref that same WeakRef, you will you will you will get as long as there's some hypothetical execution where you could deref the WeakRef you already deref derefed, you will keep the object alive otherwise you will not. The in the spec language here, basically how what this change does is you there's this keep alive list instead of holding the keep alive list instead of holding the targets of the objects. It holds the WeakRefs themselves. And this is effectively a weak list. A weak hash set of the weak refs you derefed. And then when deciding if it's possible, we do a hypothetical execution. We see that when doing when trying to this object is the set of objects you're attempting to collect. If you if the set of objects that you want to collect if the if this weak ref targets that object, then it returns the object. This solves the constraint of the fact that you don't have to look outside of your local heap anymore. To determine if an object is live. Are there questions at this point? It's definitely want to answer those before going on to other + +KM: I mean, maybe I misunderstood, but the three things that are like mutually exclusive. They're not mutually exclusive. You can have two of them. Oh, yeah. Where you can have two of them. I mean, I I think there are strategies where you basically but I think you need two GCs. I think that's the other tradeoff that you can do. You can say like first I collect the first I collect the weak references and then that allows me to mark the the targets which are now no longer reachable by these weak references and then in the second GC I will collect these objects. That might violate one of your three things. That's probably true, but I think that also then it is still sort of unimplementable. I have to think about the exact semantics of how that would work. In detail. + +CDA: MAH. + +MAH: Sorry. I was muted. Regarding the two GC step, that sounds risky. I think there's probably a way to create cycles that would no longer be collectible in that case. But at least if it was derefed; I guess that's not worse than the leap that you have right now anyway. So it would be weird to just enshrine well, I don't know. Yeah. Sorry. I was just reacting to the two-step comments that Oli made because whenever I hear two-step with GC, that means there's a cycle somewhere that's not going to get collected. + +KM: Yeah. That might be. That's probably true. That sounds suspicious. Yeah. So I think before going on to any more details of it, oh, is there sorry, do you have a question? + +MAH: Yeah. I had another topic. Which was that the original example at the very beginning and and I think you got to it after with your two out of three, that it it doesn't require to not be collectible because to be clear, the fact that WeakRef puts the targets in in the keep alive does not mean that the the target cannot be collected. It just means that it needs to remain observable through WeakRefs that have that target. So in this case, V8 does not have to have a noom???. It just means it needs to remain observable through the weak ref. But if the WeakRef gets collected or in this case, all WeakRef targeting that object gets collected, then they can all be collected together. + +KM: Correct. But yeah, as I said, that leads to the third point of the complexity and the garbage collector. Yeah. So I think we're in agreement there. I think to make it maybe an example of how this changes behaviour, maybe helpful. So this program here you have a target. You have two different WeakRefs. When the second WeakRef derefs in in the original code, you must always return target. In this case, like let me scroll. Now you can also return undefined because and essentially the way to think about what this change is doing is it's turning when you deref a WeakRef, you are turning that WeakRef into just basically an ordinary property on any other object in the implementation. + +\[looking up the right parts] + +KM: Essentially, in these programs, you can replace, here's a different example. The you can replace essentially this WeakRef deref with the target the underlying tar a reference to the target in your scope and the programs behaviour is identical. You have all the same nondeterminism that you would have with an ordinary property within a single turn of a WeakRef deref. And so yeah, does that make sense? So I have questions there. + +CDA: Sorry. There's been a request from the note helpers to please leave a little bit of a pause in between responding to each other so they can properly attribute. Thank you. MAH. + +MAH: You can mention this would not be acceptable, but I actually do not understand why when you make an object the target of a weak ref, why cannot there be a flag or whatever an expando or whatever you want to call it added to that object to be able to do it as bookkeeping. Okay, I have been derefed or not. And even backlinks into all the weak ref instances that have it as target so that internally you can actually track which ones are collected or not. + +KM: The answer is basically the same. + +MAH: Basically make it local. Sorry. + +KM: I'm sorry. I'll wait for the note takers to. The answer is like it at least in JSC, and I imagine in other engines, there are no free bits to be used for this. So you would have to have something on the you'd have to have some other global table to find what the state of this bit is, and then at that point, you might as well look at the keep alive table. + +MAH: My understanding is that okay, that's something I don't understand, I guess, about engines is that you already have mechanisms to be able to extend existing objects you need to be able to have properties or stem private fields or or anything like that. Why is that system any different here? + +KM: You would have so you're saying basically anytime you do a WeakRef deref internally in the engine, you stamp an invisible private field into the object. + +MAH: No. + +KM: And then? + +MAH: I did not say that. I said whenever an object becomes the first time the target of a weak ref. + +KM: Sure. But then you'd have to remove that field whenever you clear the keep alive list. + +MAH: No. Yeah. You're right. ThatThat becomes part of the keep alive list. You just don't clear the field. You just yeah, you clear the field. You leave the field installed. You just clear it. ThatThat is actually what the keep alive would do. + +CDA: There's a reply from Mark. + +MM: Yeah. I think there are a zillion ways to approach the implementation that's not substantially complicated. Preserves the current spec and collects kept alive objects where the collection is not observable observable collection. And just the current spec, the spec only traffics an observable differences. So it was always the case that implementations were free to collect it if the collection could not be observed. So for example, just take MAH's suggestion instead of putting a flag on the target object, have a keep alive table that's a hidden WeakMap in the implementation that just marks that a target is kept alive and then the garbage collector when it sees a WeakRef pointing at a target that's in that table treats the weak ref as strongly pointing at the target. And you know, that's not that complicated. And it might not fit particular implementations, but you know, tell me the implementation and we'll come up with a fairly simple way to do this. + +KM: If the keep alive list is a weak set, you get the behaviour of this proposal. + +MAH: Yeah. + +No, no. + +MAH: Mark, the difference there is that they all. + +MM: You get the behaviour of this proposal. Go ahead. + +CDA: Let's please use the queue. + +MAH: Yeah. Sorry. So I'll answer Mark. The thing is that all weak ref have to keep derefing. So effectively, if it's like all weak ref are pointing to a single weak. + +MAH: Let me okay. + +MM: Okay. So I think you didn't understand my suggestion. Everytime when the garbage collector traces a WeakRef, it checks if the target is in the WeakSet, the kept alive WeakSet. So it's it's it can be put into that weak set weak set because of a deref through a different weak ref. But once it's in that set, then all weak refs to it are treated by the garbage collector as strong for the rest of the term. + +KM: That's not legal. + +?? Right. + +?? All weak refs. + +KM: That violates the locality constraint because you have to look in a shared global table during your GC, which is not local to the live objects. Like, the locality is that your GC is able to, the reason why garbage collection works relatively well is that when you garbage collect, you only have to care about the particular object that you're looking at. You don't have to care about the state of other random objects in the heap to know how to scan the object that you're you're you're you're marking. And in your proposal, while you're marking, you have to then go look at some global table. + +MM: No, you're yes. But only when you're marking through a weak ref. But I I but yes, it's non-local for when the garbage. Traces through a WeakRef, but the is the time for the garbage collector to trace through a weak ref a significant concern where this additional where this particular non-locality would be a speed concern? + +KM: To be clear, the—yes, I don't think we would have I when I discussed with the champions of weak refs, basically, I asked if the optimization I was doing is correct. And at that time, the belief was that they were actually identical. + +MM: Hold on. Hold on. Hold on. + +KM: So I don't think we want— + +MM: Hold on. One of the champions of weak refs were myself and DT. + +KM: I spoke with a different champion at some point. Or certainly, yeah, I think I definitely remember distinctly asking someone if this optimization was valid. + +MM: Okay. So I will say, as a champion who constructed the spec with the particular controversial semantics that we're discussing, that yes, this optimization is not valid. + +KM: I don't want to say because I asked about this, and the whole reason I implemented it this way was because I was under a belief this was a bug. And so I think this behaviour is also inconsistent with the decision that we made for the finalization registry. Finalization registry does not require that you run the finalizers after the finalization registry itself is dead. + +MM: That is correct. What's the inconsistency there? + +KM: The inconsistency is that. + +MM: The finalizing is only the kept alive thing is only about the turn that you're in. The kept alive thing goes completely away once the turn is over. + +KM: That's what I'm saying, that, the requirement that the GC be aware of, engines opposed to having FinalizationRegistry is before to call callback on finalization registries that were dead for the exact same argument of it requires the GC to make non-local decisions. + +CDA: There's a clarifying question from MAH. + +MAH: Yeah. No, it was clarifying what Mark was saying earlier. I don't mind getting to it earlier. Let me just answer this one first. I actually believe I brought up the question of whether it's okay. I mean, I don't want to say that strongly. I do remember that discussion. I don't remember the justification being a local concern. But yeah. Okay. Yeah. So I just wanted to clarify to Mark the WeakMap issue. If a WeakRef. If it is deferred, all WeakRef must be collected before the target must be collectible for the target to be eligible for collection. That means effectively, when you deref one WeakRef, you need to go and add all the WeakRef instances that point to that target to that hidden WeakMap. + +MM: Right. And without backward pointers, the idea is instead you just mark the target. You can do it with some kind of hidden field on the object if that's acceptable to the implementation, like you suggested, or we and and the only reason I suggested a WeakSet is it's the way to mark an object without changing the representation of the object itself. But then you have to treat all WeakRefs that point to a marked target. And that gives you the collective the unobservable collectibility, and it maintains conformance to the existing spec. Keith, I got to say, process-wise, I'm very concerned that you thought you had talked to the champions. I believe there was a third champion. But they confirmed it. But you didn't talk to the champion who was responsible for putting the semantics in. + +KM: I maybe I'm misremembering, but anyway, I think also, another point to make clear here, right, is that you can still totally observe a collection mid-cycle. Right? + +MM: Yes. You can. And we are just. + +KM: So this does not give you a new capability that you couldn't do before. It also doesn't give you unlimited chances at detecting that collection, right, because the only way you could do so is through multiple. + +MM: Okay. + +KM: Are there many WeakRefs, and you can't make them in the same turn because they will then pin the object? So you'd have to preemptively create all of the chances that you want to detect this. + +MM: Right. So the way I got to this semantics was I you know, I knew that ideally, what I would like is that garbage collection cannot be observed to happen within a turn and I quickly convinced myself that there was no practical way to do that. So I gave up on that as a goal. So with that being given up on, it was—how much can I mitigate the hazard that I cannot get rid of? And the hazard is essentially the multi-threading hazard. We all know that if you have two threads that are synchronously accessing common mutable state, you have a nightmare. You have a Java-sized nightmare. And that if we introduce WeakRefs without some protection, then the interleaving, the observable interleaving of garbage collection with what is happening within a turn means that a turn is no longer an atomic unit of computation. It means that you've got interleaving within a turn rather than just interleaving of turns. So like I said, I can't get all the way to atomicity, can't remove the interleaving hazard. But the practical cases we were able to I mean, the as we imagine cases and try to imagine what could users run into, and it's very much a what could users run into without thinking about it. This is the kind of hazard where you're just innocently coding with WeakRefs, and something surprises you. And seeing that it's dereferencing it from a WeakRef and then observably having it go away later spontaneously and non-deterministically inside the same turn seemed like the greater hazard. There's a bigger issue now, though, which Keith, you specifically, should have some sympathy with, which is the spec has been promising this strong constraint. There might very well be programs out there that are currently correct because they are assuming the strong constraint that the spec promised. If you weaken the spec in this way, you potentially turn existing correct programs into incorrect programs that might misbehave even though when they were written, they were correct. And in this case, I don't think there's any plausible instrumentation that browsers can do to detect whether or not there are such programs out there. So once TC39 commits to there being an invariant that programmers can count on for correctness, woe is us if we ever try to withdraw that guarantee. That's a breaking the web kind of problem. + +KM: To be clear, the behaviour that is in this proposal is what Safari has implemented since day one. + +MM: Yes. And therefore, you can say anything that works correctly on Safari does not count on this behaviour. I'm sympathetic to that with regard to browsers, however, there is node and node is part of the web. It's not part of the browser side of the web, but it's part of the web. Breaking correct node programs I would still say is breaking the web. + +KM: I don't know. I think there's—I mean, I was also an equal chance that, I don't think RM we would ever implement we we would go back to basically the same position that, in Spider-Monkey are in, where they basically just oom. And that might break users of our applications. So I don't know. Like, there's an equal compatibility risk in the other direction. + +MM: Okay. + +KM: Like, for synchronous code. + +MM: Okay. Given that you know, given my belief that it's easy to do an implementation that doesn't oom (out-of-memory) and doesn't weaken the current guarantees, I would hope to talk you into that. But if I'm given a choice, between oom or weakening invariants that protect you from fine-grained interleaving, I would prefer to oom. + +CDA: There's a reply from MAH. + +MAH: Mari Kurodi (???) made my point that there is something you cannot re-measure, and this is where I believe you're going to have most of the problems, actually, if you change this behaviour is with applications on node. I highly doubt that a lot of web applications are actually reliant on on WeakRef finalization registry like that. But I would expect server code to be a lot more. + +KM: I mean, I think as a practical point, it seems incredibly dubious and hard to reason about code that has multiple WeakRefs pointing at the same target, generally, just from, a large application perspective. Like, it would be relatively straightforward to end up with a different like, if I were if I expected them to point to the same target, I would just reuse the same target. If I would sorry, I would reuse the same WeakRef. + +MM: I'm sorry. I should correct myself. + +CDA: Go ahead, Mark. + +MM: Okay. That's the whole point of the existing semantics with the strong guarantee, is you don't have to reason about multiple WeakRefs to the same target because they do they they they act identically to a single WeakRef to the target with regard to this issue. Under your weakening of the invariants, now suddenly application programmers do need to reason about multiple WeakRefs to the same target because they don't they don't act equivalently to a single one. + +KM: Well, I mean, is the actual in your program, assuming you're using WeakRefs widely, actually being confident that two independent WeakRefs point to the same target, is probably fraught with error to begin with. + +MM: When does the programmer need to be confident that they do? The point here is that there's all sorts of ways in which programs come to be dependent on invariants that enable them to avoid thinking about something. And I think this is one. And under your weakening, suddenly things they didn't need to think about before, they now do need to think about in order to stay correct. + +KM: But those are the same things they have to think about just with regular references and the WeakRef. + +MM: How? + +KM: I mean, you could drop your target before you deref the WeakRef the first time and expect it to be not empty, and then you would observe that it got collected. + +MM: That is correct. And that's the thing I started with, which is we were not able to fully protect against interleaving hazards, but we did what we could. And we did guarantee this. And I think it is helpful. And but none of us can actually tell by any test we know how to write how many programs out there count on this guarantee. So without being able to measure that at all and having the consequence be that correct programs start failing in ways that they can't figure out why they're failing, and it's we just induced you know, random failures that that we might not even not might not even ever understand were caused by us, this is just an unacceptable weakening of a guarantee that we made. + +CDA: Just a quick note. There's about 10 minutes left. There's nothing else on the queue. Keith? + +KM: I'm trying to think of an answer that would be compelling. I mean, I think we change things all the time that our theoretically semantics breaking. So I don't mean, I'm not. Totally convinced that this isn't different. + +MM: Okay. When we do. + +KM: I think also. + +MM: I think that's semantics breaking. We generally do it either with instrumentation or with counting on the fact that if things get broken, it'll be obvious enough that we end up hearing about it and can deal with the fallout. That happened, for example, when the issue about invoking two-value on a null this for uniformity used to throw, and that throw broke something and breaking something that used to not break is visible enough that we heard about it and were able to take corrective actions. There's been a number of those. Tell me some things where we introduce something that was breaking in theory for which the breakage might not be detected or reported to us, and it's not something we can instrument for. + +KM: I mean, I've definitely seen bug reports. I don't have them on hand where we have made a change and it happened on a small enough site that no one noticed it until after the version had shipped. And we just decided to not fix it. + +MM: I'm sorry. Say that again? + +KM: We have made changes where in the process of releasing some version of the browser, the breakage happened on a small enough site that no one happened to notice prior to shipping, and then we got a bug report, three months, six months later, after shipping, saying we broke some page, and then just decided that that was the new web reality and it wasn't significant enough and it was a breaking change. + +MM: Are you so what are you suggesting for TC39 practices with regard to making breaking changes to the spec when the when the the when it very well might cause breakage of programs in the world that that are that whose whose root cause is sufficiently non-obvious that we never hear back and can never cope with the problem? + +KM: I mean, I think like I'm saying that already happens. + +MM: In in from, it happens in the TC 39 spec? + +KM: Yeah. I'm saying we make changes and then okay. + +MM: You're not, I thought you were talking about a just a change that was just made in your browser. As a peculiar. + +KM: I'm saying we tried to adopt some new TC that are in behaviour. Or consistency with other browsers. And then we find out that broke some page later, but we don't consider that a web incompatible change. + +MM: Okay. + +??: There's a. + +?? No, what it was. + +KM: I don't know offhand. + +CDA: JRL? + +JRL: Okay. + +JRL: I mean, to help Keith out, specifically here, we do make changes occasionally that are almost impossible to figure out the root cause of. An example is here of, we just discussed the intervals, which could have a change that breaks something. Unlikely, hopefully, because we're only exposing it to WebIDL. But we've made changes to Promise timing. And if you are independent on Promise timing at all, then it's going to be almost impossible to figure out why everything has changed. But we've still made that change. We also made a change to tag template literal caching semantics. So, I think we do occasionally make breaking changes. With the assumption that probably no one is depending on the semantic. + +MM: Okay. Those are—I agree with you. Those are valid examples. + +CDA: Nothing else on the queue. + +KM: I think so—I guess my question for you, MM, is given that other that information, is your concern that this is fundamentally the wrong behaviour still, or should we have a discussion offline or somewhere else to talk about it? + +MM: My concern is that it's fundamentally the wrong behaviour. The spec is as strong as it is on purpose with a lot of thought having been given to it by me in particular, but by several of us, and that's why the spec is as strong as it is. I think this weakening creates multi-threading concurrency style hazards that are not currently there. So, yes, I would object to any such weakening. + +KM: And I guess I would make a slightly other point, which is that even if this committee decides not to make this change, it does not mean that JavaScript programs will in effect be exposed to this behaviour. There's a discussion with WASM members, if there's ever a weakened WASM, I would expect it to basically have this behaviour. + +MM: WASM and JavaScript departed on many, many design issues from the beginning. In some sense, that was why WASM exists. + +CDA: There's a reply from Matthew. + +MAH: Just to comment, the example of Promise timing and so on is relevant of a technically Promise timing is deterministic here where here we're talking about making a change to expose a source of non-determinism more directly. I don't know. It's still relevant. I want to make sure we don't fully conflate like this is GC is really non-deterministic for all intents and purposes. So yeah, that is my main worry. + +MM: Yeah. And that's one of the reasons why concurrency bugs are so hard. Somebody experiences a problem, their program breaks, so they just test it rigorously and it never breaks under testing, and then it breaks in the field again, and they have no idea why. + +KM: I guess to be clear, I think a lot of those Promise concurrency ones, still would be incredibly hard to debug and understand why your program failed. And I do think that this class of bugs you already have to deal with when dealing with weak refs I agree. + +MM: We may. + +KM: I think you deal with it in the 99th percentile case all the time. Because it's through ordinary references. I I this class of the class of bugs that would be introduced by change relaxing this WeakRef behaviour here is is the class of bugs that you deal with in, the 99th percentile, which is through, I would assume in my expectation is that 99 percent of people using WeakRefs do not have multiple WeakRefs to the same target. And they have to deal with the fact that the more common problem is that you have a strong reference you have an ordinary reference to your WeakRef, and that you and and you have to make sure that that ordinary reference stays around in order to expect that you're your WeakRef deref still gives you back the object. Maybe 99th percentile is too strong, but the most common case is that you have an ordinary reference and a WeakRef, which has this exact behaviour. + +MM: So the question is, not percentile by how much the cases occur, but by how much it causes a counterintuitive consequence to the programmer. And it's a tricky one. And I'm not confident about the answer either. But I think we're in the kind of, you know, programmers writing programs naively in the sense of genuine multi-threaded concurrency hazards. And if we can't protect them from it completely, how much can we protect them from it? And does it make a difference? And does it make a difference is the thing where I'm just going you know, on intuition, you're just going on intuition. We have different intuitions. And I have no idea how to test either one. + +CDA: All right. We are pretty much at time. Doesn't sound like we will be reconciling this today. + +KM: Does not sound like it, indeed. I’ll have to come back. + +CDA: We can continue. + +KM: TBD. + +### Speaker's Summary of Key Points + +* The current spec requirements for WeakRefs make it difficult for engines to not leak WeakRef targets in a turn +* JSC always implemented a more relaxed requirement than the spec, relaxing should be web compatible +* Mark Miller stated this design was intentional, Keith needs to verify this from the notes on WeakRefs + +### Conclusion + +* No consensus today, will have to come back. + +## Include default in export * for stage 2 & 2.7 + +Presenter: Nicolò Ribaudo (NRO) + +* [proposal](https://github.com/tc39/proposal-export-star-default) +* [slides](https://docs.google.com/presentation/d/1jHiOZQCgz626zVcrIPqYjp_PtmGfPXqMkyVZMHZA4HU/) + +CDA: All right. Thank you. NRO, are you on the call? + +NRO: Yes. Hello. + +CDA: Hello. Can you speak again, which is so we can make sure we can hear you clearly? + +NRO: Yes. Is the audio good enough? + +CDA: Yes. It's great. + +NRO: Oh, okay. Perfect. Screenshot. So can you remind me which one of the two presentations is oh, yeah. This one. Okay. Can you see my screen? + +CDA: Yes. + +NRO: And okay. Just pull up the slides. Okay. So I'm presenting now this proposal that we first discussed in May. Well, it was first discussed ten years ago, and then again discussed in May. Which is to include the default export of a module in the bindings that are exposed through exports star from. So recap of why this proposal exists. Today, exports star from means that we are exporting everything from in this example, sudo.js except for the thing that is named default. That was designed together with the first iteration of ESM, and now we know how people actually use these declaration. + +NRO: There are two main use cases. One is aggregation of modules. So you have a library with multiple helpers to find in, groups grouped to different files. And you want to have an entry point that just re-exports everything from there. And then the other use case is a kind of a Proxy module, where you are just re-exporting everything from a module, potentially augmenting it. A common augmentations are, adding, for example, a version to it. Or when using ESM CDNs, you want to Proxy a module so that you can, change its URL without affecting web caches because the web integration of ESM does not follow redirects. And so there is this Proxy JS module needed in the middle. This is an example of a library having files that contain a bunch of things. It's an example for the code base. And as I mentioned, Proxy modules it's very widely used by ESM CDNs. So this clearly works. + +NRO: It has been used since when ESM was restricted. But it has some friction. Especially in the Proxy module use case, which is that the way you need to write a Proxy module depends on the module you're proxying. Because of this default restriction. So if in our case, the module that we are exporting from does have a default export, then we must have a separate export default declaration on it. However, that does not work if the module does not have a default export because then we're trying to export an existing binding, and so we get a SyntaxError. So you cannot just have a static plain Proxy module type of file. You need to always parse the module you're exporting to figure out what exports actually are. And this kind of removes the benefits of using exports because at that point, well, you could just manually list all the bindings. So what this proposal does is to change this current behaviour of exports star from to not have the exception for default. So exports would mean just re-export everything from [sudo.js](http://sudo.js). + +NRO: The main problem or main risk with this proposal is that there is a chance of compatibility problems. In most cases where you just get a default import from a module, it's fine. Because it just turns a syntax error of the missing export into a non-error if the default value actually gets propagated. The potentially risky one is when you import a namespace of your Proxy module. This Proxy module currently does not have a default. You might just record my check if there is a default in there. But then due to this change, your Proxy module starts actually having the default, and then maybe your code takes a different path. In practice, on the NPM ecosystem, it's never a problem to add exports to a module, but here. To be more careful because it's the web. We don't have server stuff. It is very common on NPM to check if a namespace has a default property. But it happens when integrating common JS and ESM due to how not JS does the documentation where it's slightly different from bundlers. So that does not happen on the web where we have no CommonJS. + +NRO: We started doing some web compact research. There is a Firefox implementation flagged that is actually pretty simple to do. It was done by Cornelius and internally earlier. Some of us at Igalia use Firefox, but Firefox nightly and have just been running with the flag on to see if anything would break. Only a small set of people, but we didn't find problems yet in the past months. There is also Chrome use counter that counts all web pages that access default on a module namespace that has no default export and that re-exports other modules through exports star from. This is overcounting. Because first of all, it does not check if the module re-exported through exports star from actually has a default. Because that would require it would have been a much much more complex counter to implement because it would have required, traverse in the module graph rather than just looking at one module. And also, it doesn't really tell us whether pages will break or not. It just tells us whether pages could potentially observe it. At the time I took that screenshot, the data we had was that usage was very low. But also, the flag had just been shipped for a month. + +NRO: The Chrome use counters have this very nice feature that they show samples of websites that use a given feature. So one can manually inspect them. Unfortunately, the usage of this feature is, I believe, too low. And so there are no actual websites to check. Like, to manually inspect. So that's for web compact. So we believe we are starting to have some evidence that this would probably be web compatible. Obviously, as the proposal evolves, it will need, like, a long time for it to actually collect more data, more evidence before then advancing maybe all the way to stage 4. Since last time, we now have fully rewritten spec text based on the latest edition of the spec. It's a very small spec text. It's basically what you see here on screen on screen. So removing the exceptions for default. There is a tiny other bit of editorial changes, renames. If you actually go look at the diff, but this is the only normative part. So I well, I would like to see if we have consensus for stage 2. With stage 2, in this case, I believe it means agreeing that our preferred solution is to extend existing syntax rather than what we consider during stage 1 presentation just simply go with something else. Obviously, we might discover later that, well, there is no way for us to actually reuse the same syntax. And so at that point, we can take that implementation / web reality feedback and go back to the drawing board. So let's go to the queue now. I see that RGN has submitted this RGN? + +RGN: Yeah. So in practical terms, backwards incompatibility is just uncomfortable aesthetically. The discrepancy between import and export is also a bit awkward. Have you looked at new syntax rather than changing the behaviour of existing syntax? + +NRO: Yes. One, for example, one of consider was to just export star star from. To, like, have well, new but similar looking syntax. And then the idea would be that, this old syntax would basically kind of be not deprecated, but would fall out of use and people would move to the new syntax. However, we expect the actual web compact risk to be so low that it doesn't feel like it's worth to introduce separate syntax just for this case. Because, remember, the only case that breaks is when somebody imports a namespace and checks properties of namespace, which is, like, and then branches depending on what property on what properties are there. Which is far from being the common ways that ESM is used. + +RGN: Right. I don't have firm articulation of why, but touching functionality that has already shipped is uncomfortable even when it's safe. I don't know that I want to block this; it just leaves a bad taste in my mouth. I think there's a later item about it as well. Just wanted to give that feedback. + +JRL: Yeah. So before we go on. There is a message directly from LVU in the message that directly relevant to the same topic. Her words: "This would be great if we were designing export star now, but in my opinion, it's too much of a breaking change to deploy today." I'd also suggest new syntax, possibly even something for a conditional re-exports in general export star default question mark. From `Foo`. So I think that is directly the same thing as what RGN is saying here. To reply to that, though, is actually me. + +JRL: Do we really expect anyone to break because of this? I think in the web ecosystem, I personally don't use export star frequently. And in general, most people avoid default exports. It's been really honed in that to everyone that you should really use named exports because they were more compatible back in the ES5 transition days. And they work better for renaming nowadays, just doing refactorings. I expect personally this web compact risk to be just absolutely minuscule. And I don't really expect anyone to break because of it. + +NRO: Yeah. Also, I want to add, if we stumble upon a web compact problem, then regardless of whether this is our preferred solution or not, we would probably need to, not do this. So, this proposal advancing is entirely based on the assumption that there will be no web compact problem. But then we will actually know before finalizing the proposal. And it happened multiple times that web compact problems were only discovered when one implementation actually tried to ship in nightly or canary. And I think this is one of those cases where it's very likely to be web compatible. But we will only actually know at that point. So the question is more, is it something where we as a committee are willing to take the risk? + +JRL: Okay. Up next, we have a new topic from hacks. + +JHX: Yeah. I still worry about that. I checked some old notes. Which discuss this and and I AWB and YK talk about and mention some refactor hazard of that. Unfortunately, there were not many details in the older notes. But I think we can explore the—can we ask them because I feel it's risky if we don't fully understand the older discussion. Thank you. + +NRO: Yeah. So I also did some research about the history of this proposal, given it was already presented a long time ago. And the refactoring that if you have a module that has a default export, and you have a separate module that does export star from that module and export star from from some other module, that module would do export star from will expose the default export. But then if the second module that you are doing that you are exporting everything from also adds a default export, that default export will not be exported by the module that proxying both of those. Because the way export star from works is that when you have multiple export star from declarations in the same file, and there is a conflict, it solves the conflict by, not picking either of the two possible things to re-export. This is not specific to default. This is something that happens in general with all also, with all other import names. It's just in for the timer. Actually, you have replied to this? + +JRL: Yeah. So we can skip mine. Four minutes. I think we'll get to the Q. As long as we don't dive too deeply. Ashley, you're up next. + +ACE: Yeah. Just for kind of repeating what NRO said. Like, the refactoring hazard here is no different the refactoring hazard with named exports. So it's I don't think I think we fully understand what was being raised and all the semantics here. And I don't think this is any if any new thing to be concerned about. + +JRL: Okay. And then we have a couple of go ahead. + +NRO: Yeah. The things we have are some support in the queue. EOMs. So just to, like, restate it, I think it's clear like, the risks are clear to the committee. And so now the question with advancement is whether we are comfortable with those risks or not. So do we have consensus here for stage two? + +JRL: Okay. So you have a couple of strong supports, one from ACE, one from CHU, CDA, MF, I don't know about RBR yet. He's still typing. You have some from myself as well. Is there anyone that blocks stage two advancement? Okay. I think we can call it for stage two. + +CDA: I just want to interrupt real quick. Did we read ACEs comment for the notes? + +JRL: I did not. Sorry. I just read the strong support. So Ashley says NNTS, which I have no idea what that acronym means. + +CDA: No need to speak. + +JRL: Okay. EOM. Yes. Strong support. The chances of this breaking something are so small that I think the new syntax is far too cautious. New syntax should be reserved for only when we must have it. + +CDA: Okay. Now let us clap for stage two. + +Yeah. + +NRO: I can hear people clapping today. This is new. So I actually. And also interesting to see if we have consensus for stage 2.7. The reason so there is no reason for this proposal to advance fast. Because before being shipped, it needs to marinate. We need to have canary implementations to see if we can actually do it. We already selected reviewers for this during stage one because they've already actually reviewed the spec text. And from a process point of view, all of these stage 2.7 requirements as at this point are met. Because we have complete spec text, and the design space once we settle, trying to reuse the same syntax is basically nonexistent. The stage two reviewers were CLA Manga Bedford. And. + +JRL: Okay. So I think we qualify for stage two then as long as we have the full spec texts nailed down. We have stage two approval. I'm sorry. We have reviewer approval. Have the two reviewers approved the spec? + +NRO: Yes. I don't know if I have editors. I know of let me just check. Well, I checked if we have enough editors. Two people have comments about two things. + +JRL: Okay. + +JRL: Can we quickly get any support for stage 2.7? If not, we are running over the time box now. + +NRO: And yes, we have enough editors. + +JRL: Okay. NRO, change your hats and sorry. You got deleted. I can't read it now. No concerns. If entrance criteria met from CDA, MF says I support this to stage 2.7. So we have two supports, explicit supports. Does anyone object to stage 2.7? Okay. One clarifying question from CDA. Sorry. + +CDA: Sorry if I missed this. Do we have 262 tests? + +NRO: We don't have them, but that's for stage 3. + +CDA: Sorry. + +JRL: Yeah. So we just need reviewer approval and editor approval and concrete spec text. And then I think those are the only entrance criteria. And I think we've met all of that. So hearing no objections, I think you have stage 2.7. Congratulations. + +NRO: Thank you. And to be clear here, now I plan to slow down and let this marinate as we make sure it's compatible. + +JRL: All right. I'm going to pop this off the queue. And go on to the next agenda item. So Nicolo, get ready for export defer. + +NRO: Just give me just a second because people are complaining about my echo. So I'm going to try to, I don't know, move some curtains around and see if that helps. Okay. Okay. Can you see my screen? + +JRL: Yes. + +JRL: I cannot hear you speaking now. + +### Speaker's Summary of Key Points + +* The proposal changes `export * from` to also propagate the default export, to simplify modules aggregation and proxy modules. +* Use counter in V8 and flagged impl in Firefox, no obvious web compat problems +* Discussed about the potential refactoring hazard of propagating default: adding a default export to a module re-exported through `export * from` will be a breaking change if a sibling `export * from` already exposes a default export. +* The proposal already has spec text written +* Stage 2.7 reviewers were selected during Stage 1 and already reviewed it + +### Conclusion + +* The committee considers the refactoring hazard and the web compat risk low enough that the proposal is overall worth it +* “Include default in export *” has Consensus for both Stage 2 and Stage 2.7 + +## 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/1M_5zKVnyzCrPdxFnMSQrOwiyRX-p9t0Nt8S4Osx55a0/) + +NRO: Oh, okay. Okay. So another modus operandi proposal. Deferred exports for stage 2.7. + +NRO: So recap, I assume you all remember what the proposal is. But just in case, recap of the motivation. That had this proposal get approved for stage two. Consents for stage two. Which is that a common practice in ESM libraries is to have an entry point that has a bunch of re-exports. Especially for things like component libraries, utility libraries, where they have many different things. And libraries prefer from a DX perspective this approach compared to having many entrypoints, one for utility asking people to just start to import from the right entry point. And the way they do this is they probably still have set multiple files internally within the library. It just makes more sense from a code organization and maintenance perspective. But then they all have an entry point that re-exports all of those things from all of these files. It has, however, a big problem which is that it causes a lot of unnecessary code loading and execution. + +NRO: So because, from the slide before, maybe you just need, like, the add function. You import the add function from that file. And it's coming together with all of the other utilities exported by that library. Different tools, bundlers, have occurrence for this. They all implement re-shaking. They try to remove code that can prove isn't used and set effort free. But it still has its limitations, which is why it's frequently recommended to actually not use libraries like that. Because it is just not possible to know whether something is fully safe to remove or not. However, DX benefits are so large. Frequently, even ignore this recommendation. Or, not everybody agrees with this recommendation because not everybody agrees with the trade-off between DX and the problem of the X code. So the goal of this proposal is to allow developers to keep choosing this good DX pattern where you import your utilities from your one library entry point. But without forcing them to pay for this extra unnecessary code cost. + +NRO: So what the proposal does is that it takes this example of a library entry point and it allows marking export statements as deferred. Where deferred means in this case, well, let the importer choose whether this re-export they have is actually something needs to be to be, fetched and processed or not. So in this case, if I import only add from this library, I will completely skip loading execution of all of these other utilities. + +NRO: The proposal integrates with import defer. It was actually born as part of import defer, but then it was split off because of the extra complexity and extra power of also having, like, big loading implications other than just execution implications. So import defer just lets you defer the execution of part of your module three while preloading it. It is used for things that you need you will know. + +NRO: But maybe not right away. And where there is too high friction to adopt dynamic import in your code base. For reasons. And so you tend to prefer eager loading just because you cannot migrate and import defer gives you a middle ground solution here. That's, like, matches if adopt even though it's not as powerful as dynamic import. Export defer gives you granular control over that. So instead of the importer just saying it has to have this whole chunk of modules, export defer lets libraries further separate their own subgraphs. And as I mentioned before, it allows when a module is not imported in any way, so when it's not imported through a namespace or through plain, a plain import where you list the bindings, it will completely skip loading, which is something that import defer cannot support. + +NRO: The proposals are meant to both be used; neither is a replacement for the other. Library authors should use export defer when re-exporting something that the consumer might not need. To not force their consumer to load that potentially useless code. And consumers should use import defer when they're detecting that they're loading something that they do need, but who is execution as part of the initial ESM evaluation time is causing some performance problems. There have been some changes since the last update. We discussed in many presentations already filter namespaces. That was solving an incompatibility between namespace imports, which are required by import defer, and export defer. + +NRO: Following the various discussions we had, this is now merged in the proposal. We ended up picking a property name for how we call those filter namespaces in dynamic import. We need to choose the word that sounds like here, exports on screen, which is the list of names you're actually interested in. Thanks to all of those that participated in the polls, you can see here the results on screen. The reason we ended up picking exports was not necessarily because it was the most loved option. But because of the options that people liked, it was the least disliked one. For example, you can see that, select had actually more excellent votes. But there were more people finding it bad. Some people suggested only after the poll was opened. So thank you for that. Maybe leave the votes that only would have gotten if it was slightly higher if it was introduced in the beginning would have been slightly higher. But also looking at, GitHub issue and trying to talk with people that I knew had filled the poll we ended up picking exports. And you can think of this as this is the list of exports of the module that I'm interested in. + +NRO: There are also some bug fixes when it comes to, like, that were found thanks to an engine XS implementation. Where we can, already try the proposal, try some draft tests we have, and make sure it works as we're expecting it to work. And finally, one large change done to the proposal in the past couple of months is to make sure it does not regress the goal of allowing exports from the abuse for Proxy modules. You might have noticed that a schedule constraint to have the export star from change before this presentation because I wanted to get confirmation from the committee that there's a good goal to follow. + +NRO: So before this change to export to the export defer proposal, an export star from declaration would cause all of the deferred re-exports of the module that it's proxying to be loaded. Because it was kind of equivalent to replacing the asterisk with a list of all the names exported from the module. So this is bad because the export star from basically makes the defer keyword in the proxyed module useless. So the proposal was changed to actually so that export star from checks whether they've exported bindings are eager or or deferred. And re-exports them appropriately. If you have followed the repository in the last week and a half, you might have seen that even though we're after the agenda deadline, there were a lot of PRs merged to mark as normative. There were all bug fixes that did not impact in any way the semantics that were ever discussed. For bugs found during this stage 2.7 reviews. + +NRO: Thank you a lot, especially GB and ACE for, making sure the proposal was in a very good state. And, these bug fixes were things like, oh, we have an infinite loop in one case. Or maybe somewhere we have an assertion where actually it should have been a, a thrown error. And things of that type. There have also been some editorial cleanups if you'd read the spec text. You might have seen it was introducing the concept of a binding that is initialized on access. It was there, kind of safe because it was side effect-free. But it was a little bit ugly. There were some concerns with that opening the door to in the future maybe binding access triggering side effects in places where it does not already do that. So we were a factor that away by using, like, existing spec concepts instead of modifying how bindings work. So yeah, that's it for my presentation. I would like to ask if there is consent for stage 2.7. I also have a statement from GB who unfortunately cannot be here. + +NRO: For context, GB blocked this proposal for stage 2.7 one year ago. Due to the incompatibility between export defer and namespace imports. So I'm just going to read it exactly the way he sent it to me. Which is the filter namespace design of the proposal integrates well with import defer, which was one of my main concerns with this specification before. I'm satisfied from my stage 2.7 review over the last weeks that the specification and design of the semantics is fully complete at this point. And all issues I raised during the process have now been resolved in the spec. I'm also excited to see it integrate with model declarations where I can naturally add a lot of value. Plus one for stage 2.7 progression for me. And yeah, that's it for me. Let's get to the queue. + +CDA: Yeah, I'm on the queue. So yeah, I know the goal of this proposal as stated is about DX. But I just wanted to point out we haven't really talked about the security benefits that we get from landing this. So I just think that's particularly understated. And I am looking forward to this proposal advancing further. Reason. And the DX reason as well. I'm also next on the queue. I guess I cannot say no need to speak while I am chairing. So plus one support. We desperately need this. And then Ashley is on the queue with plus one support. I wish ESM had worked this way from the start. Do we have any other feedback and/or support for stage 2.7? NRO, can you confirm the entrance criteria have been met? Reviewers signed off? Editors signed off? + +NRO: Okay, just reviewers signed off, and let's check again if the editor stayed. Which is fine. Same editor. I actually don't have him allowed to review my own proposals. + +CDA: While you were double-checking, CHU, supports as well as LEK, RPR, and RG. + +NRO: Yeah, editor signed off. So I guess this will be conditional on editor sign-off. I can say I obviously since I became an editor and learned all of those things, reviewed the proposal, also from an editor perspective. But I think we need also a second editor. + +CDA: Yeah, I don't think the editor can just rubber-stamp their own specs. + +NRO: Yeah. So this will be 2.7 conditional on editor review. + +CDA: Are we comfortable with that, committee folks? I see one thumbs up from MF, thumbs up from PKA, thumbs up from RG. Okay. We'll call it conditional 2.7 unless there are any objections. All right. Do you have 2.7? + +NRO: I think so. + +CDA: There was there was quiet. + +NRO: I cannot hear it. + +CDA: Okay. Well, I muted the microphone. Hang on. Let's try it again. + +NRO: I can see but I can still not hear it. Nice cancellation is still good. + +### Speaker's Summary of Key Points + +* The proposal now integrated the `{ a, b } as ns` “filtered namespace” syntax, discussed in previous plenaries +* We had a poll among delegates to express opinions on option names for the dynamic import variant of `{ a, b } as ns`, to be used as `import(…, {