diff --git a/meetings/2019-12/december-4.md b/meetings/2019-12/december-4.md index 8705f3f1..d3e92812 100644 --- a/meetings/2019-12/december-4.md +++ b/meetings/2019-12/december-4.md @@ -1,7 +1,7 @@ # December 4, 2019 Meeting Notes ----- -Brian Terlson (BT), Aki Rose (AKI), Daniel Rosenwasser (DRR), Shelley Vohr (SVR), Michael Saboff (MLS), Yulia Startsev (YSV), Ross Kirsling (RKG), Waldemar Horwat (WH), Chip Morningstar (CM), Rob Palmer (RPR), Shane Carr (SFC), Jordan Harband (JHD), Kevin Gibbons (KG), Sebastian Markbage (SM), Tierney Cyren (TCN), Damien Engels (DES), Caio Lima (CLA), Alan Schmitt (AS), Tab Atkins (TAB), Shu-yu Guo (SYG), Justin Ridgewell (JRL), Till Schneidereit (TST), Michael Ficarra (MF), Pieter Ouwerkerk (POK), Zibi Braniecki (ZB), Hemanth HM (HHM), Dan Finlay (DJF), Benjamin Coe (BCE?), Chris Hewell Garrett (CHG), Gabriel McAdams (GMS), Valerie Young (VYG), Tantek Çelik (TEK) +Brian Terlson (BT), Aki Rose (AKI), Daniel Rosenwasser (DRR), Shelley Vohr (SVR), Michael Saboff (MLS), Yulia Startsev (YSV), Ross Kirsling (RKG), Waldemar Horwat (WH), Chip Morningstar (CM), Rob Palmer (RPR), Shane Carr (SFC), Jordan Harband (JHD), Kevin Gibbons (KG), Sebastian Markbage (SM), Tierney Cyren (TCN), Damien Engels (DES), Caio Lima (CLA), Alan Schmitt (AS), Tab Atkins (TAB), Shu-yu Guo (SYG), Justin Ridgewell (JRL), Till Schneidereit (TST), Michael Ficarra (MF), Pieter Ouwerkerk (POK), Zibi Braniecki (ZB), Hemanth HM (HHM), Dan Finlay (DJF), Benjamin Coe (BCE?), Kristen Hewell Garrett (KHG), Gabriel McAdams (GMS), Valerie Young (VYG), Tantek Çelik (TEK) Remote: István Sebestyén (IS), Bradley Farias (BFS), John Hax (JHX), Caridy Patiño (CP), Daniel Ehrenberg (DE), Erica Pramer (EPR), Mike Samuel (MSL), Richard Gibson (RGN), Ron Buckton (RBN), Mathias Bynens (MB), d2g, Ujjwal Sharma, Jonathan Keslin (JKN), Ben Newman (BN), Sergey Rubanov (SRV), Mark S. Miller (MM) diff --git a/meetings/2020-06/june-2.md b/meetings/2020-06/june-2.md index cc470aae..1aa198cc 100644 --- a/meetings/2020-06/june-2.md +++ b/meetings/2020-06/june-2.md @@ -3,7 +3,7 @@ **In-person attendees:** (none) -**Remote attendees:** +**Remote attendees:** | Name | Abbreviation | Organization | | -------------------- | -------------- | ------------------ | | Yulia Startsev | YSV | Mozilla | @@ -19,7 +19,7 @@ | Rick Button | RBU | Bloomberg | | Jason Williams | JWS | Bloomberg | | Waldemar Horwat | WH | Google | -| Chris Hewell Garrett | CHG | LinkedIn | +| Kristen Hewell Garrett | KHG | LinkedIn | | Richard Gibson | RGN | OpenJS Foundation | | Bradford C. Smith | BSH | Google | | Shane F. Carr | SFC | Google | @@ -57,7 +57,7 @@ | Ron Buckton | RBN | Microsoft | ## Hallway track update -YSV: Online towns did not really work, there was another alternative, shane are you in the call? We can try that alternative or Mozilla Hubs today +YSV: Online towns did not really work, there was another alternative, shane are you in the call? We can try that alternative or Mozilla Hubs today SFC: A couple alternatives are posted on the GitHub issue on the Reflector. @@ -148,7 +148,7 @@ I was under the impression, seperate from my own intuition, that WebIDL processe So, my personal preference is that we prioritize what's observable to callers and not the implementation code that one might write to do it, but there are implementation concerns in general, but today it sounds like a priority of consistency question. -SYG: I think for users, my intuition is that keeping with the mental model that by the time the super constructor runs, it would have done its logic normally, it would have set the message. It is easier for the user to understand the current state. We might skip this logic in constructor ….??? +SYG: I think for users, my intuition is that keeping with the mental model that by the time the super constructor runs, it would have done its logic normally, it would have set the message. It is easier for the user to understand the current state. We might skip this logic in constructor ….??? SYG: I agree that it's edge casey. @@ -213,15 +213,15 @@ PFC: They don’t. Anything that could tell you about the current time or enviro KKL: Thank you, this answer is very satisfying. -JHD: Temporal is large, and the preference of the champions is often to merge PRs quickly and then continue iterating from there, which at least for me personally makes it really hard to keep up with all the changes. In order for there to be sufficient time to review, I would like to request that whenever you are ready to ask for stage 3, please give a significant period of time for us to review and announce it. +JHD: Temporal is large, and the preference of the champions is often to merge PRs quickly and then continue iterating from there, which at least for me personally makes it really hard to keep up with all the changes. In order for there to be sufficient time to review, I would like to request that whenever you are ready to ask for stage 3, please give a significant period of time for us to review and announce it. KG: And announce that you’re doing so. PFC: That's a good point. -JHD: For a normal proposal I’d say at least two months for review, but this is a very large proposal. We will need multiple meetings of time with it static in order to do a proper review. +JHD: For a normal proposal I’d say at least two months for review, but this is a very large proposal. We will need multiple meetings of time with it static in order to do a proper review. -PFC: That is good to know. What we intended to do between this week and stage 3, after incorporating feedback from users, was freeze the API and release a second version of the polyfill. So ideally by that time we’d have all of our provisional decisions revisited and addressed. +PFC: That is good to know. What we intended to do between this week and stage 3, after incorporating feedback from users, was freeze the API and release a second version of the polyfill. So ideally by that time we’d have all of our provisional decisions revisited and addressed. JHD: Hopefully that is the way it plays out. Sometimes issues are discovered by usage, some by review. And the kind that needs review to discover them, we need review to happen first in order to discover them. @@ -253,7 +253,7 @@ PFC: This seems like something we should talk about in an issue tracker thread. DE: I think it was interesting that PFC raised to the committee this question of the default calendar, and the initial decision to release the polyfill defaulting to the Gregorian calendar. Do people have thoughts about that? -TAB: As discussed in the delegates chat, I believe the Gregorian calendar is the right default here. You’re still interacting with the Gregorian calendar regardless of your locale. It is so strongly weighted that all usage will be Gregorian that we should keep that as the default. +TAB: As discussed in the delegates chat, I believe the Gregorian calendar is the right default here. You’re still interacting with the Gregorian calendar regardless of your locale. It is so strongly weighted that all usage will be Gregorian that we should keep that as the default. SFC: I would like more feedback from TAB and the committee on that. The options that I listed in the discussion thread, linked here in the slides, cover a very wide spectrum, from making the calendar always explicit, to only requiring it in a calendar-dependent operation. For example, adding a month is a calendar-dependent operation, but adding a day is not. Converting timezones is not a calendar dependent operation, etc. And for the small number of operations that are calendar-dependent, there are a number of options for what we could do in those specific cases but not have it be required by the rest of the API. What is your general feeling to have this as two levels, calendar dependent and calendar independent? @@ -358,14 +358,14 @@ MB: What do you think about the idea of doing what you were planning on doing, b MF: I would be fine with that. Thank you. Think we’re done with this topic. ## Decorators update -Presenter: Chris Garrett (CHG) +Presenter: Kristen Hewell Garrett (KHG) * [proposal](https://github.com/tc39/proposal-decorators) * [slides](https://slides.com/pzuraq/decorators-status-update-2020-06) -CHG: (presents slides) +KHG: (presents slides) -CHG: Decorators Design Space Analysis - https://docs.google.com/document/d/1DSuLlEbAjBImDutX_rhjnA6821EUyj9rANzDVJS3QV0 +KHG: Decorators Design Space Analysis - https://docs.google.com/document/d/1DSuLlEbAjBImDutX_rhjnA6821EUyj9rANzDVJS3QV0 Decorator Use Case Analysis - https://docs.google.com/spreadsheets/d/1QP0hfXkkkAXTktGrI7qrt-RUqKp2KtsVKuPo4yuoZZI/edit?ouid=115900510010132195082&usp=sheets_home&ths=true RPR: Empty queue, which is weird for decorators. @@ -475,7 +475,7 @@ BFS: There is precedent in nodejs of muting down our stacktraces when outputting MF: We mentioned in readme that devtools could default by hiding but would let you show them. It kind of acts as an opt-in to black-boxing directive in that way. -YSV: Cursory note: Mozilla is blocking this but, for anyone who isn’t familiar, the proposal is not rejected, as TC39 doesn’t have a model for rejecting. As such, I am open to discussing, and I will go to the library calls and listen to the library authors as requested. And maybe we will come out of this with a better solution, maybe with the same solution. +YSV: Cursory note: Mozilla is blocking this but, for anyone who isn’t familiar, the proposal is not rejected, as TC39 doesn’t have a model for rejecting. As such, I am open to discussing, and I will go to the library calls and listen to the library authors as requested. And maybe we will come out of this with a better solution, maybe with the same solution. MF: Takeaway is - I don’t have much for conclusion on my side. The feedback was kind of a backstepping from stage 2 where we were committing to a direction for the problem. So I will await feedback from Mozilla and Apple as to what they would like to do, otherwise I will feel kind of stalled. I will attend the library call and hear feedback there too. @@ -490,7 +490,7 @@ It might be a correctness problem, it might be an API abuse problem, but I would MLS: From JSC, I do not think that the security use case is valid. -LEO: Talking about the notes: I think for us to make it a following pattern for decision that tc39 makes, +LEO: Talking about the notes: I think for us to make it a following pattern for decision that tc39 makes, And not as YSV tried to say - it’s not blocking the actual proposal. Rather than creating a new pattern on how we distinguish thing here, we should be more clear in the notes that we are blocking the stage advancement, and not the proposal. Is that okay to say, YSV and MLS? YSV: Sorry I think I wasn’t clear. We don’t reject as a rule, we block. We can just say that it’s blocked from advancement. I know how much work this took, and I’m sorry for the surprise. @@ -567,7 +567,7 @@ SFC: If we have WH as a half reviewer and YSV as a half reviewer, maybe that’s DE: I have some idea for other people to recruit offline and if I can’t I will bring that up in next meeting -LEO: It’s definitely something where we can get reviewers from TG2, because not everyone from there is in this meeting. +LEO: It’s definitely something where we can get reviewers from TG2, because not everyone from there is in this meeting. SFC: Ok sounds good, I will reach out later in the summer when ready for stage 3 review. So for now there’s no work for those reviewers. @@ -606,7 +606,7 @@ DE: looking at localedata the other day, no locales have spaces around the numbe RKG: You had called out that certain fields in the API were still being discussed, but I wanted to ask about hiding zeros for leading or trailing or both or none, and it seems like if you’re going to cover all possibilities, why not have two booleans? Has that been discussed? -YMD: So the idea is that many people +YMD: So the idea is that many people People hide all of them or none, yes? @@ -704,7 +704,7 @@ DE: That’s good, I’m glad to hear that that’s not a blocker. I don’t lik JHD: On the slide where you have the table and say “why not”, I think it’s sort of a “must”, that if any of the Weak things accept or reject a value, then all the other Weak things should do the same. So if they are allowed as WeakMap keys, they must be allowed as WeakSet members and WeakRef targets. And registered vs unregistered Symbols, they would also have to be treated the same. Like however we treat registered and unregistered symbols has to be the same everywhere.Which dovetails into my next item which is about treating registered and unregistered the same everywhere. Even if Record and Tuple does not advance any further, There was a long thread on ecma262 on this a year ago where a bunch of folks wanted it but the main reasons that issue got closed were because MM insisted that registered symbols not be included, and I insisted that registered and unregistered symbols be treated the same. And that presented an intractable block. So if there’s no longer an obstacle to treating registered and unregistered symbols the same in that regard, then that could support moving this forward without tying it to Records and Tuples. -DE: Thanks for your comments. To be clear, the proposal here is yes for all 3: all symbols would be keys for all structures. I do not know whether I agree with this use of MUST. About the previous discussion, there is motivation, independent of Records and Tuples, for Symbols as weakmap keys. This one about records and tuples is super relevant to me now, but that doesn’t exclude that there’s other important motivations. +DE: Thanks for your comments. To be clear, the proposal here is yes for all 3: all symbols would be keys for all structures. I do not know whether I agree with this use of MUST. About the previous discussion, there is motivation, independent of Records and Tuples, for Symbols as weakmap keys. This one about records and tuples is super relevant to me now, but that doesn’t exclude that there’s other important motivations. AKI: Tension resolved? diff --git a/meetings/2020-07/july-21.md b/meetings/2020-07/july-21.md index 3409ea61..8527801a 100644 --- a/meetings/2020-07/july-21.md +++ b/meetings/2020-07/july-21.md @@ -1,10 +1,10 @@ # July 21, 2020 Meeting Notes ----- -**In-person attendees:** +**In-person attendees:** None :( -**Remote attendees:** +**Remote attendees:** | Name | Abbreviation | Organization | | -------------------- | -------------- | ------------------ | | Mathias Bynens | MB | Google | @@ -371,7 +371,7 @@ KM: WeakRefs landed in JSC! There are just some bugs to fix. DE/YSV: (presents slides) -MM: You’ve changed my mind. I originally was against splitting up cleanupSome because of the wasm use case. I like your rationale for why to postpone it. I'm wondering, with it postponed, we'll gain experience as to how well we can do without it. It may be one of those you-ain't-gonna-need-it (YAGNI) things, where we find that we don't need it in the end. So I would recommend bumping cleanupSome back to Stage 2, and even consider never advancing it if we consider that life is ok without it. I support advancing WeakRefs to Stage 4. Congratulations on changing my mind. +MM: You’ve changed my mind. I originally was against splitting up cleanupSome because of the wasm use case. I like your rationale for why to postpone it. I'm wondering, with it postponed, we'll gain experience as to how well we can do without it. It may be one of those you-ain't-gonna-need-it (YAGNI) things, where we find that we don't need it in the end. So I would recommend bumping cleanupSome back to Stage 2, and even consider never advancing it if we consider that life is ok without it. I support advancing WeakRefs to Stage 4. Congratulations on changing my mind. DE: Thank you MM. I want to point out that when we’re talking about the Wasm use case, the use case for cleanupSome is really particular to particular instances the Wasm long-jobs use case--not just where you are doing calculations and communication with SharedArrayBuffer, but also where you are synchronously calling out to JavaScript. So it is quite specific. It might be more valuable to invest in wasm long-jobs to yield to the event loop. I'm not a Wasm expert but I've heard some exciting ideas in this space. @@ -472,24 +472,24 @@ AKI: Congratulations! Another one! Yay! - Stage 4! ## Decorators status update -Presenter: Chris Garrett (CHG) +Presenter: Kristen Hewell Garrett (KHG) - [proposal](https://github.com/tc39/proposal-decorators/) - [slides](https://slides.com/pzuraq/decorators-3cb407) -CHG: (presents slides) +KHG: (presents slides) WH: What does “downlevel” mean in this presentation? You used it several times and I couldn’t figure out what it was referring to. -CHG: It’s a term we coined within the decorator group. Every single decorator usage would have to be compiled to the polyfilled version, even if it potentially was using a native decorator, in other words "downlevelled." +KHG: It’s a term we coined within the decorator group. Every single decorator usage would have to be compiled to the polyfilled version, even if it potentially was using a native decorator, in other words "downlevelled." WH: I'm still unclear as to what “downlevel” means here. -CHG: Basically if you were in a case where you had a mix of native and non-native decorators they had to apply, they would have to transpile all of the decorators - because there is presumably no easy way to un-transpile a decorator which has already been transpiled. +KHG: Basically if you were in a case where you had a mix of native and non-native decorators they had to apply, they would have to transpile all of the decorators - because there is presumably no easy way to un-transpile a decorator which has already been transpiled. WH: Why can't the transpiler transpile only some of the decorators? -CHG: Because the syntax itself, when used, would not necessarily be compatible with the polyfill or transpiled version. +KHG: Because the syntax itself, when used, would not necessarily be compatible with the polyfill or transpiled version. JHD: WH the first thing is that in your deps graph, you will have non dependency code using transpiled code. Before the feature is available to you on your platforms, you will be using Babel or something to transpile the decorators in native syntax. @@ -499,25 +499,25 @@ JHD: At the point where the platform is able to change from transpiling the deco WH: Another point on the first slide that I didn't quite understand. You talked about “byte size”. Did you mean byte size of objects? -CHG: It’s just the byte size of decorated values in general that are using decorator syntax +KHG: It’s just the byte size of decorated values in general that are using decorator syntax WH: So, you're concerned that if you decorate an object, then the object will require more bytes to store in memory? -CHG: I’m sorry those are the bytes for the output syntax actually +KHG: I’m sorry those are the bytes for the output syntax actually WH: You mean outputting the object via, for example, JSON? -CHG: One solution proposed is that decorators would be a reserved syntax that isn't actually implemented in JavaScript, and have build tools compile decorators into JavaScript, and let the ecosystem figure out what it should mean, and ship that over the wire. If that were the solution we're gonna go with and we’re always going to solve the byte size problem. It would result in much larger class definitions, because in a lot of cases, you're decorating a field, which turns a field into a getter and setter, and that getter and setter would have to be transferred over the wire. Even minimized, that will be 10 times the size. (gist: https://gist.github.com/pzuraq/6c2ff5594bf16f9693a7d9131855ee2d) +KHG: One solution proposed is that decorators would be a reserved syntax that isn't actually implemented in JavaScript, and have build tools compile decorators into JavaScript, and let the ecosystem figure out what it should mean, and ship that over the wire. If that were the solution we're gonna go with and we’re always going to solve the byte size problem. It would result in much larger class definitions, because in a lot of cases, you're decorating a field, which turns a field into a getter and setter, and that getter and setter would have to be transferred over the wire. Even minimized, that will be 10 times the size. (gist: https://gist.github.com/pzuraq/6c2ff5594bf16f9693a7d9131855ee2d) WH: Ah, I think you mean the byte size of the transpiled code, is that correct? -CHG: Yes. And one other proposal is that it is always transpiled, that we never standardize on a decorator syntax. +KHG: Yes. And one other proposal is that it is always transpiled, that we never standardize on a decorator syntax. WH: From the slides and presentation I got the completely wrong idea of what you meant by “byte size”, so it was hard for me to follow the presentation. Thank you for clearing it up. -DE: A lot of people are talking about tooling solutions, as CHG mentioned in the byte size discussion, even in tooling a lot of these constraints still exist. I want to raise another one. Constraint #2 basically this gets at decorators being transpilable in a single-file mode. If you want to transpile decorators differently based on whether they add metadata, make fields into accessors, etc, you either need some cross-file communication, or you need to add runtime overhead conditionally. So, the constraints are still in conflict even in a pure tools mode. Personally, I'm optimistic that we can find some of these constraints that can be relaxed to find a solution. We’ll have to relax some of the constraints on whether we put this in tooling or in the language. My hope is that this presentation will illustrate the contradictions and get people thinking about which concerns do we really care about, which concerns can we relax. Then we can find more solutions. +DE: A lot of people are talking about tooling solutions, as KHG mentioned in the byte size discussion, even in tooling a lot of these constraints still exist. I want to raise another one. Constraint #2 basically this gets at decorators being transpilable in a single-file mode. If you want to transpile decorators differently based on whether they add metadata, make fields into accessors, etc, you either need some cross-file communication, or you need to add runtime overhead conditionally. So, the constraints are still in conflict even in a pure tools mode. Personally, I'm optimistic that we can find some of these constraints that can be relaxed to find a solution. We’ll have to relax some of the constraints on whether we put this in tooling or in the language. My hope is that this presentation will illustrate the contradictions and get people thinking about which concerns do we really care about, which concerns can we relax. Then we can find more solutions. -CHG: DE summed it up very well and we’d like to continue in that direction and the group will continue to work that way +KHG: DE summed it up very well and we’d like to continue in that direction and the group will continue to work that way ## NumericLiteralSeparator for Stage 4 Presenter: Rick Waldron (RW) @@ -540,7 +540,7 @@ RW: That's correct. [Background noises from somewhere drowning out the meeting. Notetakers can’t hear what’s being said and are asking for clarification.] -WH: I think I can summarize the situation. We’re not allowing underscores in unicode escape sequences. V8 is allowing them and therefore failing the test. V8 should fix this. Is that correct? +WH: I think I can summarize the situation. We’re not allowing underscores in unicode escape sequences. V8 is allowing them and therefore failing the test. V8 should fix this. Is that correct? RW: Presumably that’s why it’s failing, correct. Everyone else is throwing the correct SyntaxError. @@ -618,7 +618,7 @@ WH: I have similar views to YSV, I feel like this is adding a bit of complexity On the other hand, with x[a:b] you have to remember which things allow the single argument in brackets x[a] and which things allow two arguments in brackets x[a:b]. And those are likely to be different sets. And then I see that we’re discussing that slicing a string should index by unicode characters, so if you apply s[a:b] to a string, you get indices by unicode characters, but if you apply s[a] to a string, you’d get indices by code points, which would be terribly confusing. -LEO: (queue reply: This improves Developer Experience) +LEO: (queue reply: This improves Developer Experience) DRR: To further WH’s point, the fact that slice already exists as a method and has the semantics I intend means that this is a nice-to-have for me. With this syntax, when I show it to people, they’re like “oh cool, I can get the last element of an array”, but then it was weird, because everyone would realize that, oh wait, I still have to re-index with 0 to get the last element. Maybe this leads into SYG’s topic, but the fact that you can’t do a negative index on these things makes it a little confusing. I know that there is a related proposal that we'll discuss about later, but I think that that is something to consider. @@ -817,7 +817,7 @@ Presenter: Richard Gibson (RGN) RGN: (presents slides) -DE: You referred to the string getter as superpower, and I wanted to express reservations about that characterization. There was that previous exotic internal slot hazard discussion - we discussed this more in the SES strategy meeting. MM is here, so he can talk more, but what we arrived at is that internal slots with objects are not dangerous if accessed from `this`. https://github.com/tc39/proposal-intl-segmenter/issues/96#issuecomment-661008571 +DE: You referred to the string getter as superpower, and I wanted to express reservations about that characterization. There was that previous exotic internal slot hazard discussion - we discussed this more in the SES strategy meeting. MM is here, so he can talk more, but what we arrived at is that internal slots with objects are not dangerous if accessed from `this`. https://github.com/tc39/proposal-intl-segmenter/issues/96#issuecomment-661008571 RGN: It would impose additional work for what have been referred to as “near membranes” in the SES call. But the change was primarily about ergonomics, avoiding the internal slot use wasn’t a motivating factor. I’m willing to back off on the characterization. diff --git a/meetings/2020-09/sept-23.md b/meetings/2020-09/sept-23.md index c1dd9d69..c16a0323 100644 --- a/meetings/2020-09/sept-23.md +++ b/meetings/2020-09/sept-23.md @@ -1,9 +1,9 @@ # September 23, 2020 Meeting Notes ----- -**In-person attendees:** +**In-person attendees:** -**Remote attendees:** +**Remote attendees:** | Name | Abbreviation | Organization | | -------------------- | -------------- | ------------------ | | Ross Kirsling | RKG | Sony | @@ -79,7 +79,7 @@ Should this proposal be blocked on exploring that. Sounds like you are implying BFS: That’s it. MM: I like almost all of this. I do think that the reified path is sufficiently separate that it shouldn’t be part of this proposal, the in syntax should advance, I am not interested in re-litigating the mental model which in a way ??? -Sort of property like, consistent with the syntax we have in the proposal, and consistent with the 2xx, things that are ??? +Sort of property like, consistent with the syntax we have in the proposal, and consistent with the 2xx, things that are ??? The reified form is really a much more specialized kind of use and very rare, for reflective purposes. That is the one where the mental model has to be the WeakMap model, and I think that it doesn’t need to be bundled into this proposal. The one disagreement I have with the WeakMap proposal is that I think the reified form should not simply be #x, the reason is another least surprise issue, for people in other class based languages, seeing #x they will expect it to be bound to this.#x. Reifying the name is weird, and doesn’t have precedence in other languages. I won’t mention concrete suggestions there but it is OK if that syntax has more ceremony to it, and is less easy to stumble on accidentally. JHD: One thing I forgot to mention, the inconsistency between string symbol and private fields, are intentional. We explicitly designed this over years of debate and perhaps considering perhaps too many alternative options, and this is kind of what we agreed upon. To me, suggesting consistency between private fields and strings and ignoring the fact that ??? was intentional is not a constraint that I agree with. Thank you for your thoughts on reifications and I’m not planning to bring forth a proposal for reification. @@ -104,18 +104,18 @@ WH: By “this feature”, do you mean `in` or reification? DE: Reification. -DE: I am not suggesting that JHD's feature takes a dependency on adding the reification feature. I think the dependency is on us thinking through the design space and I think we have done that. +DE: I am not suggesting that JHD's feature takes a dependency on adding the reification feature. I think the dependency is on us thinking through the design space and I think we have done that. JRL: I think what JHX is saying, if we have `#x in foo`, that implies that `#x` can be keyed in computed property access like `foo[#x]`. My problem with that is that we already have `foo.#x` syntax, and we think of that as `WeakMap.p.get` in the map-like API. If we already have `foo.#x`, I don’t see how `#x in foo` matching a map-like API for `WeakMap.p.has` is that different. It is not a huge jump in logic for both of these syntaxes even if we were to reify into a WeakMap API. JHD: I certainly agree with that. -AK?: How are we on clarity right now? Silence cool. +AK?: How are we on clarity right now? Silence cool. YK: I just want to say positive things. JHD did a good job of presenting the mental model, and that he did a good job stating why the syntax is. In general reification interacts with ??? Obviously that proposal is not going to proceed as-is. We will want to see how reification interacts with other proposals anyway, and there is no reason for us to wait on this for that to shake out. -MM: The reified thing is a separate reflective level which is a much more specialized use, and we don’t know what the demand is. For the same rationale I don’t want to add syntax for other features. If there isn’t special syntax for it, how hard is it to do it yourselves? I pasted code in chat, that is a few lines of code that does this. If you have to do this all the time it will be a pain, but if you need to do it rarely you can roll it yourself. If we find that people end up doing this a lot even if it is 3 lines, then we have established a need. +MM: The reified thing is a separate reflective level which is a much more specialized use, and we don’t know what the demand is. For the same rationale I don’t want to add syntax for other features. If there isn’t special syntax for it, how hard is it to do it yourselves? I pasted code in chat, that is a few lines of code that does this. If you have to do this all the time it will be a pain, but if you need to do it rarely you can roll it yourself. If we find that people end up doing this a lot even if it is 3 lines, then we have established a need. ``` ({ has: obj => #x in obj, @@ -183,12 +183,12 @@ AKI: Before or after lunch. Decision deferred until JHX can review notes. ## Decorators: A new proposal iteration -Presenter: Chris Garrett (CHG) +Presenter: Kristen Hewell Garrett (KHG) - [proposal](https://github.com/tc39/proposal-decorators/) - [slides](https://slides.com/pzuraq/decorators-a-new-proposal-2020-09) -CHG: (presents slides) +KHG: (presents slides) WH: I'm confused by the explanation of init decorators. @@ -298,7 +298,7 @@ DE: For that particular one, that is something you can do with a type system, bu BSH: For class decorators it does decorators a class and return a class, ?? was given. -DE: The answer to the question is no. We can discuss this more in the decorators call, I want to learn more about these invariants. +DE: The answer to the question is no. We can discuss this more in the decorators call, I want to learn more about these invariants. I want lean more about what you want . thats not awared by previous decorators. DE: Do people have concerns on the high level, thanks for feedback. diff --git a/meetings/2021-07/july-14.md b/meetings/2021-07/july-14.md index 3641a512..5a2e4ff0 100644 --- a/meetings/2021-07/july-14.md +++ b/meetings/2021-07/july-14.md @@ -1,7 +1,7 @@ # 14 July, 2021 Meeting Notes ----- -**Remote attendees:** +**Remote attendees:** | Name | Abbreviation | Organization | | -------------------- | -------------- | ------------------ | | Waldemar Horwat | WH | Google | @@ -66,7 +66,7 @@ DDC: and one question that has come up with this is what to do with unsupported DDC: So I think I'd like to go to the queue at this point and get thoughts. Like are there other ideas for having some kind of useful limitation here or is this something that we're okay with? Just going to dropping after learning about these concerns from other hosts. -GCL: So from, from the requirements that node has, as long as the spec doesn't say something like an implementation must declaratively know what types it supports, you know, something like where you're like putting it at the limitation on the specific way that the implementation determining whether or not it understands what a type is, you could have something that says the host should throw. I don't know exactly what the text for that would look like, but I don't think this is inherently like something that node - like I think it's reasonable to say that within any like VM context you could add new types but also unknown types could still throw. I think we could get to text that does that, but I'm also fine with leaving the proposal as if I just wanted to mention that. +GCL: So from, from the requirements that node has, as long as the spec doesn't say something like an implementation must declaratively know what types it supports, you know, something like where you're like putting it at the limitation on the specific way that the implementation determining whether or not it understands what a type is, you could have something that says the host should throw. I don't know exactly what the text for that would look like, but I don't think this is inherently like something that node - like I think it's reasonable to say that within any like VM context you could add new types but also unknown types could still throw. I think we could get to text that does that, but I'm also fine with leaving the proposal as if I just wanted to mention that. SYG: I just want to clarify, Gus has a point about "declarative". Do you mean, Declarative in the sense of the host of the new host hook where it would upfront get the static list of supported types that Dan was talking about. Is that what you mean by declarative? @@ -86,7 +86,7 @@ BT: Any other thoughts on the topic? `[silence]` Looks like no. All right. Feel DDC: Yeah, I know, there might be some others that aren't present here. That might also have thoughts on this end. Uncertain, whether this is the right time to like, ask for consensus on sticking with the status quo on that. -KG: I mean, you never need consensus to stick with the status quo; the status quo is what happens in the absence of calls for consensus. +KG: I mean, you never need consensus to stick with the status quo; the status quo is what happens in the absence of calls for consensus. DDC: Okay. In that case, I think. Yeah, I think I would also prefer to just leave it like that. I'm kind of also questioning the specifics of what it would look like to have to say, what an unrecognized type would look like. In this with without knowing more, like also not a node experts unless we have something very concrete there that we could that we could say, I'm not sure. I'm not really sure how to move forward. So yeah, I guess in the absence of that I think I think that would be it. I think we'd just leave it as is. @@ -129,16 +129,16 @@ No changes sought or made, general agreement on the status quo ## Decorators update -Presenter: Chris Garrett (CHG) +Presenter: Kristen Hewell Garrett (KHG) -- [proposal](https://github.com/tc39/proposal-decorators) +- [proposal](https://github.com/tc39/proposal-decorators) - [slides](https://slides.com/pzuraq/decorators-update-2021-07) -CHG: So yeah, my name is Chris. I'm here with a quick update on decorators today. Basically, the tldr is, the spec has been written and the decorators champion group has achieved internal consensus on all of the details. In this presentation, I want to go over the proposal just as a broad overview, kind of the general design principles and the way that it works and then I wanted to talk about the current status. +KHG: So yeah, my name is Chris. I'm here with a quick update on decorators today. Basically, the tldr is, the spec has been written and the decorators champion group has achieved internal consensus on all of the details. In this presentation, I want to go over the proposal just as a broad overview, kind of the general design principles and the way that it works and then I wanted to talk about the current status. -CHG: So first off the proposal overview. So decorators in This proposal are plain JavaScript functions, so no, custom syntax, no new types of elements or anything. Like that, unlike the static decorators proposal that came before. And as in previous proposals, they can be applied to classes and class elements. They have three main capabilities, which is the way that we've kind of distilled them into some design principles that should make it pretty intuitive to understand what decorators are capable and what they should be in general. And those capabilities are Replacements, Metadata, and Access. In addition, there is a notion of modifiers syntax which is the ability to prepend a keyword on to the invocation of a decorator as seen here in the last decorator in this example on the right (`@init:`). Modifiers add additional capabilities to a decorator if the user chooses to opt into capability. But default decorators are not able to do what modifiers are able to do because it's basically like opt-in if you want that extra cost, that extra capability, otherwise don't incur it for every single user. And the only modifier that is included in this proposal is the `@init` modifier, which we will be going over in a bit. Also, this proposal includes a new type of class element, which is a Class Auto accessor, an auto accessor is very similar to a field, and it is defined using a new access or keyword which will go over as well, on. +KHG: So first off the proposal overview. So decorators in This proposal are plain JavaScript functions, so no, custom syntax, no new types of elements or anything. Like that, unlike the static decorators proposal that came before. And as in previous proposals, they can be applied to classes and class elements. They have three main capabilities, which is the way that we've kind of distilled them into some design principles that should make it pretty intuitive to understand what decorators are capable and what they should be in general. And those capabilities are Replacements, Metadata, and Access. In addition, there is a notion of modifiers syntax which is the ability to prepend a keyword on to the invocation of a decorator as seen here in the last decorator in this example on the right (`@init:`). Modifiers add additional capabilities to a decorator if the user chooses to opt into capability. But default decorators are not able to do what modifiers are able to do because it's basically like opt-in if you want that extra cost, that extra capability, otherwise don't incur it for every single user. And the only modifier that is included in this proposal is the `@init` modifier, which we will be going over in a bit. Also, this proposal includes a new type of class element, which is a Class Auto accessor, an auto accessor is very similar to a field, and it is defined using a new access or keyword which will go over as well, on. -CHG: Okay, so, so first off, let's look at the decorator function API, what it looks like generally. Generally decorators receive the value they are decorating as their first argument. So that's the input value, if they're decorating a method, it'll be a function, if they're decorating a class, it'll be the class constructor so on and forth. The second argument is a context object. This object provides just general context about the value that is being decorated. So what kind is it, is that a class, method, field Etc. What is its name? If it is class elements, the name of that class elements. If it's a private element, the spelling of the element for debugging purposes, but not for any access purposes. And so on. It also has information like whether or not the value is private, is it static, and then also the ability to get instead metadata and add initializers which we'll talk about later on. The return value of the decorator is the replacement value, the value that replaces the decorated value, and this is optional for all decorators, you can either return a new value or you can do nothing and that's completely fine. The types of the input and output values are dependent on what is being decorated. Of course, I'm using typescript here just to kind of show briefly what the API looks like in general. +KHG: Okay, so, so first off, let's look at the decorator function API, what it looks like generally. Generally decorators receive the value they are decorating as their first argument. So that's the input value, if they're decorating a method, it'll be a function, if they're decorating a class, it'll be the class constructor so on and forth. The second argument is a context object. This object provides just general context about the value that is being decorated. So what kind is it, is that a class, method, field Etc. What is its name? If it is class elements, the name of that class elements. If it's a private element, the spelling of the element for debugging purposes, but not for any access purposes. And so on. It also has information like whether or not the value is private, is it static, and then also the ability to get instead metadata and add initializers which we'll talk about later on. The return value of the decorator is the replacement value, the value that replaces the decorated value, and this is optional for all decorators, you can either return a new value or you can do nothing and that's completely fine. The types of the input and output values are dependent on what is being decorated. Of course, I'm using typescript here just to kind of show briefly what the API looks like in general. DDC: Let's dig into the capabilities of decorators. The first one, as I mentioned before is Replacement so decorators may replace a value that they are applied to with another value. Of the same type. This is the primary capability of decorators, so class decorators return, into class method, decorators can return a new method. The one exception is in a somewhat of an exception is field decorators. You might expect that field decorators would for instance, receive the initializer of the field and return a new initializer, but the constraints for performance reasons on the proposal was that could not do this because capturing the initializer would allow too much dynamism. So instead they are pipelines, so when return a new initializer from a field decorator, that initializer will receive as its first argument the value of the previous initializer. So you can then transform it or add on to it for each field that is initialized. Crucially, in this proposal decorators cannot replace a value with a different type of value. So they cannot turn a method into a field, a field into an accessor, or so on. So that reduces dynamism and reduces the ability of decorators to change the shape of a class. And in addition they cannot add, remove, or replace any other values other than the decorated value. And this is both important from like a just static analysis and performance standpoint, but it's also important from a user/developer experience standpoint. Previously decorators could do all of this and you could potentially have a decorator that would affect every other element on a class except for the one that was decorating. Something that would be counterintuitive to the user. Now users can look at what a decorator is applied to and have a general understanding of what that decorator is capable doing whether or not It's replacing a value or so on. So that limitation really helps to inform users what that decorator is doing. @@ -146,9 +146,9 @@ DDC: Next up, the second capability of decorators is the ability to add metadata WH: Re: the slide, you could run `validate` on an instance of `MyClass`? -DC: Yes, you could do that. +DC: Yes, you could do that. -WH: And where does `​​obj[Symbol.metadata]` come from? Every object has a binding of metadata now? +WH: And where does `​​obj[Symbol.metadata]` come from? Every object has a binding of metadata now? DC: So if the object has a decorator that adds metadata via context.addMetadata, then that creates an object at the end of class, create a class definition and assigns it to the symbol table metadata property, property. So done So it's done at a specific time during Glass construction and only done. if, if the metadata was added in the first place, if no metadata was added during definition, this will just be an undefined property, it won't be defined at all. @@ -192,7 +192,7 @@ JHD: It should never fail, but if it's called instead on something else, so it'l DDC: Yes. -JHD: Thank you. +JHD: Thank you. DDC: So, back to modifiers. So basically initializers run during class construction for class elements so they can do things like, for instance, in example, they bind the function to the instance. So this is a pretty common ask for decorators, the ability to kind of auto bind functions that you might want to use as a callback, for instance. So, this is how you would do that. And the other use case is to run for classes is to run after the class has been fully defined, meaning after static fields have been assigned. This is something that has been a topic of some debate on the decorators proposal, but essentially decorators themselves run before static fields have been assigned, meaning you can't actually use those them in the process of decoration. so, having class initializers, which run after everything has been defined, cannot change the class. They can't rebind the value. They can't return a new class Constructor solves that use case. So yeah, any questions on that one? @@ -214,7 +214,7 @@ IID: Thanks. DDC: Moving on, so that's modifiers. And then, I also mentioned previously that we have a new type of class elements, so auto-accessors are basically like a class field, but instead of being defined on the instance, they are sort of defined on the prototype, a getter, and Setter are defined on the Prototype and that backing, that getter and Setter just basically access backing storage on the instance, instance, which is a private slot. It is quite similar to this [slide] in the spec, like these are basically equivalent. The purpose of this, there are a few purposes. One is to provide some syntactic sugar to do something that users. Do occasionally asked to do these days which is making a field on the Prototype users might want to do this to make a field not enumerable, or for any other number reasons. But also its so that we can have a value that basically works like a field but can be decorated and allow the decorator to intercept access so intercepting getting and setting and that allows us to do things like provide reactivity to that field, to that value. And allows us to do things like validate the field when it is set, to run code when the value is being set, lazy dependency injection basically requires this well. The ability to look up the value lazily the first time it is accessed, you need to have a getter there and so either, you have to decorate an accessor or you have to decorate a field. And this kind of is in between for those two. The idea is also that this could potentially be extended in the future with a more general syntax which Ron Buckton has proposed. There's a link to the proposal here. I forget the exact name of the proposal, but I definitely am excited to see where that goes. But it's out of scope for this proposal. -DDC: Okay. So that's an overview of the proposal. Any questions about auto accessors? +DDC: Okay. So that's an overview of the proposal. Any questions about auto accessors? BT: There are a few questions on the queue, but also just a quick time note. We're down about eight minutes in the time box, I believe. So try to be brief. @@ -224,7 +224,7 @@ DDC: I think it could move independently on its own. I definitely think that the JHD: Okay. And then the second question was with your "similar to". I was curious how faithful that sugar was. In other words, will the getter throw if it's called an object that isn't it? Like the didn't run through the constructor? You know like where as if it was a private field like your line 6 through 16 here will throw if the receiver lacks that private field. So I'm wondering if the auto accessors works the same. Then if so, how would I determine in advance without a try/catch if the accessor is going to throw or not? -DDC: That is a great question. The second one, rather. The first one is the answer is it will throw, I believe, because in the spec we back the field with a private slot, it uses all the same mechanisms as a private field. For the second question, I'm not too sure. I think you would have to use a try/catch. I'd have to think on that or what it means that like General concern, +DDC: That is a great question. The second one, rather. The first one is the answer is it will throw, I believe, because in the spec we back the field with a private slot, it uses all the same mechanisms as a private field. For the second question, I'm not too sure. I think you would have to use a try/catch. I'd have to think on that or what it means that like General concern, JHD: there is the proposal I discussed recently that just got stage 4 is that I wanted to determine if something is going to throw or not with the `in` keyword, so that works for private fields now. But in this case because it's sugar for it, there isn't a special way to refer to it that would work within and tell you if it's going to throw or not. Because if did some value in an object, it'll just tell you if the accessors, you know, if the property is successful there, right? @@ -284,7 +284,7 @@ Presenter: Wenlu Wang (KWL) - [proposal](https://github.com/tc39/proposal-array-find-from-last) - [slides](https://kingwl.github.io/proposal-array-find-from-last-looking-for-stage-3-sides) -KWL: quick recap, this allows you find some elements or a from end of list to the start. This proposal will be seeking stage 3. No major changes from last meeting. You can see the pr and they are not semantical. All around and behavior changes. The final spec text: [shows text]. +KWL: quick recap, this allows you find some elements or a from end of list to the start. This proposal will be seeking stage 3. No major changes from last meeting. You can see the pr and they are not semantical. All around and behavior changes. The final spec text: [shows text]. KWL: we have completed the spec text, reviewers have signed off, and editors have signed off too. I have to say thanks to everyone. And we have a few implementations: coreJS has had already implemented, there are other polyfills that have implemented, and Chakra has been implemented behind a flag, even if Chakra may not related to the web Compact anymore. For web compat, we would appreciate it if someone could help with the investigation. Thanks, that's all. So this proposal is seeking for stage 3. @@ -298,7 +298,7 @@ KWL: I'm not familiar with your proposal, but this proposal the spec test text i JRL: Yeah, I agree with your behavior actually. I'm asking for consensus on standardizing on get behavior and not doing has and then get. -SYG: I'm not sure, the queue is an appropriate place to ask consensus for a precedent. +SYG: I'm not sure, the queue is an appropriate place to ask consensus for a precedent. BT: Yeah, like that sounds like something we could discuss the context of your other proposal Justin. @@ -310,7 +310,7 @@ BT: We can try and get that on the agenda if there's time. KWL: should I... -BT: I think your proposal is good from this perspective. Hax was just pointing out that this is following the find and findIndex precedent. +BT: I think your proposal is good from this perspective. Hax was just pointing out that this is following the find and findIndex precedent. MF: I probably won't feel comfortable with addressing this topic on that short of preparation. @@ -337,7 +337,7 @@ Proposal achieves stage 3 -## Guidance for nested namespaces +## Guidance for nested namespaces Presenter: Philip Chimento (PFC) - [slides](https://ptomato.github.io/talks/tc39-2021-07/index.html) @@ -345,9 +345,9 @@ Presenter: Philip Chimento (PFC) PFC: This is a short last-minute agenda item that SYG suggested that I add. Coincidentally enough from the context of the previous discussion, this is a request for plenary to give guidance and set a precedent for the situation that we have in a proposal, so that future proposals will be consistent with it. Namespace objects, I think nobody disagrees that they should start with a capital letter. We have Math with a capital M since 1995 probably; and Temporal with a T. In the plenary about a year ago we decided that namespace objects should have a @@toStringTag property at least for top level namespace objects, which are the only namespace objects that we have so far that I'm aware of. The Temporal proposal is going to add a nested namespace object, `Temporal.now`, which until now has been spelled with a lowercase n probably because nobody actually thought about it, and it started out life as a function. So we got a request to change this to a capital N. And you know, this also raises the question, should it have a @@toStringTag property and if so, what should that be? Should it be `"now"` or should it be `"Temporal.now"`? It seems like this is something that we should provide explicit guidance about so that we don't make an ad hoc decision that's done differently by different proposals. It seems from the thread that was started, that people think in general that nested namespaces should be capitalized. My proposal here that I'm going to ask for a consensus on is, is that, plus having a @@toStringTag property equal to the fully qualified name. So, in the case of `Temporal.Now`, it would be Now with a capital N, and the @@toStringTag property, would have a value of `"Temporal.Now"`. So, after whatever discussion we have, I'd like to ask for consensus on a guidance and consensus on making this change in any current proposals. Temporal is the only one that I'm aware of that is affected by this, but there may be others. So discuss away. -MM: I just have a clarifying question first. Last I looked it was just simple. What is currently in the namespace? +MM: I just have a clarifying question first. Last I looked it was just simple. What is currently in the namespace? -JHD: [link] +JHD: [link] MM: Is it brief enough that you can just enumerate it? @@ -383,7 +383,7 @@ JRL: `Date.now()` is a method that you call and having `Temporal.now` be lowerca JHD: This is a counter to my own constructor comment as well, but if you think it's a thing that it's not, and you try to use it that way, and then it immediately tells you it's not a function, you can't do something. If it's not a function, and you can't call it, you're not going to be confused anymore. So I don't know if the confusion argument really pushes in either direction very strongly. -SYG: If there's no initial confusion at all, even if it's quickly resolved, isn't that better? +SYG: If there's no initial confusion at all, even if it's quickly resolved, isn't that better? JHD: Well yeah, but I shared one intuition, others have shared others, right? I think there's the chance of confusion either way, it's just about which kinds of confusion we prefer. In either case, I think someone will try it and immediately discover what's going on and the confusion will be gone. And so I think it's a moot point towards this proposal. @@ -393,7 +393,7 @@ KG: I do actually draw a distinction. If I am creating a bunch of instances of a MM: I don't. I don't know what to do about that. It would be interesting to see whether there's an adequately dominant, consensus, practice to help there. But this question, as a question to debate, hasn't even come up that I'm aware of; as something people have argued about, the things people have referred to as namespaces. It's always just been top level. -BT: Just to note that we are up against the time box, we did get some time back so we have maybe another five minutes maximum for this. Hopefully we finish up the discussion. It looks like there's a few more replies on this topic. +BT: Just to note that we are up against the time box, we did get some time back so we have maybe another five minutes maximum for this. Hopefully we finish up the discussion. It looks like there's a few more replies on this topic. JHD: KG's answer may answer this, but to MM's point, what is a namespace object? The decorator API we just got a presentation about, where a decorator function gets an object argument that has an `access` property that contains two functions: that's lowercase `access`, right? But it's not a singleton, that’s true, but how would we even define this? Is it that it has to be a global singleton object containing stuff? @@ -403,9 +403,9 @@ SYG: Yes. So I think context is decidedly not a namespace object, even though it JHD: Yeah, I think so. -MM: What you said, I agree that it makes sense. I just — and I see from the title of your reply to your question to me, the only things where I give them capital names and think of them as namespace objects are at top level. Other than that, I just think of myself as handling records with properties. And some of them are singletons. And I don't strongly distinguish that; sometimes I refactor code from from a singleton to something that's multiply instantiated or vice versa. I don't think of the fact that an object is a singleton. If it's just immutable data or if it's just functions as being a completely different category of object, an object that's made by a factory that can create multiple instances. That's certainly different in some ways but not that different. +MM: What you said, I agree that it makes sense. I just — and I see from the title of your reply to your question to me, the only things where I give them capital names and think of them as namespace objects are at top level. Other than that, I just think of myself as handling records with properties. And some of them are singletons. And I don't strongly distinguish that; sometimes I refactor code from from a singleton to something that's multiply instantiated or vice versa. I don't think of the fact that an object is a singleton. If it's just immutable data or if it's just functions as being a completely different category of object, an object that's made by a factory that can create multiple instances. That's certainly different in some ways but not that different. -SYG: I guess I do. I'm somewhat surprised, being primarily a C++ programmer that has non-reified namespaces. I feel like any language that has a concept of the namespace thing where you scope things to group them together, also has a way to nest them, and then the way to name those namespaces are consistent, regardless of nesting. I'm both kind of surprised by the argument that nesting makes it qualitatively a different thing; and that namespaces you don't think of them, MM, as nestable. +SYG: I guess I do. I'm somewhat surprised, being primarily a C++ programmer that has non-reified namespaces. I feel like any language that has a concept of the namespace thing where you scope things to group them together, also has a way to nest them, and then the way to name those namespaces are consistent, regardless of nesting. I'm both kind of surprised by the argument that nesting makes it qualitatively a different thing; and that namespaces you don't think of them, MM, as nestable. MM: I'm glad you brought up the C++ example because that really helps understand what the question is. And I agree that when I nest them and think of them as namespace-like, then they're a different category subjectively than when I just happen to have a reified record that has properties. The problem is that, if we're going to talk about this as a precedent for something, in JavaScript there is no concept of namespaces, we're just overloading reified objects as records. Some of them are holders of data and function and is just a reified object and some of them are as if they were second-class namespaces. There's nothing to grab onto in JavaScript to make a crisp distinction such that we would set a precedent according to the distinction. @@ -417,7 +417,7 @@ No conclusion, will revisit later this meeting if there is time -## Restricting callables to only be able to return normal and throw completions +## Restricting callables to only be able to return normal and throw completions Presenter: Shu-yu Guo (SYG) - [proposal](https://github.com/tc39/ecma262/pull/2448) @@ -428,7 +428,7 @@ SYG: when doing a review of the resizable buffers proposal, Mike Pennisi noticed MM: I enthusiastically support this. -BT: the queue is empty. +BT: the queue is empty. WH: This seems like motherhood and apple pie. I support this. @@ -461,13 +461,13 @@ Consensus on both PRs -## Guidance for nested namespaces again +## Guidance for nested namespaces again MM: The `now` thing is separate exactly because of the desire to virtualize. If you desire to have different compartments, have different settings of `now`. In order to do dependency injection of what the current time is, (??). So in that sense, there will be multiple `now` objects running around, and the replacement of `now` is the meaningful thing. So SYG, I want you to clarify given that from your definition of what it means to be a namespace object, that anticipated usage would make the `now` not be a namespace object. Is that correct? SYG: Interesting point, let me think that through. When I said the identity of the namespace holder object matters, I was thinking of if — like a static method — if I'd reassign to somewhere else, if I pulled it out as a free function, and I called it, it would behave the same regardless of the receiver. In that sense, even if virtualized, that would still be true, right? Are you thinking of virtualizing with functions where its receiver matters? -MM: I would certainly prefer the all the functions not to be `this`-sensitive. When I program with the objects with closure pattern, which I do a lot, I also program with functions that are properties of objects that act like methods that close over instance state, but do it without being `this`-sensitive. So that by itself does not make it into a namespace. +MM: I would certainly prefer the all the functions not to be `this`-sensitive. When I program with the objects with closure pattern, which I do a lot, I also program with functions that are properties of objects that act like methods that close over instance state, but do it without being `this`-sensitive. So that by itself does not make it into a namespace. SYG: I haven't thought through exactly what a namespace object is, but you can virtualize `Math.random` by virtualizing the Math object, and we don't seem to disagree that is a namespace object? @@ -500,7 +500,7 @@ No outcome on capitalization, we may or may not revisit at this meeting, status -## Renaming Strawperson to Concept or something better +## Renaming Strawperson to Concept or something better Presenter: Hemanth HM (HHM) - [slides](https://docs.google.com/presentation/d/11PBKeQOGVj3r3F9xBJIKpgftfyeW5lGHHAJrI7Misgc/edit?usp=sharing) @@ -525,7 +525,7 @@ SYG: I see. It seems like it would be clear for the process document to perhaps AKI: All right. Thank you for that. I'm next on the Queue. I'm going to say honestly we have a lot of time this plenary. So I'm less concerned about utilizing the time to discuss the topic like this. Except I agree with Shu in that I think it could be as simple as - I think getting rid of strawperson a good idea. I think maybe just getting rid of English names for hard to grasp esoteric concepts is maybe the best idea. -GCL: I'm also in agreement that we should just remove this column and be done with it. +GCL: I'm also in agreement that we should just remove this column and be done with it. HHM: currently the the page, which talks about the process or the progression of proposals, has strawperson and proposal, and draft and likes. So, if you were to remove this, what would we call it? Are we happy with calling it concept or we just stick with stages like State 0 to stage four more? What are currently proposing? @@ -567,7 +567,7 @@ HHM: So from what we heard, a few people voted and they were comfortable with ha KG: So that was two questions. Can we ask one question? -HHM: Yeah, the question is, should we have names or not? +HHM: Yeah, the question is, should we have names or not? [TCQ temperature check] @@ -575,7 +575,7 @@ SYG: I want this to be narrowly about removing the name column from the process AKI: Okay, so I'm seeing the strongest feelings about just getting rid of the column. There are some people who are unconvinced. There's some people who are indifferent. Those of you who are unconvinced, do you think that we should not get rid of that column and instead should spend some time bikeshedding what we call things, or - I would like to be done with this actually, I would like to know what people who are unconvinced, how strongly you feel. `[silence]` I think we have consensus to remove the column, that is what it sounds like to me. No one has spoken up to stop that. I will give everybody one brief opportunity to speak up and otherwise let's just get rid of it and move on and we can all use whatever phrasing we want when we're educating people because use the language that matches your audience. -LEO: I am sorry. I just got late to this topic because it was putting my kid to sleep. I totally just saw the slides already mentioned part of my point of view. I'm getting late to this train, just I have like there are many problematics with Straw Men, straw person or anything that derives from these terms, like my biggest pet peeve is any wording that derives from that. And also like the original one comes in from like very problematic . I just want to mention like for someone who does have English as a second language even like Straw Men was problematic so many perspectives, not only like by, there's one, there is a most of anyone but like, just a perspective, it doesn't mean anything else, like, for technical for a technical naming - In concept was actually like, dictionary based naming for that, but there's another discussion here that see on removing that column. Sorry. I just wanted to give this perspective as like, if I see a column, if there is anything that we call for stage zero, I'd rather have it with something that it's easier for me to translate. And it's also like legit to what it means. That's that's like the point of view why I support this. There are many other problematics that I also support this change as well but I'm just giving a perspective that that I don't believe everyone shares the same point view and I hope you understand that Thank you Leo for that perspective. +LEO: I am sorry. I just got late to this topic because it was putting my kid to sleep. I totally just saw the slides already mentioned part of my point of view. I'm getting late to this train, just I have like there are many problematics with Straw Men, straw person or anything that derives from these terms, like my biggest pet peeve is any wording that derives from that. And also like the original one comes in from like very problematic . I just want to mention like for someone who does have English as a second language even like Straw Men was problematic so many perspectives, not only like by, there's one, there is a most of anyone but like, just a perspective, it doesn't mean anything else, like, for technical for a technical naming - In concept was actually like, dictionary based naming for that, but there's another discussion here that see on removing that column. Sorry. I just wanted to give this perspective as like, if I see a column, if there is anything that we call for stage zero, I'd rather have it with something that it's easier for me to translate. And it's also like legit to what it means. That's that's like the point of view why I support this. There are many other problematics that I also support this change as well but I'm just giving a perspective that that I don't believe everyone shares the same point view and I hope you understand that Thank you Leo for that perspective. SFC: Yeah, I think the mental model is useful, but now that I've thought through this a little more, I think the column called "Acceptance Signifies" is actually more useful than like the single word stage names. That already forms a very good mental model, because, as others have said, trying to use a single word for this is problematic; there are lots of issues with that. So I'll withdraw my negative vote, and move it to a weak positive (for removing the single-word names altogether). @@ -599,7 +599,7 @@ KG: Basically, my thesis is that we should have a built-in mechanism for convert KG: Here is a possible API. At this stage obviously nothing is fixed, but it could look like this. We can have a prototype method that converts a buffer to a base64 string and a static method that consumes a base64 string and gives you an array buffer of the appropriate length. -KG: Now, of course, there are a lot of details that need to be worked out here. For example, should it be asynchronous? My claim is no, it shouldn't. Userland solutions aren't and we should not be less convenient than userland solutions. If you are operating on very large data, for example if you are uploading a base64 version of a file or something, then you want to use a stream anyway, which is an HTML concept, and not really something that we currently deal with. Again, open to changing this - I should say, I am open to having different answers for all of the questions I am about to pose. I just want to raise them as questions, and to give my opinion so that if people strongly disagree, we can fight about it in the future. +KG: Now, of course, there are a lot of details that need to be worked out here. For example, should it be asynchronous? My claim is no, it shouldn't. Userland solutions aren't and we should not be less convenient than userland solutions. If you are operating on very large data, for example if you are uploading a base64 version of a file or something, then you want to use a stream anyway, which is an HTML concept, and not really something that we currently deal with. Again, open to changing this - I should say, I am open to having different answers for all of the questions I am about to pose. I just want to raise them as questions, and to give my opinion so that if people strongly disagree, we can fight about it in the future. KG: Should we also support hex, the other common method of encoding arbitrary, binary data as text? I think yes, probably. It comes up often enough. It's easy to do in userland but we might as well. It seems like we ought to support hex. @@ -607,7 +607,7 @@ KG: If we are doing base64, of course there are different variants of base64. Th KG: Now padding is controversial. The RFC for base64 does not say that decoders are required to verify that the string that they are decoding is correctly padded, it gives them the option of doing so. Almost all base 64 decoders do not enforce that the string that they are given is correctly padded. Note here that I'm speaking of both kinds of padding, the equals signs on the end and the additional bits that might be in the last character. If you don't know what those are, don't worry about it. Just for those who are aware, I want to emphasize I'm talking about both kinds of padding. The fact that decoders don't typically verify means that you end up in the situation where base64 is not actually a canonical encoding. I think that this surprises many people, it surprised me when I learned about it. I have a nice collection of screenshots of it surprising other people. And because people are not aware of this, it is very easy to write code which is subtly incorrect, possibly in a way that causes a security vulnerability, that relies on the assumption that it is canonical. For example, you might be checking membership in a list of revoked keys by comparing the base64 encoding of some values and that simply does not work if your decoding is not canonical, meaning to say, if your decoding does not enforce that padding is correct and reject strings that are incorrectly padded. So it is my opinion that we should verify padding by default and have an option that allows you to not verify padding. However, there's disagreement about this point. I don't want to fight that out before stage 1, but do want to fight that out before stage 2. So I also would be interested in hearing opinions on that topic, if people think that the proposal as a whole is reasonable, so that I have something to be going with towards advancing this in the future. So let's go to the queue. -WH: What do you mean by canonical? +WH: What do you mean by canonical? KG: What I mean is that there is only one string of characters which is accepted by the decoder which decodes to a given sequence of bytes. @@ -623,9 +623,9 @@ KG: I pretty strongly disagree. This proposal is about the serialization and de GCL: I think maybe utf-8 was a poor way to say just like raw strings because I don't think we need to enforce the like well-formedness of Unicode data, but besides hex and base 64. I feel like that would be a very useful thing. That's a thing I run into all the time at least and I'm sure other people do. -KG: I agree that a mechanism for taking a string and getting the binary representation of it according to some particular choice of Unicode encoding is a useful thing. I just don't think that it has anything to do with this proposal. Also it already exists in the web platform so I don't care very much. +KG: I agree that a mechanism for taking a string and getting the binary representation of it according to some particular choice of Unicode encoding is a useful thing. I just don't think that it has anything to do with this proposal. Also it already exists in the web platform so I don't care very much. -GCL: Okay. I would just say that doing it performantly, I guess is a task that is easier thought of than actually implemented, and doing it at the language level could facilitate that. But I guess this is something that can be discussed in the repository more in depth. +GCL: Okay. I would just say that doing it performantly, I guess is a task that is easier thought of than actually implemented, and doing it at the language level could facilitate that. But I guess this is something that can be discussed in the repository more in depth. KG: I want to take a strong stance on this being out of scope for this proposal. I want to say that this proposal is strictly concerned with arbitrary data serialization and deserialization, which has absolutely nothing to do with text encoding, which is what you are asking for. @@ -645,7 +645,7 @@ GCL: Yeah. AKI: How are you doing on clarifying? Are we clarified? All right, Shu. -SYG: I'll fold my two items into one. I want to back Kevin up on the APIs on drawing a strong line. I am not interested in having the scope of this extend into bringing text encoder and text decoder into the JS spec. If that were your goal, I guess I would recommend engaging that as a separate proposal that I wouldn't think has a high chance of succeeding. +SYG: I'll fold my two items into one. I want to back Kevin up on the APIs on drawing a strong line. I am not interested in having the scope of this extend into bringing text encoder and text decoder into the JS spec. If that were your goal, I guess I would recommend engaging that as a separate proposal that I wouldn't think has a high chance of succeeding. GCL: if I wanted to have a separate proposal, that would be, you know, something but I would just want it to not be like a desperate idea from whatever API happens here, which is the reason that I sort of see it as being related to this? so, at the very least, designing this proposal with the idea in mind that further “encodings” may be added in the future. Maybe it is a good way to phrase it. @@ -661,9 +661,9 @@ SYG: No, I'm saying if you want this in scope for this proposal, I am saying, no GCL: okay, I know, I was just saying, if that's the case, I would then say it would be in nice to have in scope for this proposal, not a specific encoding, not specifically like binary encoding but just the ability to... just keeping the design and in a way that allows future expansion nicely with whatever we may want to add in the future without saying what we want to add in the future because we haven't decided that yet. -SYG: That is too abstract of a thing for me to respond to. If you have a concrete thing how, how the API maybe doesn't find one way or another to to not preclude future extensions that you had in mind, then I can respond to that better. +SYG: That is too abstract of a thing for me to respond to. If you have a concrete thing how, how the API maybe doesn't find one way or another to to not preclude future extensions that you had in mind, then I can respond to that better. -AKI: I think it might be time to move on to the next topic. +AKI: I think it might be time to move on to the next topic. SYG: Okay. So my next item is a suggestion. So this is on the arraybuffer types, right? Not TypedArrays? @@ -671,17 +671,17 @@ KG: That is correct, yes. SYG: If it were on - I agree it's kind of weird to have it only on Uint8Array, but if you were on, if it were only on uint8 arrays, you get the shared array buffer stuff for free, you get the slicing for free without copying. I don't know what you think about that. -KG: I don't think you get the shared array buffer stuff for free. For shared array buffers there's the question of whether the buffer is atomic, right? +KG: I don't think you get the shared array buffer stuff for free. For shared array buffers there's the question of whether the buffer is atomic, right? SYG: The whole operation probably is not going to be atomic without actually locking because that's going to be pretty expensive, right? Whether each access is atomic, I think you can just decide when you iterate over to the device, KG: I would want the whole access to get Atomic and SharedArrayBuffers, kind of weird not having that. -SYG: So we can't do that on the main thread, but yeah, we don't have to discuss this during stage one. +SYG: So we can't do that on the main thread, but yeah, we don't have to discuss this during stage one. KG: Yeah, I don't know about doing this without locking. I don't mind also putting this uint8array. I do however think that it belongs on arraybuffer because arraybuffer is the sequence of bytes type in the language and uint8array is, in fact, a sequence of width-8 numbers that is backed by a sequence of bytes. But like I said, I'm okay with putting it on. uint8array as well. Please open an issue to that effect. -AKI: OK. Moving on to Philip. +AKI: OK. Moving on to Philip. PFC: I just wanted to say I support this proposal going to stage 1. I think this is a great tool to have in the toolbox of a language's standard library. @@ -719,21 +719,21 @@ KG: my intention is for this proposal to cover base64 and hex, those two and no WH: I just re-read the spec. The forgiving spec removes whitespace from the string before parsing. On GitHub KG wrote that the only differences between the forgiving and the strict versions are the padding and the overflow bits. So does this mean that the strict version will also ignore whitespace? -KG: My comment on GitHub was mistaken. I had missed the white space difference, +KG: My comment on GitHub was mistaken. I had missed the white space difference, -WH: Okay +WH: Okay KG: My preference is for ignoring white space to be an opt-in feature, like ignoring padding. -WH: So will there be two switches or just one? +WH: So will there be two switches or just one? -KG: I am open to either. I would probably make two. +KG: I am open to either. I would probably make two. WH: Okay. I just wanted to understand the whitespace situation. KG: I apologize for my mistake in comments on github. Thank you. -AKI: All right, we are at time. Shane had added one thing to the queue chain. Can you get through this real quick? +AKI: All right, we are at time. Shane had added one thing to the queue chain. Can you get through this real quick? SFC: Yeah, I just wanted to say that I agree with what Hax said and I think having the encoding as a string argument looks a lot like how Node.js solves this problem. This way, it also would possibly be a way for us to support the URL friendly encoding by just making string encoding like "base64url". @@ -743,7 +743,7 @@ KG: I would like to ask for stage 1. Definitely not stage 2 at this time. It sou PHE: So you read me, right. I really don't think we should. In the interest of letting this work its natural way through, I'm okay with progressing to stage one, but I have a bunch of questions that I guess we should talk about at some point which I'm not confident we're going to be able to address, but I'd be thrilled if somehow we found a way to do it. So I'm okay with stage one, but strong reservations. -KG: I will make sure that is captured in the notes, and please do open issues on GitHub. +KG: I will make sure that is captured in the notes, and please do open issues on GitHub. AKI: if you think will need to be addressed it's also a great reminder for everyone to make sure that you check the notes at the end of the meeting so that you can be sure that your feelings and intent are captured accurately. All right? @@ -763,21 +763,21 @@ DE: So I wanted to present on module fragments. We talked about this a few month DE: So the motivation is that module fragments allow bundling multiple modules in a single file. At first, I thought that we could handle bundling just by general-purpose resource bundles that contain multiple different file types. I still think we should have general-purpose resource bundles, but my understanding is that resource bundles that operate at the network level are just going to be too slow for the huge number of Javascript modules that we have so we probably also want a complimentary JavaScript only bundling format and that's what module fragments can accomplish. So for this basic bundling example, if you declare these modules `countBlock` and uppercase block, then you could declare another module that imports from them and you can see that none of these have quotes around them. So this is kind of the difference. Another aspect of this proposal is that these module fragments are only exported if they have the `export` keyword, so you can import from this private local module fragment and that's possible in the same file and then if something else imports this, then it can also import that export here -MM: you're referring to "different" several times, different from what? +MM: you're referring to "different" several times, different from what? DE: Oh, from the previous draft to this proposal. -MM: Okay, thank you. +MM: Okay, thank you. DE: So just in a self-contained way. if you have this module, priv then it's only accessible here in this same file. Where we have this multiple Pub declared, if you have export, then it can be imported from another file. And we have an example of those Imports in future slide, Module fragments can also be used to declare what's used at runtime in a module block. So here is an example from the actual module blocks explainer, where we have this worker block this module, that's going to be executed in a worker as a parameter to the worker constructor. What this does when it's referred to at runtime in an expression context, is it just evaluates to a module specifier, namely a module block that can be passed around like normal. And you can still use anonymous normal module blocks in the exact same context where you could use one of these. As an example for nested imports - Sorry, this should probably say `export module foo` instead of being on separate lines - but the idea is that you could have a module fragment that you export and then import from another one and then these import statements could still be applied. Or it could be used as a runtime module block value. But yeah, this should definitely be export multiple foo. So that it's statically analyzable or link-time analyzable that you're exporting module. -DE: A possible extension is, if we want module fragments to work with import mmaps, if we want an import map to be able to make it so that your logical module map onto where the modules are stored than we might want to have an extension to import Maps, which addresses them because these are not addressed by strings the way previously in the proposal we discussed before, you would have a URL with it with an actual fragment in it. Now, we need some other way to refer to it. Like maybe this kind of object better so, as I mentioned when with marks question in previous presentation, you would declare a module fragment with this `"#foo"`. Now, all that noise is gone and the reason is the idea of the new proposals that unifies a single mental model between module blocks and module fragments. so for a long time, basically everyone who looked at these proposals said, hey, these should be the same proposal and I said, “no, they can't. That's never going to work.” But the reason I thought this couldn't work is because we need the namespace of this to be statically analyzed. After thinking it through and and talking it over with the incubator group, I think this is fine, actually. Another big piece of motivation was to avoid stomping on the existing, specifier namespace. So hash foo already can be used as a suffix. in both node.js and the web and it has different semantics in these places. I thought it would be okay to shadow that but some of the feedback that I've gotten is that, that's actually not a good design. And finally, this new design exposes non exported module fragments, which was a common feature request. +DE: A possible extension is, if we want module fragments to work with import mmaps, if we want an import map to be able to make it so that your logical module map onto where the modules are stored than we might want to have an extension to import Maps, which addresses them because these are not addressed by strings the way previously in the proposal we discussed before, you would have a URL with it with an actual fragment in it. Now, we need some other way to refer to it. Like maybe this kind of object better so, as I mentioned when with marks question in previous presentation, you would declare a module fragment with this `"#foo"`. Now, all that noise is gone and the reason is the idea of the new proposals that unifies a single mental model between module blocks and module fragments. so for a long time, basically everyone who looked at these proposals said, hey, these should be the same proposal and I said, “no, they can't. That's never going to work.” But the reason I thought this couldn't work is because we need the namespace of this to be statically analyzed. After thinking it through and and talking it over with the incubator group, I think this is fine, actually. Another big piece of motivation was to avoid stomping on the existing, specifier namespace. So hash foo already can be used as a suffix. in both node.js and the web and it has different semantics in these places. I thought it would be okay to shadow that but some of the feedback that I've gotten is that, that's actually not a good design. And finally, this new design exposes non exported module fragments, which was a common feature request. DE: So the important semantic goal of this is that the runtime early namespaces match. So, critically when you import a module fragment, especially in this nested way, where a module exports and module fragments. And then another module Imports that export and then Imports that fragment, this has to all be visible at link time. It has to be visible actually, before link time at the fetch and parse Loop. So it has to be identifiable which module you are importing because that module fragment might contain other static imports that need to be fetched all together, so it's really critically important if we have this kind of compile time or early semantics for bindings that, We really don't want - I think we shouldn't introduce multiple namespaces that programmers have to follow. The way that, e.g. in some languages macros or, I mean, classically in common lisp macros being in like a separate namespace is a thing that's confusing for people. And sorry, that's maybe not the best example but the idea is that these namespaces just correspond with each other. So I think this can work out, just fine if module fragment bindings are const. I think if we say that this is a run-time variable binding, that that maps to this module block, as long as you're not able to overwrite that variable, I think everything matches up. -DE: So with module blocks, which as reminder those are in line anonymous modules that evaluate to a new kind of object that be used as a multiple specifier. we have a unified mental model because module fragments, when they referred to just as a variable evaluate to module blocks. So, module blocks are the base proposal. the module fragments proposal builds on module blocks. I'm still proposing them as separate proposals because module blocks are just a lot simpler and module fragments, by being named, add a lot of complexity on top of them. ModuleModule blocks are useful on their own. Maybe we could consider renaming them to capture this closer kind of unified relationship, like inline modules. +DE: So with module blocks, which as reminder those are in line anonymous modules that evaluate to a new kind of object that be used as a multiple specifier. we have a unified mental model because module fragments, when they referred to just as a variable evaluate to module blocks. So, module blocks are the base proposal. the module fragments proposal builds on module blocks. I'm still proposing them as separate proposals because module blocks are just a lot simpler and module fragments, by being named, add a lot of complexity on top of them. ModuleModule blocks are useful on their own. Maybe we could consider renaming them to capture this closer kind of unified relationship, like inline modules. -DE: So there is a small syntactic conflict with this proposal that Ron (?) raised which is that in typescript module is currently synonym for namespace. They're making ISM for declaring something like math or (?). Which he could do with. You know, with an object literal but you could also do with the namespace, this proposal, semantics do not correspond to typescript semantics and the new syntax without the quotes overlaps with the existing typescript syntax. So, there are a number of possible resolutions to the ambiguity. Maybe typescript could change, maybe this proposal could change, and I think that's something we could work out before stage 3. +DE: So there is a small syntactic conflict with this proposal that Ron (?) raised which is that in typescript module is currently synonym for namespace. They're making ISM for declaring something like math or (?). Which he could do with. You know, with an object literal but you could also do with the namespace, this proposal, semantics do not correspond to typescript semantics and the new syntax without the quotes overlaps with the existing typescript syntax. So, there are a number of possible resolutions to the ambiguity. Maybe typescript could change, maybe this proposal could change, and I think that's something we could work out before stage 3. DE: So far we've discussed this in the incubator group and the tools Outreach group. and I felt like the feedback was generally positive. You can check the notes, I'd previously asked for other Champions people to be involved and I didn't, I apologize for not getting back to people but I hope we can work together in the future here. There's still a lot to do. So, I want to ask the committee just a new design but being based on variables not strings seem like a reasonable path forward. If so, I think the next steps are to update the readme to be in line with this presentation to to write the initial spec text, maybe some tooling support or some playground or something that. And sorry, the slides said proposed for stage 3 but I meant proposed for stage 2,two, not jumping ahead that quickly. So yeah, right now it's in stage 1 would just be proposing for stage 2 and the future. so thanks, that's the presentation and he thank you. @@ -793,7 +793,7 @@ DE: Yeah, yeah, so I think I agree with you. To maybe put it another way these d MM: the static thing itself, the module block is a reification of the static thing. Is there a is the variable that's bound to The name, the static concept? -DE: Yes, +DE: Yes, MM: I see. And the end the export and import is the thing that is referring to an in a linked initialized instance, rather than the static thing? @@ -807,9 +807,9 @@ MM: Okay. So it has the same meaning here as it does if I send it elsewhere, whi DE: I don't know if I understand that question. -MM: If it were locally linked but a unit of communicating code elsewhere that did not communicate is linkage graph, then it's local meaning and the meaning of it as something portable to express behavior let's say on the other side of a realm boundary, or for parameterizing worker creation or something, that the module itself does not carry its linkage graph, its linkage graph has to be provided from the context. +MM: If it were locally linked but a unit of communicating code elsewhere that did not communicate is linkage graph, then it's local meaning and the meaning of it as something portable to express behavior let's say on the other side of a realm boundary, or for parameterizing worker creation or something, that the module itself does not carry its linkage graph, its linkage graph has to be provided from the context. -DE: Yes, that's right. I agree that that mismatch will be bad and I think we're avoiding that mismatch here. +DE: Yes, that's right. I agree that that mismatch will be bad and I think we're avoiding that mismatch here. MM: Okay, so I don't understand. So clearly, when I was listening to the whole proposal, I misunderstood what I was seeing very badly. I like the sound of everything I'm hearing now. So I will need to go over it again and re-understand it, but I do like the sound of everything I'm hearing now. @@ -817,7 +817,7 @@ DE: Okay, I have to say the proposal materials are not in such great shape right MM: And I would also be interested in having you present this again to the SES meeting. Specifically, to make sure that the static module record and the module block are still aligned Concepts where we can expect to unify those as well. -DE: Yeah, I'm happy to discuss it further with the SES group, their comments were really helpful so far. This proposal does not make any changes at all to module blocks. Okay. So everything from that discussion is still valid. +DE: Yeah, I'm happy to discuss it further with the SES group, their comments were really helpful so far. This proposal does not make any changes at all to module blocks. Okay. So everything from that discussion is still valid. MM: great. Thank you. @@ -829,15 +829,15 @@ JWK: OK. GCL: Yeah, just from the know, just from the Node perspective. At least we don't care so much about shoving things over the network. But uses that this provides in terms of, you know, worker APIs and stuff is fantastic. And just, you know, good strong support, this is a Great proposal. -DE: My understanding was that even in the node.js world there was still a relevant thing about startup performance and bundling has been catching on more and more there and for this reason. Especially because of Windows file IO cost, So I thought this would be an important proposal there too. +DE: My understanding was that even in the node.js world there was still a relevant thing about startup performance and bundling has been catching on more and more there and for this reason. Especially because of Windows file IO cost, So I thought this would be an important proposal there too. GCL: yeah, that's a fair point. -DRR: hey, so I think from the typescript perspective there's really two things that I just want to call out the first is what you've already mentioned, in your with the module and namespace sort of Collision there, right? We've really pushed the community to move off of the `module` keyword to proper namespaces just because that's general parlance what they represent. But we really have never pulled the rug out from underneath someone on this on syntax. That's something I think we'll have to speak a little bit more broadly as a team about, so I'll bring that back. The other thing there is something that I've raised in the inline modules proposal discussion, which is just whether or not the tooling can support the sort of scenarios that you have in mind. While bundling is a fine scenario, I don't know how well this can model something like a worker that is in another project context, for example. That has all to do with being able to nest multiple global environments within the same project. That's something that we're not exactly wired up to do. And we don't really have a good sense of how to capture that today. Well today. So that is technically an implementation concern but it's something that I need to be up front with you about now because it's still something that we're not really clear on how we would achieve that. So we don't want you to have a feature that has a crappy developer experience but it is something that will continue to investigate. +DRR: hey, so I think from the typescript perspective there's really two things that I just want to call out the first is what you've already mentioned, in your with the module and namespace sort of Collision there, right? We've really pushed the community to move off of the `module` keyword to proper namespaces just because that's general parlance what they represent. But we really have never pulled the rug out from underneath someone on this on syntax. That's something I think we'll have to speak a little bit more broadly as a team about, so I'll bring that back. The other thing there is something that I've raised in the inline modules proposal discussion, which is just whether or not the tooling can support the sort of scenarios that you have in mind. While bundling is a fine scenario, I don't know how well this can model something like a worker that is in another project context, for example. That has all to do with being able to nest multiple global environments within the same project. That's something that we're not exactly wired up to do. And we don't really have a good sense of how to capture that today. Well today. So that is technically an implementation concern but it's something that I need to be up front with you about now because it's still something that we're not really clear on how we would achieve that. So we don't want you to have a feature that has a crappy developer experience but it is something that will continue to investigate. DE: Yeah. Thanks for bringing up that second point. I mean, we've been discussing that point pretty - kind of on and off, over the recent months, and understanding is that there's already lots of developer excitement about solving this pre-existing problem of getting a better developer experience for those cases. Because juggling multiple projects, even if there are multiple files, is not really fun for anybody. So so, you know, seems like the same opportunity for improving things. -DDR: Yeah, just being forthright with you. +DDR: Yeah, just being forthright with you. JK: Oh, I just wanted to say that we would really strongly support this on Rome. I have wanted something like this in JavaScript for various build tools for a long time. I think there are many tools beyond even just bundling that make use of syntax transforms to replicate some of the sort of isolation of these module blocks provide and I think that this could replace lot of the syntax transforms, or what many people would call "magic" in those tools, so strong support all around. @@ -903,7 +903,7 @@ JRL: There are a few open questions that we have about grouping. The first is wh JRL: There's also a slight issue with python. Python has a standard library package called itertools. Itertools provides a groupby, except it has a subtle difference with the way JavaScript lodash and underscore work. In python groupby combines sequential running groups, and does not combine all groups of the same key. It's easier to just look at my code sample below. So taking 1 2 2 1 and keying on the value, it's giving me three groups here because the first group is 1, I then have 2 sequential 2s which are joined into a single group, and then I have another 1, which will form its own group. Notice that the two `1` groups are not joined together. Python will only group items together if they are sequentially, the exact key. This is different than the way that underscore or lodash work, with this exact same code example. Both will group the 1s together. I'll just have a single 1 group with those two items. I don't know what to do about this, besides renaming it, but there's such strong precedents from lodash and underscore that I'm not sure it's necessary. -JRL: Finally, we have the other thing that I was talking about with the findLast proposal. What do we do about holes in an array? ES6 methods were supposed to standardize on just ignoring holes, pretending they're just undefined and we don't do anything special about them. ES5 methods and strangely flat/flatMap skip holes, they see a hole and they continue on. What is the practical effect of this is shown in this code example, if you have a hole and you groupBy, should that value get turned into undefined in your output groups or should we just skip the item entirely and not call the predicate. Hoping to have discussion one on the array filtering into on the three points. +JRL: Finally, we have the other thing that I was talking about with the findLast proposal. What do we do about holes in an array? ES6 methods were supposed to standardize on just ignoring holes, pretending they're just undefined and we don't do anything special about them. ES5 methods and strangely flat/flatMap skip holes, they see a hole and they continue on. What is the practical effect of this is shown in this code example, if you have a hole and you groupBy, should that value get turned into undefined in your output groups or should we just skip the item entirely and not call the predicate. Hoping to have discussion one on the array filtering into on the three points. JHD: yeah, so this came up when you were joining the filter reject slide, I was curious. Why I named it that instead of just reject which is what like lodash and ruby called it. @@ -911,27 +911,27 @@ JRL: the reason lodash and Ruby and underscore have both a select and they rejec JHD: The lack of a filterSelect doesn't change that at all? -JRL: Well, I initially brought up that we should have a select alias and a reject but I was told we are not going to add an alias. So I've dropped that one. +JRL: Well, I initially brought up that we should have a select alias and a reject but I was told we are not going to add an alias. So I've dropped that one. JHD: Okay. WH: I’m weakly unconvinced about `filterReject`. I just don't see much of a use case for it, and if we do have it, we should call it `reject`. -WH: I'm much more interested in `groupBy`. It seems like a useful thing for grouping things. My concern is about making things which work 99 percent of the time and have weird edge cases like the inheritance problems you mentioned. People will want to use this for database-like things where you get a bunch of results and group them by some part of a key. When that happens, I don't want to have to look up what happens if somebody uses “__proto__” for that key. Or if somebody puts both the value `true` and the string `"true"` in there. So my preference would be to have Maps because that's the most well-behaved kind of output. +WH: I'm much more interested in `groupBy`. It seems like a useful thing for grouping things. My concern is about making things which work 99 percent of the time and have weird edge cases like the inheritance problems you mentioned. People will want to use this for database-like things where you get a bunch of results and group them by some part of a key. When that happens, I don't want to have to look up what happens if somebody uses “__proto__” for that key. Or if somebody puts both the value `true` and the string `"true"` in there. So my preference would be to have Maps because that's the most well-behaved kind of output. -JRL: I could agree to that. I don't feel strongly enough about any of the three options to force anything here. I think all three options are valuable and the only reason prefer the regular object is just because of the ecosystem precedent. +JRL: I could agree to that. I don't feel strongly enough about any of the three options to force anything here. I think all three options are valuable and the only reason prefer the regular object is just because of the ecosystem precedent. WH: Yeah. -JRL: I think the ecosystem standardized back when we still had ES5, and we didn't have Maps at that point, it may be more appropriate to choose Map as our output now. +JRL: I think the ecosystem standardized back when we still had ES5, and we didn't have Maps at that point, it may be more appropriate to choose Map as our output now. -WH: Yeah, I definitely don't want regular objects. Objects with no prototype would be significantly better, but then we have to decide what the keys are — whether the keys are always strings or whether you can have symbols. Maps seem the safest approach. +WH: Yeah, I definitely don't want regular objects. Objects with no prototype would be significantly better, but then we have to decide what the keys are — whether the keys are always strings or whether you can have symbols. Maps seem the safest approach. JH: I would prefer null objects. It's very, very strongly over an app apps or simply not useful enough because they have like no helper methods or not enough. So I agree with the inheritance inference returning an `Object.prototype` would be unwise for groupBy. -BSH: I just want to say regarding the python thing reason, it has that behavior that python version of group by is because it acts on a potentially infinite iterable. So it can't group together. It's really different use case, if we're only doing, definitely finite arrays. I don't think we have to worry about that difference. +BSH: I just want to say regarding the python thing reason, it has that behavior that python version of group by is because it acts on a potentially infinite iterable. So it can't group together. It's really different use case, if we're only doing, definitely finite arrays. I don't think we have to worry about that difference. -MF: I have a couple things to say and I like to echo what Bradford just said there. Haskell has the same behavior again because of infinite lists there. It's called groupBy. So, maybe the name we'll have to talk about. But as you mentioned in the JavaScript ecosystem, I think it's fairly common to call the operation you're proposing groupBy. So I don't think it should be an issue. I am pretty excited about groupBy. I think that it covers the original use case that you had with filtering fairly well and I'm excited to see the other things that it will solve because it has much more flexibility. As far as the proposal just to do a rejection method. I am not very supportive of that route, I am still not convinced that it would have the kind of discoverability that would help people make the decision about filtering in versus out. I don't really think it will help too much there. +MF: I have a couple things to say and I like to echo what Bradford just said there. Haskell has the same behavior again because of infinite lists there. It's called groupBy. So, maybe the name we'll have to talk about. But as you mentioned in the JavaScript ecosystem, I think it's fairly common to call the operation you're proposing groupBy. So I don't think it should be an issue. I am pretty excited about groupBy. I think that it covers the original use case that you had with filtering fairly well and I'm excited to see the other things that it will solve because it has much more flexibility. As far as the proposal just to do a rejection method. I am not very supportive of that route, I am still not convinced that it would have the kind of discoverability that would help people make the decision about filtering in versus out. I don't really think it will help too much there. JRL: I speak with experience. Whenever I try to write a filter method. I first think as if I could have written a filterReject. So it does help me even though it doesn't exist, but that doesn't help anyone else because it doesn't exist for anyone else to use. Google has an internal meeting before each tc39. also a strong supporter of a filter reject method because he also sees filtration the exact same way that I do. And so he screws up just like I did. @@ -961,7 +961,7 @@ JRL: I heard two parts to that. One about filterReject, and I believe that filte JHX: Yeah, I agree with you. -JHX: My next point is, naming is always a bikeshed issue. I want to point out that filterReject. may have some conflict with Promise.reject. There are other contexts where we use the same word, but it seems avoidable. But I really hope if we have other choices I would like to see other words, not reject. +JHX: My next point is, naming is always a bikeshed issue. I want to point out that filterReject. may have some conflict with Promise.reject. There are other contexts where we use the same word, but it seems avoidable. But I really hope if we have other choices I would like to see other words, not reject. JRL: Thank you. I actually had that same opinion brought up when I was calling it select/reejct. I was hoping that filterReject would avoid any confusion because it starts with filter. Because then I felt like it was more closely associated with filtering than with promise rejection. @@ -971,7 +971,7 @@ JRL: I don't think it's appropriate to ask for stage 2 on groupBy. So I'll ask f MF: I would not support stage 2 on filterReject until we've done further research on whether groupBy solved the originally stated problem here because I feel that if we have grouped by and it is a solution to your originally stated problem that we do not need filterReject. -JRL: Okay. +JRL: Okay. IID:(?): Yeah, Mozilla agrees. @@ -983,7 +983,7 @@ MM: Thank you. I would feel uncomfortable -I understand the argument Aki made, b JRL: okay, so I think I'm with the resolution here. I'm definitely going to split groupBy into its own proposal, and then, I'm just asking stage 1 for `groupBy`. -WH: Sounds good. I support stage 1 for `groupBy`. +WH: Sounds good. I support stage 1 for `groupBy`. MF: Great. I don't want to be difficult here, but like Aki was saying earlier, stage one is about defining a problem. Stage two is about selecting a solution. "groupBy for stage 1", I don't think is a meaningful statement here. We can be trying to solve just your filtering problem or trying to solve the problems that group by solves. We're not trying to group by if that makes sense. @@ -991,7 +991,7 @@ MM: Okay, groupBy solves a much bigger range of problems. So I would certainly. MF: I'm fine with that. Please Justin in your description in your repository, address the problem and not just the solution. -WH: I take a different procedural position and I would say that, in my opinion, the `groupBy` proposal is almost at stage 2. We already have spec text for it, with the only modulo being that I would want the prototype gone from the produced objects and possibly a Map version. +WH: I take a different procedural position and I would say that, in my opinion, the `groupBy` proposal is almost at stage 2. We already have spec text for it, with the only modulo being that I would want the prototype gone from the produced objects and possibly a Map version. JRL: So, I think with agreement that the Prototype object has to be changed to use object.create(null), or we have to use a Map, or a solution that does both. I think that's an agreement. There's also holes, which I think we still need to discuss but we can do that at stage one, and naming, which I think we're in agreement that just normal "groupBy" is fine. I think that is what I'm proposing to go to the stage one, that agreement @@ -1001,7 +1001,7 @@ JRL: I agree. AKI: Do we have a conclusion to record here? -JRL: I'm hoping the conclusion is groupBy reaches stage one. +JRL: I'm hoping the conclusion is groupBy reaches stage one. JHD: Can we come up with a name for the problem that groupBy solves and perhaps grouping with its own repo. Okay. And then that addresses Michael's point and then filter rejected be discussed separately. @@ -1009,13 +1009,13 @@ JRL: That seemed reasonable. So I'm asking for "array grouping" to go to Stage 1 [general agreement] -JRL: Okay, then I'm being blocked from reaching stage 2 for filterReject pending progress on array grouping. +JRL: Okay, then I'm being blocked from reaching stage 2 for filterReject pending progress on array grouping. -MM: I'm just un-enthused about `filterReject` period. +MM: I'm just un-enthused about `filterReject` period. -AKI: Is that the same thing as blocking consensus? I'm sorry. I'm a little bit unclear. +AKI: Is that the same thing as blocking consensus? I'm sorry. I'm a little bit unclear. -MM: So what am I agreeing to? If I were to agree to stage two, I'm sorry I keep having to for a refresher as almost What is the implication of advancing solution? +MM: So what am I agreeing to? If I were to agree to stage two, I'm sorry I keep having to for a refresher as almost What is the implication of advancing solution? MF: I would not like `filterReject` to advance to stage 2 until `groupBy` has had further progress, so it should not advance to stage 2 today. I don't think we need to go into process discussion right now. diff --git a/meetings/2021-12/dec-15.md b/meetings/2021-12/dec-15.md index 470a1496..6b7aedb0 100644 --- a/meetings/2021-12/dec-15.md +++ b/meetings/2021-12/dec-15.md @@ -299,30 +299,30 @@ RPR: You still have 10 minutes in the time box. ## Decorators Update: Removing @init -Presenter: Chris Garrett (CHG) +Presenter: Kristen Hewell Garrett (KHG) - [proposal](https://github.com/tc39/proposal-decorators/) - [slides](https://slides.com/pzuraq/decorators-update-2021-07-cedd5b) -CHG: Okay, cool. So yeah, this is just going to be a quick update on the decorators proposal. There's some changes that we made recently in preparation for proposing for moving to stage three which were hoping to do at the next meeting in January. So I just wanted to run these changes by the committee now so that people understand that they're coming and everything. Cool so quick refresher on the capabilities of decorators. These are the fundamental capabilities that we decided that decorators would be responsible for and every decorator kind of has the ability to do these things. So the core ones were replacement. So being able to replace the value, that is being decorated with a like kind of value a method with a method, a field with a field on and so forth. Metadata, so you would be able to associate some metadata with that value, which could then be read by other code. And then access so that is basically giving the ability to access that value out to other and that could be, you know, with public values. That's pretty easy. You just give the name of the property of the value and then you can access it. But this was really important for private. Is where you may want to be able to set or get a private value through some friend code. There was a fourth capability, which was initialization and this was really important for certain use cases like the bounds decorator. but because of the original constraints we had we ultimately couldn't allow every decorator to just have an initialization because otherwise Is it would result in a very Dynamic kind of execution path? And that's why we added this extra syntax @init and so at an it gives when used with a decorator. It gives that decorator the ability to, to initialize the value. So quick refresher on that: adding an @ to the beginning of a value of a decorator like so, adds this @ initializer function to the context provided to that decorator and you can then pass a function into that initializer to initialize the add value. And so, originally Clash elements initializers would run during construction. They would run at the same time as class fields, and they would eat interleaved with class fields. And yeah, so that's basically initializers and added it in a nutshell. So like I said originally this was motivated to make decorators more statically analyzable. Basically, we had the situation where, you know, a decorator could be defined on a method between a few class fields and the idea was that the initializers would run in order. You start with, in this example, here you'd have an uninitialized field assigned first. You would have the initializers for method called s and then you would have the initialized field assigned to last. So, the reason I made this example here is to demonstrate one of the issues we found with this approach. It was really all in all a very controversial approach. It was very confusing to users. It meant they had put it on every usage of a decorator that required initializers and it also ended up in this case where you would have a really confusing behavior, where the fields, the for a method could reference the method before it had been initialized. So there was a period of time a method or another initialized value would be visible without those initializations. And that could be pretty confusing behavior to folks. So, yeah, basically, nobody really liked this behavior and everybody thought it was pretty confusing, but we were originally keeping it around for the performance constraints. So, after some discussions with folks, we actually decided that there was a way we could remove it and still meet these performance constraints. So that the updated proposal initialization is now considered a core capability of decorators. So it is now the fourth capability that they provide initialization is provided in one of two ways either for elements that are per instance like fields. They can already replace the initializer of the field so you can just call additional code during that initializer. And for elements that are part of class such as methods that are assigned once to the Prototype, Prototype, you can add additional initializers without initializer. That will run / for every instance, and these initializers are run all at once. So before class fields are assigned, they are run, so that class fields and other user code has no chance to see the uninitialized version of the method. In addition, because they are run all at once we no longer have to deal with the interleaving class fields and decorator initializers, which means from a performance perspective there's only one check that needs to be admitted for a decorated method to see if any initializers were added. So we're no longer having to add a bunch of additional complex code for class field in between class field initializers. There is one other consequence to this change. Previously it possible to have a decorator on class field specifically that could change the enumerability of that or other aspects the right ability using an it and how this would work is you would essentially have the fields would be defined on the instance and then it would immediately be redefined with the decorators initializer. So this capability is no longer provided in the same way because the only way you can decorate fields is by replacing their initializer. The only way you can initialize them is with their initializer. We saw this as not being a huge issue because this was never a capability that was designed for. It was just one that kind of fell out and it also was never a capability that was provided across the board with this particular proposal. instance. You could have done this type of decorator with fields. You could not do it in an efficient way with methods, since initializers run once. For instance, not once per brother-type(?). So the opinion we came to was that this type of capability should be provided by a different behavior in order for decorators to maintain their static analyzability and all the other things that we designed them for. Yeah, that's pretty much it, any questions? +KHG: Okay, cool. So yeah, this is just going to be a quick update on the decorators proposal. There's some changes that we made recently in preparation for proposing for moving to stage three which were hoping to do at the next meeting in January. So I just wanted to run these changes by the committee now so that people understand that they're coming and everything. Cool so quick refresher on the capabilities of decorators. These are the fundamental capabilities that we decided that decorators would be responsible for and every decorator kind of has the ability to do these things. So the core ones were replacement. So being able to replace the value, that is being decorated with a like kind of value a method with a method, a field with a field on and so forth. Metadata, so you would be able to associate some metadata with that value, which could then be read by other code. And then access so that is basically giving the ability to access that value out to other and that could be, you know, with public values. That's pretty easy. You just give the name of the property of the value and then you can access it. But this was really important for private. Is where you may want to be able to set or get a private value through some friend code. There was a fourth capability, which was initialization and this was really important for certain use cases like the bounds decorator. but because of the original constraints we had we ultimately couldn't allow every decorator to just have an initialization because otherwise Is it would result in a very Dynamic kind of execution path? And that's why we added this extra syntax @init and so at an it gives when used with a decorator. It gives that decorator the ability to, to initialize the value. So quick refresher on that: adding an @ to the beginning of a value of a decorator like so, adds this @ initializer function to the context provided to that decorator and you can then pass a function into that initializer to initialize the add value. And so, originally Clash elements initializers would run during construction. They would run at the same time as class fields, and they would eat interleaved with class fields. And yeah, so that's basically initializers and added it in a nutshell. So like I said originally this was motivated to make decorators more statically analyzable. Basically, we had the situation where, you know, a decorator could be defined on a method between a few class fields and the idea was that the initializers would run in order. You start with, in this example, here you'd have an uninitialized field assigned first. You would have the initializers for method called s and then you would have the initialized field assigned to last. So, the reason I made this example here is to demonstrate one of the issues we found with this approach. It was really all in all a very controversial approach. It was very confusing to users. It meant they had put it on every usage of a decorator that required initializers and it also ended up in this case where you would have a really confusing behavior, where the fields, the for a method could reference the method before it had been initialized. So there was a period of time a method or another initialized value would be visible without those initializations. And that could be pretty confusing behavior to folks. So, yeah, basically, nobody really liked this behavior and everybody thought it was pretty confusing, but we were originally keeping it around for the performance constraints. So, after some discussions with folks, we actually decided that there was a way we could remove it and still meet these performance constraints. So that the updated proposal initialization is now considered a core capability of decorators. So it is now the fourth capability that they provide initialization is provided in one of two ways either for elements that are per instance like fields. They can already replace the initializer of the field so you can just call additional code during that initializer. And for elements that are part of class such as methods that are assigned once to the Prototype, Prototype, you can add additional initializers without initializer. That will run / for every instance, and these initializers are run all at once. So before class fields are assigned, they are run, so that class fields and other user code has no chance to see the uninitialized version of the method. In addition, because they are run all at once we no longer have to deal with the interleaving class fields and decorator initializers, which means from a performance perspective there's only one check that needs to be admitted for a decorated method to see if any initializers were added. So we're no longer having to add a bunch of additional complex code for class field in between class field initializers. There is one other consequence to this change. Previously it possible to have a decorator on class field specifically that could change the enumerability of that or other aspects the right ability using an it and how this would work is you would essentially have the fields would be defined on the instance and then it would immediately be redefined with the decorators initializer. So this capability is no longer provided in the same way because the only way you can decorate fields is by replacing their initializer. The only way you can initialize them is with their initializer. We saw this as not being a huge issue because this was never a capability that was designed for. It was just one that kind of fell out and it also was never a capability that was provided across the board with this particular proposal. instance. You could have done this type of decorator with fields. You could not do it in an efficient way with methods, since initializers run once. For instance, not once per brother-type(?). So the opinion we came to was that this type of capability should be provided by a different behavior in order for decorators to maintain their static analyzability and all the other things that we designed them for. Yeah, that's pretty much it, any questions? RGN: Yeah, I wanted to thank you for the I'm thrilled to see it and enthusiastically supported. Thank you. SYG: Could you go back to the slide that had the new semantics? I also like to apologize that I know you are mailed me for feedback and I've been swamped. I haven't been able to. So, okay. So the thing I was confused about here was initializers run all at once before class fields are assigned. So the idea here, let's take a number. Let's take number one first. You can do initialization by replacing the field initializer. So, in that case, all the ones that are replaced. Those fields conceptually have like an equals undefined then the replacement initializer run at the end after all the on replace decorators have run. -CHG: So initializers for fields, the way the way decorators for fields work is you can return a function that receives it basically pipelines. So that the decorator receives the initial value of the field, the first decorator, and then Returns the new value. And the idea is that you can also go if you need to run additional initialization code for that. You can also run that code during that initializer because that initializer has access to the class instance. It has, it can do anything that a class field initializer can do. So the only thing that it can't do is redefine the field after it's been assigned, because it doesn't runt at the same time, you can't do that in a normal class field initializer. +KHG: So initializers for fields, the way the way decorators for fields work is you can return a function that receives it basically pipelines. So that the decorator receives the initial value of the field, the first decorator, and then Returns the new value. And the idea is that you can also go if you need to run additional initialization code for that. You can also run that code during that initializer because that initializer has access to the class instance. It has, it can do anything that a class field initializer can do. So the only thing that it can't do is redefine the field after it's been assigned, because it doesn't runt at the same time, you can't do that in a normal class field initializer. SYG: Okay, so what does it mean that initializes run all at once before class fields are assigned. What those initializes? -CHG: Additional initializers added via @, initializer per class initializer. So initializers for methods for accessors the. Yeah, those and I think that's a anything that is not a field. +KHG: Additional initializers added via @, initializer per class initializer. So initializers for methods for accessors the. Yeah, those and I think that's a anything that is not a field. SYG: Okay. So for fields the mechanism of initialization is only via replacement and for non fields. It's via at it at initializer and those additional initializers are the ones that that slide is referring to when it says run. All at once before class fields are assignment? -CHG: Correct? +KHG: Correct? SYG: Okay, I see so and then it's fine that for your use case that those initializers do not any fields. -CHG: Yeah. +KHG: Yeah. SYG:, I see. Okay. I think this is fine from implementation perspective for how these are compiled for field initialization. Yeah, I think this is okay. And I do agree that if you can work around it and the use cases allow for it, not having the extra syntax. Does seem better for the users. @@ -330,21 +330,21 @@ RBR: That minutes left on the find box. Yulia is on the cape. YSV: So we also reviewed this to see if there were any remaining issues that we had with like dynamically initialize class fields, and it looks fine and I want to Echo what you said. The thing is we would like a bit more time to digest because we haven't looked at this for a while. So we did read-through but we don't think we did due diligence yet and would just basically like more time. But otherwise from what we have seen it looks okay. -CHG: Okay. That sounds great. When say you would like more time, the mean you would like more time before we pose moving to stage 3 or just in general more time? +KHG: Okay. That sounds great. When say you would like more time, the mean you would like more time before we pose moving to stage 3 or just in general more time? YSV: But to be completely honest, we haven't looked in depth at the decorators proposal for a while. So if you go to stage three, can you give us a heads up of about a month. -CHG: Yeah. Absolutely. I mean, the current plan was to try to go to stage three in January, But if it sounds like that won't be enough time. We could move to next, plenary, after that +KHG: Yeah. Absolutely. I mean, the current plan was to try to go to stage three in January, But if it sounds like that won't be enough time. We could move to next, plenary, after that YSV: if you can, then that would be great. But that would that would give us a chance to actually fully review everything again. -CHG: That sounds good. We’ll do that. +KHG: That sounds good. We’ll do that. RPR: Okay, one minute left and Philip on the queue, okay. PFC: Did I understand correctly that initializers would be able to see static fields, but not instance fields? -CHG: Initializers for static methods, will not be able to see static fields because they run before static methods. The Initialization, like thoughts construction, If you will, the equivalence will work exactly the same way. Static methods and accessors. Their initializers will run first, then, static Fields, classes will assigned. Then the well, I guess there isn't a Constructor equivalent. So static blocks will run interleaved with the class fields. So then for methods that are static, yes, their initializers will be able to see static fields because the instance necessarily is constructed. Constructed after the class has been fully defined. +KHG: Initializers for static methods, will not be able to see static fields because they run before static methods. The Initialization, like thoughts construction, If you will, the equivalence will work exactly the same way. Static methods and accessors. Their initializers will run first, then, static Fields, classes will assigned. Then the well, I guess there isn't a Constructor equivalent. So static blocks will run interleaved with the class fields. So then for methods that are static, yes, their initializers will be able to see static fields because the instance necessarily is constructed. Constructed after the class has been fully defined. RPR: Okay, I think we have to wrap it up there. So I'll time box has expired. Okay. All right, I thank you for your time. time. Chris decorate us is always exciting. Okay. Last up from this session. Is Sarah with decimal. diff --git a/meetings/2022-03/mar-28.md b/meetings/2022-03/mar-28.md index 4749ac8b..abef3ca8 100644 --- a/meetings/2022-03/mar-28.md +++ b/meetings/2022-03/mar-28.md @@ -697,30 +697,30 @@ USA: Yes. Thank you TAB. Yeah, so regarding stage advancement, there are concern ## Decorators for Stage 3 -Presenter: Chris Garret (CHG) +Presenter: Chris Garret (KHG) - [proposal](https://github.com/tc39/proposal-decorators) - [slides](https://slides.com/pzuraq/decorators-for-stage-3-2022-03) -CHG: So my name is Chris, and I'm here to present decorators for stage 3. This presentation is mostly just going to be a recap because the proposal has not changed significantly since the previous plenaries, when we have discussed dated brought up updates and what not. So, yeah, we'll just dig right into it. +KHG: So my name is Chris, and I'm here to present decorators for stage 3. This presentation is mostly just going to be a recap because the proposal has not changed significantly since the previous plenaries, when we have discussed dated brought up updates and what not. So, yeah, we'll just dig right into it. -CHG: So, first off, what is a decorator? Decorators are functions and they have four main capabilities that they can do when applied to a class or class elements. They can replace the element with one. That is a like-kind. like-kind. They can initialization for the elements specifically whenever the instance of the class is initialized and then they can add metadata, which could be read externally from the class and they provide access to the value, which is particularly important for private elements. So first up replacement so decorators, receive the original value. that is being decorated and they can replace You that has the same shape. So methods can be replaced with new methods and The Decorator receives the method or Fields. The value that is to replace is the initial value of the field. Not the initializer function itself. That was primarily for performance concerns, I believe. and then you just generally can't change the shape of the value that is being decorated. So this is something that previous proposals could do you could change a method into a field, a field into a getter and on and so forth In this proposal, it really is just you are replacing like with like so that's the first capability. +KHG: So, first off, what is a decorator? Decorators are functions and they have four main capabilities that they can do when applied to a class or class elements. They can replace the element with one. That is a like-kind. like-kind. They can initialization for the elements specifically whenever the instance of the class is initialized and then they can add metadata, which could be read externally from the class and they provide access to the value, which is particularly important for private elements. So first up replacement so decorators, receive the original value. that is being decorated and they can replace You that has the same shape. So methods can be replaced with new methods and The Decorator receives the method or Fields. The value that is to replace is the initial value of the field. Not the initializer function itself. That was primarily for performance concerns, I believe. and then you just generally can't change the shape of the value that is being decorated. So this is something that previous proposals could do you could change a method into a field, a field into a getter and on and so forth In this proposal, it really is just you are replacing like with like so that's the first capability. -CHG: Second capability is initialization. So method decorators and class decorators can call addinitializer to add a function which will run when the class instance or the class itself is first created. So for static methods, and for the class itself, this will run Immediately after class definition or during class definition and right around that time and yeah, for Fields decorators because they already basically run code during the initialization step. There's no ability to add an additional initializer. the idea being that you can run, whatever initialization code you need at that time, one important thing to note about Method initializers here is that they run before class fields are assigned. So they run all at once at the beginning, right after super right before class fields are assigned. And this partially for performance reasons, so we don't have to like constantly be tracking where methods are and like when they need to be initialized relative to fields. It's, but it's also for consistency reasons. This way fields and field initializers can't see an initialized and an uninitialized version of a method. The method initializers, all finish, whatever they're doing possibly in this example, for instance, binding, the, the method before, you know the field, any of the fields can run. So user code in general, won't be exposed to that. +KHG: Second capability is initialization. So method decorators and class decorators can call addinitializer to add a function which will run when the class instance or the class itself is first created. So for static methods, and for the class itself, this will run Immediately after class definition or during class definition and right around that time and yeah, for Fields decorators because they already basically run code during the initialization step. There's no ability to add an additional initializer. the idea being that you can run, whatever initialization code you need at that time, one important thing to note about Method initializers here is that they run before class fields are assigned. So they run all at once at the beginning, right after super right before class fields are assigned. And this partially for performance reasons, so we don't have to like constantly be tracking where methods are and like when they need to be initialized relative to fields. It's, but it's also for consistency reasons. This way fields and field initializers can't see an initialized and an uninitialized version of a method. The method initializers, all finish, whatever they're doing possibly in this example, for instance, binding, the, the method before, you know the field, any of the fields can run. So user code in general, won't be exposed to that. -CHG: So next up is metadata. So, metadata has a variety of use cases. One of the most common use cases is for dependency injection. So figuring out, which value should be injected on a particular field, or in a particular, like, in the Constructor or something like that. Metadata is defined using `setMetadata`, which is passed in on the decorators context object. And it is keyed on a symbol. So you have to create a symbol, which you set metadata to and then metadata ends up on the `Symbol.metadata` property on the class itself. And it's accessible via like your symbol key and it's split up between own metadata, which is the classes of metadata public metadata, and private metadata, and there's actually a mistake. See that prototype symbol, that metadata the first line right there that.own. That should actually be just see, symbol that metadata. So static metadata goes on the class itself and instance, quote unquote metadata, like methods that are non static and whatnot and Fields goes on the Prototype. Metadata is inherited. So you can very easily read the metadata for a particular class and also see what its parents metadata is through that. Like it uses prototypical inheritance itself. So just mirrors the class exactly for public metadata for private metadata. There is no for, you know, a private field to shadow a parent field. So private metadata. Is just kept in an array. So yeah. And lastly access. So as I mentioned before, decorators provide That's to whatever the value is and this is particularly important for private fields private methods. So for instance, if you wanted to create a dependency injection decorator, which in was able to inject a value onto a field, you would need some way to set that Fields. So that's what this access object provides. And it basically just provides a get function and a set function, that can be used to get or set the value. You have to call the function with the target the class itself. This is pretty standard for decorators in general, like, having to use `call` or `apply`. So yeah, this is a pi. Should generally be pretty intuitive to decorator author. Yeah, and you can only get values that are generally gettable. So like Fields, gutters methods and set values that are settable like fields and Setters. You can't set a method because generally, that's not something you do and for private methods it's actually not possible. +KHG: So next up is metadata. So, metadata has a variety of use cases. One of the most common use cases is for dependency injection. So figuring out, which value should be injected on a particular field, or in a particular, like, in the Constructor or something like that. Metadata is defined using `setMetadata`, which is passed in on the decorators context object. And it is keyed on a symbol. So you have to create a symbol, which you set metadata to and then metadata ends up on the `Symbol.metadata` property on the class itself. And it's accessible via like your symbol key and it's split up between own metadata, which is the classes of metadata public metadata, and private metadata, and there's actually a mistake. See that prototype symbol, that metadata the first line right there that.own. That should actually be just see, symbol that metadata. So static metadata goes on the class itself and instance, quote unquote metadata, like methods that are non static and whatnot and Fields goes on the Prototype. Metadata is inherited. So you can very easily read the metadata for a particular class and also see what its parents metadata is through that. Like it uses prototypical inheritance itself. So just mirrors the class exactly for public metadata for private metadata. There is no for, you know, a private field to shadow a parent field. So private metadata. Is just kept in an array. So yeah. And lastly access. So as I mentioned before, decorators provide That's to whatever the value is and this is particularly important for private fields private methods. So for instance, if you wanted to create a dependency injection decorator, which in was able to inject a value onto a field, you would need some way to set that Fields. So that's what this access object provides. And it basically just provides a get function and a set function, that can be used to get or set the value. You have to call the function with the target the class itself. This is pretty standard for decorators in general, like, having to use `call` or `apply`. So yeah, this is a pi. Should generally be pretty intuitive to decorator author. Yeah, and you can only get values that are generally gettable. So like Fields, gutters methods and set values that are settable like fields and Setters. You can't set a method because generally, that's not something you do and for private methods it's actually not possible. -CHG: So yeah, that's The last bit, here is the `accessor` keyboard, which is included in this proposal. It is somewhat orthogonal functionality, but it is very important for another very common decorator use case, which is to create reactive values. So what accessor allows us to do, is it installs a getter and Setter for a private field, Essentially that can be used or On a field rather, which is then backed by private storage and that getter and Setter can be used to be decorated to intercept whenever a value is accessed, and whenever a value is updated, so that you can track value and generally react to updates on that value. Yeah, that's pretty much it. So update since the last meeting. So initialise on accessor decorators, return values has renamed to `init`, the idea here. was that initial has an initializer can are both common kind of words used here and they could get quite confusing. In fact, we made a typo when we were implementing the Babel transform for this. So this was a bug. Popped up for us and `init` is just simpler, shorter, easier to remember. So we thought we would make that change. We've also included the `access` object for public elements. Previously. It was only for private elements, but for consistency sake, we added it for public elements. The idea was that you could just use the name of the public element to access it, but adding this just makes it easier for people to have more consistent decorator, handling code, and whatnot. `constructor` on metadata has been renamed to `own`. so previously it was named ‘constructor’. It was just the class itself, The metadata for the class itself, but that's somewhat confusing. Because you know, there are properties named ‘constructor’ in relation to classes already. And also, it seems like it wouldn't be forward compatible. Like if we ever wanted to add metadata, you know, and decorators for plain functions. for instance, that could get confusing, and we'd have to have another, you know, field on the metadata objects, ‘own’ kind of makes sense. It's like the value that is being decorated here. So, yeah, and then the spec has been fully written. It is fully updated. It has been reviewed by a number of members. so far and yeah, there's been some some good feedback. And yeah, it's pretty much everything. I'm asking for advancement to stage 3. any comments. +KHG: So yeah, that's The last bit, here is the `accessor` keyboard, which is included in this proposal. It is somewhat orthogonal functionality, but it is very important for another very common decorator use case, which is to create reactive values. So what accessor allows us to do, is it installs a getter and Setter for a private field, Essentially that can be used or On a field rather, which is then backed by private storage and that getter and Setter can be used to be decorated to intercept whenever a value is accessed, and whenever a value is updated, so that you can track value and generally react to updates on that value. Yeah, that's pretty much it. So update since the last meeting. So initialise on accessor decorators, return values has renamed to `init`, the idea here. was that initial has an initializer can are both common kind of words used here and they could get quite confusing. In fact, we made a typo when we were implementing the Babel transform for this. So this was a bug. Popped up for us and `init` is just simpler, shorter, easier to remember. So we thought we would make that change. We've also included the `access` object for public elements. Previously. It was only for private elements, but for consistency sake, we added it for public elements. The idea was that you could just use the name of the public element to access it, but adding this just makes it easier for people to have more consistent decorator, handling code, and whatnot. `constructor` on metadata has been renamed to `own`. so previously it was named ‘constructor’. It was just the class itself, The metadata for the class itself, but that's somewhat confusing. Because you know, there are properties named ‘constructor’ in relation to classes already. And also, it seems like it wouldn't be forward compatible. Like if we ever wanted to add metadata, you know, and decorators for plain functions. for instance, that could get confusing, and we'd have to have another, you know, field on the metadata objects, ‘own’ kind of makes sense. It's like the value that is being decorated here. So, yeah, and then the spec has been fully written. It is fully updated. It has been reviewed by a number of members. so far and yeah, there's been some some good feedback. And yeah, it's pretty much everything. I'm asking for advancement to stage 3. any comments. MM: Well, hi, the. Could you go back to the slide where you the identifier all caps exposed? So what is - oh, I'm sorry, I missed it. It's right there on line one. So, all of this really devolves to my second question, which is what is the API of the context object? Was there any time where he's holed up together? -CHG: I did not add that on my slide. Sorry, It's been in the proposal for quite a long time now, and I didn't know how much I should include in terms of the updates. You can show it in the context object. Is right here. +KHG: I did not add that on my slide. Sorry, It's been in the proposal for quite a long time now, and I didn't know how much I should include in terms of the updates. You can show it in the context object. Is right here. MM: Okay, and is there and the context object that's passed to a given decorator? Is that specific to the thing that decorator, that, you know that occurrence of that decorator is decorating, and does the context object only have the power to manipulate the thing being decorated. There's no ability to use the context object to like add data to something else. Yes, so, the context object is recreated currently in the spec, per decorator. I kind of went back and forth on whether or not it should be like reusable or whatnot, but I've opted on the side of the making it new each time so let, you know, there wasn't a chance of leakage and these methods that are passed in, for instance, also are all like they'll throw an error if you to call them outside of the context of that decorator outside of the roadside like immediately after there's actually bug, I need to fix in the spec because if it if it throws an error currently, it doesn't directly handle that. But the intention is that if you attempt to call them outside of the usage of this, it will throw an error. MM: Okay, so it's disabled when you're out the outside of the dynamic scope and presumably when you're inside, right? Okay. So if you're inside, you can use the console that all make sense once Once the think, once the thing being decorated has been decorated, there shouldn't be any more usability of the context object. The reason for the arbitrary symbol on the metadata is that you're associating the metadata with the pair of the symbol and the thing being that Ready? -CHG: Yes, so metadata is looked up quite often. Usually by particular decorator libraries. And the shape of the metadata objects allows people to that. We've designed allows decorators to look up that value very quickly, easily if they know that symbol we kind of went back and forth on this. There is an alternative idea of a very simple metadata format, which wouldn't even have a symbol. It would just add a value onto an array. The, the downside there would be that, you know, every decorator would have to then re-implement that look up to find its values and cache them and so on and so forth. it's kind of a trade-off there and we were we We ended up going with the one. We felt would be more performance in real-life usage because you know, the previous reasons this proposal did not Advance where specifically around performance. So we wanted to make it as performant as possible. +KHG: Yes, so metadata is looked up quite often. Usually by particular decorator libraries. And the shape of the metadata objects allows people to that. We've designed allows decorators to look up that value very quickly, easily if they know that symbol we kind of went back and forth on this. There is an alternative idea of a very simple metadata format, which wouldn't even have a symbol. It would just add a value onto an array. The, the downside there would be that, you know, every decorator would have to then re-implement that look up to find its values and cache them and so on and so forth. it's kind of a trade-off there and we were we We ended up going with the one. We felt would be more performance in real-life usage because you know, the previous reasons this proposal did not Advance where specifically around performance. So we wanted to make it as performant as possible. MM: Okay, thanks. I think that's it for my questions. @@ -728,49 +728,49 @@ next up, we have three topics with the same general idea. So first up, we have J JWK: Hello. So I see because of the feedback from the V8 team, the decorator proposal has a new PR to make a big change on the metadata API, and I don't think that new API looks good to me. So, please consider more about that's part. Thanks. And if you are really going to simplify the metadata API, please at least preserve the symbol-keyed parts, I have already commented in that pull request. -CHG: Yeah, my my feedback in the pull request. I think remains the same. We The feedback we got was so far, has been that the metadata API is fairly complex and really, the idea of that change is to it as simple as possible and the symbol, the splitting things out by the symbol and assigning metadata to a symbol doesn't really seem to it. Kind of just is somewhere in the middle arbitrarily without really a good reason for it, Like, either performance or, you know +KHG: Yeah, my my feedback in the pull request. I think remains the same. We The feedback we got was so far, has been that the metadata API is fairly complex and really, the idea of that change is to it as simple as possible and the symbol, the splitting things out by the symbol and assigning metadata to a symbol doesn't really seem to it. Kind of just is somewhere in the middle arbitrarily without really a good reason for it, Like, either performance or, you know JWK: There was a performance issue in the new PR, if you want to get your own metadata, you need to iterate the whole list to find out which one is your metadata. If you use symbol-keyed, you don't have that concern. You just make property access. -CHG: The issue is we don't have enough context really understand where the trade-off between performance and simplicity makes the most sense at the moment. We went all the way performance and the feedback so far has been that that might be too complicated. If if that is the case and I do want to hear what The v8 team has to say about that because a not sure that they would prefer the simpler proposal. Maybe they would. But I think it would be really helpful to get somebody to get some guidance there, where it makes sense to make that trade off. +KHG: The issue is we don't have enough context really understand where the trade-off between performance and simplicity makes the most sense at the moment. We went all the way performance and the feedback so far has been that that might be too complicated. If if that is the case and I do want to hear what The v8 team has to say about that because a not sure that they would prefer the simpler proposal. Maybe they would. But I think it would be really helpful to get somebody to get some guidance there, where it makes sense to make that trade off. SYG: Right, so it's been touched on. We reviewed this proposal with language folks in V8 and yes, some of the feedback you have already said which is that it's kind of complicated. There are I think the general feeling is not just that it's complex that it's as I understand, it is not the most technical feedback, but it's it feels like not the kind of thing we should be shipping in an engine or in a language, like the code needed to support the metadata use case. Feels Like a JS library, and we're still kind of not clear and not super sold on the motivation that as you saying your reply on the GitHub issue that this is a crucial use case. Like it's still not clear to me. Why that? Like, even it were a crucial use case? What are we losing by making it the domain of decorator libraries to solve is like is it? Oh, aight Nation. The issue of having me. He's interacting -CHG: So when you say making it the domain of decorator, libraries, what do you mean by that? +KHG: So when you say making it the domain of decorator, libraries, what do you mean by that? SYG: I mean, not having any metadata at all. This also touches on yulia's matter, they know metadata API in The Decorator proposal at all. In that it's not like an extra hook. Step right now, right? It's like you like, you call this decorator. And then you have the ability to call this add metadata function to stash that metadata, Somewhere to be reflected into this is object. -CHG: So okay, then that might where they lack of understanding is coming from without this API. It is not possible to do metadata with without some API. It is not possible to add. metadata at all, because of all the other constraints that have been placed on decorators. The way that metadata was accomplished previously was that the class itself was passed into the decorator, but that was given as an explicit condition of we cannot do that because that allows decorators to change the shape the class. So without that there is just no way for us to be able to associate any kind of information from the decorator that can then be read externally at all, especially for things like class Fields. So we need some way to pass that information along in order to support very basic, use cases, dependency injection. Without some metadata, API dependency injection is simply impossible, and dependency injection one of the most common use cases for decorators. It is has millions of weekly downloads collectively across just just one Greater library for dependency injection. Has 500,000 weekly downloads and you know, if we include like angular, if we include other libraries that are doing this, it is, it is very, very common use case. So we just need something. And you know, this was this was the more complicated approach we could go with a much simpler approach sure, but we need some way to side channel that information. I see I want to talk. I +KHG: So okay, then that might where they lack of understanding is coming from without this API. It is not possible to do metadata with without some API. It is not possible to add. metadata at all, because of all the other constraints that have been placed on decorators. The way that metadata was accomplished previously was that the class itself was passed into the decorator, but that was given as an explicit condition of we cannot do that because that allows decorators to change the shape the class. So without that there is just no way for us to be able to associate any kind of information from the decorator that can then be read externally at all, especially for things like class Fields. So we need some way to pass that information along in order to support very basic, use cases, dependency injection. Without some metadata, API dependency injection is simply impossible, and dependency injection one of the most common use cases for decorators. It is has millions of weekly downloads collectively across just just one Greater library for dependency injection. Has 500,000 weekly downloads and you know, if we include like angular, if we include other libraries that are doing this, it is, it is very, very common use case. So we just need something. And you know, this was this was the more complicated approach we could go with a much simpler approach sure, but we need some way to side channel that information. I see I want to talk. I SYG: have two responses to that one. Thank you for the explanation again that without like, you need something to key off of and because we've explicitly kind of gotten the thing to key off of without some kind of support here to implicitly carry along the key without exposing it directly. That's you need something. So, yes, a simpler approach might work here. I haven't had the time to review the proposed simpler approach yet. So can't really respond to that as for the. And I also want to respond to the dependency injection thing. I'm not sure there's Universal agreement that that's a good thing to enable first of all, in the language and to the Angular thing in particular. I'm not sure how strongly I would take that as evidence that we need this in the language, even if we were to were to have standardized decorators. It's my understanding that angular is not going to be adopting this. If that is the main use case for dependency injection, or at least the main part of the argument for why? It's, it's such a crucial use case. I personally wouldn't put too much weight on that. -CHG: But yeah, if mean there are there are many other use cases as well. I just thought it was the most compelling, glad given like I said, there are many Frameworks that have adopted it and it has many millions. Downloads per week if we want to get into like entire Frameworks. The angular is a good example because they don't just dependency injection via metadata. They do everything the event in that it like literally every angular decorator, just uses metadata. It's basically annotation oriented. So it's like reactivity and many other things also use metadata. But yeah, I happy that you go into more detail of the specific like use cases for sure. And and I do think like we could like I said, ship something simpler here or potentially break this out into another proposal. Although if we were do that, I would really, we would need to discuss like how we, I think YSV’s previous points. in the last presentation kind of comes up that these are two very highly related things and they would need especially if we wanted to prevent the ecosystem like from, you know, fragmenting a bit. We would need some way to make sure that those landed relatively close to each other or Advanced relatively close together. +KHG: But yeah, if mean there are there are many other use cases as well. I just thought it was the most compelling, glad given like I said, there are many Frameworks that have adopted it and it has many millions. Downloads per week if we want to get into like entire Frameworks. The angular is a good example because they don't just dependency injection via metadata. They do everything the event in that it like literally every angular decorator, just uses metadata. It's basically annotation oriented. So it's like reactivity and many other things also use metadata. But yeah, I happy that you go into more detail of the specific like use cases for sure. And and I do think like we could like I said, ship something simpler here or potentially break this out into another proposal. Although if we were do that, I would really, we would need to discuss like how we, I think YSV’s previous points. in the last presentation kind of comes up that these are two very highly related things and they would need especially if we wanted to prevent the ecosystem like from, you know, fragmenting a bit. We would need some way to make sure that those landed relatively close to each other or Advanced relatively close together. SYG: Yeah. Before I cede the time to Yulia, I think there is a different. like, I don't want to take it as a given that because a very popular framework does something. We have already met the bar for language inclusion, like that might not have been exactly what you were arguing for, but it sounded kind of like that and for metadata in particular because angular does everything vehement metadata. I'm anything about whether I'm not sure that it is. we should do metadata as part of. -CHG: Yeah, I don't. Yeah. I don't want to over rotate on angular. I mean, there's also there's a lot of Frameworks that use decorators right now, and I think that's really what I mean. There is just decorators is a unique in a unique spot as proposal. It is probably one of the most adopted pre-staged 2 syntactic features - for a variety of reasons, historically. Hopefully, we never have a proposal quite like it again. +KHG: Yeah, I don't. Yeah. I don't want to over rotate on angular. I mean, there's also there's a lot of Frameworks that use decorators right now, and I think that's really what I mean. There is just decorators is a unique in a unique spot as proposal. It is probably one of the most adopted pre-staged 2 syntactic features - for a variety of reasons, historically. Hopefully, we never have a proposal quite like it again. SYG: but you may about fragmentation. Is it the case today? That there is there exists fragmentation already do to, for example, the decorators, the typescript of chipped. -CHG: I would say the fragmentation is very minimal because most libraries that use decorators either, use TypeScript’s implementation, or they use Babel’s implementation, which is quite similar to typescript implementation in capabilities and actual like semantics. This is a so in this current form of the whip, without with the metadata intact in the current form. It is so very different, very different right from from, yeah. +KHG: I would say the fragmentation is very minimal because most libraries that use decorators either, use TypeScript’s implementation, or they use Babel’s implementation, which is quite similar to typescript implementation in capabilities and actual like semantics. This is a so in this current form of the whip, without with the metadata intact in the current form. It is so very different, very different right from from, yeah. SYG: Okay, absolutely. And so so we're buying into fragmentation no matter what, but hopefully what we'll just have like a before standard decorator and after Santa decorated instead of more fragmentation. What's your point, -CHG: right. And and more. So like I guess we're what ideally we would just make a decision on whether something like metadata for instance is going to be included or not And that would allow these libraries to either. you know, adopt the new expect that doesn't support their use cases anymore, but they'll just have to figure out some way around it or, you know, continue on I guess using the previous leadership iterations. where where, I think it could be really - is if we ended up, you know, moving decorators without metadata for instance stage 4 and metadata was still in stage 1, Let's say and ended up waffling around. There for quite some time. We could see a lot of libraries that are in this kind of in between a rock and a hard place, right? Like, they want to adopt the language. They want to be spec compliant. But at the same time like metadata is coming. So do they be spec compliant, but then adopt a stage one feature or do they just hold out and hope that you know, it gets through the process. Like I think it would be ideal if this could be done progressively. And, and I guess the way I would approach this is I would probably as the champion who's primarily working on this. would probably create the separate proposals and try to advance all of them to the same stage as decorators as it is right now. And then, you know, move each one to get to stage three before proposing for stage four and so on. So they would all always be within one stage of each other. I think that would be a pretty reasonable, you know, way to approach that problem and to prevent further fragmentation and confusion in the ecosystem. +KHG: right. And and more. So like I guess we're what ideally we would just make a decision on whether something like metadata for instance is going to be included or not And that would allow these libraries to either. you know, adopt the new expect that doesn't support their use cases anymore, but they'll just have to figure out some way around it or, you know, continue on I guess using the previous leadership iterations. where where, I think it could be really - is if we ended up, you know, moving decorators without metadata for instance stage 4 and metadata was still in stage 1, Let's say and ended up waffling around. There for quite some time. We could see a lot of libraries that are in this kind of in between a rock and a hard place, right? Like, they want to adopt the language. They want to be spec compliant. But at the same time like metadata is coming. So do they be spec compliant, but then adopt a stage one feature or do they just hold out and hope that you know, it gets through the process. Like I think it would be ideal if this could be done progressively. And, and I guess the way I would approach this is I would probably as the champion who's primarily working on this. would probably create the separate proposals and try to advance all of them to the same stage as decorators as it is right now. And then, you know, move each one to get to stage three before proposing for stage four and so on. So they would all always be within one stage of each other. I think that would be a pretty reasonable, you know, way to approach that problem and to prevent further fragmentation and confusion in the ecosystem. SYG: Okay. Thank you. I have said my piece. YSV: Hi. Unfortunately, I'm going to be going in a similar direction to Shu and just to say that from our perspective, this decorators proposal looks great with the exception of metadata. We would like to see that broken out and get a better understanding of what we really want to achieve. And there are several comments that we have that are really only related to metadata and don't affect the rest of the proposal. So it would be a shame to, for example, block this proposal on this, when could simply, you know, split it out into a separate proposal and have that discussion on that separate proposal. In particular, We have concerns about metadata around private stuff and that's a discussion that we would like to have more in-depth, but I Do think that if we split this in this has a really strong chance of moving forward, so that would be my recommendation. -CHG: All right. just do you think Yulia the methodology I proposed where we would split it in then focus on getting metadata up to Stage 2, or before advancing, the rest of the proposal to stage three. Do you think that would a reasonable way to approach it? +KHG: All right. just do you think Yulia the methodology I proposed where we would split it in then focus on getting metadata up to Stage 2, or before advancing, the rest of the proposal to stage three. Do you think that would a reasonable way to approach it? YSV: So you're saying like block and decorators from moving to stage three right now, and wait until metadata for it, right? Yes. Yeah, that would have the same impact as us blocking right now. Whereas, alternatively, this moves forward, then we can see implementation happen in stage, 3 and metadata can catch up, or we can see where metadata ends up. and then we can block decorators from moving to stage 4, at the stage 3. But there will be something done in engines and will have certain feedback from that. -CHG: Okay, I guess this is. I'm new dish to the process for like advancement would we be able to it and it's like would we have to wait another meeting here? If we were to split out part of it before advancing the rest of the proposal to stage 3, +KHG: Okay, I guess this is. I'm new dish to the process for like advancement would we be able to it and it's like would we have to wait another meeting here? If we were to split out part of it before advancing the rest of the proposal to stage 3, YSV: We have a concept called conditional advancement which based on feedback in the committee. If everything else is fine, that still needs to be established because we haven't gotten to the point where you ask for consensus. Conditional advancement is modulo a certain change in The Proposal it gains that advancement once that change has been made. -CHG: Okay, that’s good to know. Can I also make a quick ask for both Mozilla and V8 then to have some more active engagement in the metadata proposal. We especially, you know, previously we were the decorators proposal. It's all over the place. We were exploring many. Different directions. I could understand not wanting to invest heavily at that point, but it would be nice if In the coming months, we had, you know, some buddy from both teams, join us to be able to help us understand their concerns. And also, to be able to kind of just sync and kind of figure out these problems quickly that it's been a, the feedback loop right now is very long. We would prefer to be able to do make it a bit shorter. +KHG: Okay, that’s good to know. Can I also make a quick ask for both Mozilla and V8 then to have some more active engagement in the metadata proposal. We especially, you know, previously we were the decorators proposal. It's all over the place. We were exploring many. Different directions. I could understand not wanting to invest heavily at that point, but it would be nice if In the coming months, we had, you know, some buddy from both teams, join us to be able to help us understand their concerns. And also, to be able to kind of just sync and kind of figure out these problems quickly that it's been a, the feedback loop right now is very long. We would prefer to be able to do make it a bit shorter. YSV: before I answer you, Mark disagrees with me. @@ -782,13 +782,13 @@ SYG: Now that MM has said - I mostly agree. I was assuming, YSV did not explicit YSV: Yeah, so this is definitely for the champion to decide like if the champion chooses not to advance. I do want to bring up one example from the past, which was the finalization registry and weak references where we split out, `cleanupSome` and that move directly into stage two as sort of a in that case. It was it was a different goal, but we directly split that out and advanced finalization groups so that we can see finalization groups and groups and how they function in. In the wild before making the decision about whether or not cleanupSome should be attached. So that was a different situation And that was another way to do it, where we fully Advanced something, but there is space for ‘cleanupSome’ to be a, to be integrated later. It may be different situation here. I just want to let you know what your options are. I do think it would be wise to advance this soon because this is a large proposal and it is going to take some time to staff it and for the different browsers to go ahead and implement it. and that may also help inform us about how metadata might work. In particular, like, our concerns are at how this is going to work around private. What if we eventually reify private values, what does that look like for a metadata? So, how do how to decorators get involved with these other fields? Anyway, this is going to be a really large change on classes. So that's where my concerns are coming from as an implementer, but this is your decision. -CHG: Yeah, absolutely. That is good. Good feedback. I guess one another question. I have there that is if we were to split out the metadata could that proposal be advanced or just start in a different stage then stage zero and if so, what would be necessary in order to do that, I guess. +KHG: Yeah, absolutely. That is good. Good feedback. I guess one another question. I have there that is if we were to split out the metadata could that proposal be advanced or just start in a different stage then stage zero and if so, what would be necessary in order to do that, I guess. SYG: I think what YSV was concretely proposing was splitting directly to Stage 2, given we have precedent for that, given that accept this proposal, which is in, its entirety in stage 2. So you split out that part of this proposal, and it would remain stage 2. Okay, that basically solves my concerns in terms of like I said, just keeping them relatively close to one another stage 2 is still a signal to the community that this is a relatively likely feature. Again, given discussion given us all, you know, hashing it out and everybody making sure that they're comfortable with it. That it's definitely being seriously explored not just going to be left on the cutting room floor so to speak. So I think that that would be acceptable from my perspective. YSV: To answer the question that you raised earlier. I can you get more involvement from the browsers? I can't volunteer too much but two of our Engineers are looking at this proposal and are familiar with it. That's where these comments are from. One thing that we are struggling with is a concrete motivation for metadata. Now, it is fine to have this at stage 2 and I understand that there is motivation, for example, dependency injection. but there we will have a couple of questions on that. we can do is probably do an incubator call, and make sure that the browser implementers are present for that. -CHG: Yeah, that would be, that would be great. +KHG: Yeah, that would be, that would be great. SYG: Incubator call sounds good to me. @@ -796,39 +796,39 @@ YSV: When we plan that, I'll make sure that my colleagues are also available to JHX: I just realized that we have already had a Babel implementation since February. Well as well the the README is not updated. Yeah, my real concern is that I feel. It might not have enough feedback from developers. I really like the current proposal but I feel it would be better we could allow the developers do more testing in their production toolcchains, like babel, and I think this is a very important and actually, as the standardization plan in the ring Yeah, it is sad. It will propose was staged 2 know sooner than six months after prototyping. So I like this proposal. I just feel make maybe we need some time for developers to do more testing. -CHG: Thank you. Totally. The readme - sorry. I kind of inherited this proposal. That section the readme has been updated. I think for quite some time so that I think it's just a little bit out of date. yeah. In terms of what we said we would commit to in terms of getting actual feedback. I think this kind of runs into the problem I talked about previously, about decorators being a unique proposal in a unique space. Basically every framework and author that I have talked to has absolutely no intention of testing this out with their communities, until it moves to stage 3 and supports all the functionality that they need in order to move to stage 3. Yeah, so we are kind of, you know, a chicken and egg problem. Like we can't really get feedback from developers who are already like we can't get it from the frameworks and like we have gotten it from Individual developers. We have gotten it from people who tested out the babel transforms themselves. Possibly new Frameworks that are willing to try cutting edge, but I just think this proposal has bitten too many people too many times for them to really invest significantly before it moves to stage 3. So I would love to get more feedback myself, I agree, but I'm not sure that we will be able to. +KHG: Thank you. Totally. The readme - sorry. I kind of inherited this proposal. That section the readme has been updated. I think for quite some time so that I think it's just a little bit out of date. yeah. In terms of what we said we would commit to in terms of getting actual feedback. I think this kind of runs into the problem I talked about previously, about decorators being a unique proposal in a unique space. Basically every framework and author that I have talked to has absolutely no intention of testing this out with their communities, until it moves to stage 3 and supports all the functionality that they need in order to move to stage 3. Yeah, so we are kind of, you know, a chicken and egg problem. Like we can't really get feedback from developers who are already like we can't get it from the frameworks and like we have gotten it from Individual developers. We have gotten it from people who tested out the babel transforms themselves. Possibly new Frameworks that are willing to try cutting edge, but I just think this proposal has bitten too many people too many times for them to really invest significantly before it moves to stage 3. So I would love to get more feedback myself, I agree, but I'm not sure that we will be able to. JHX: yeah. Yes I know. We all are they didn't many if on the collect more input, but recently I discuss the current has current proposal with some developers and found that they still don't know it's happening updating Updating and haven't tried new version and tested. Actually, did I think decorators are very important and many libraries use it, right? -CHG: Yes, like we have, we had many of those libraries that use them on regular calls. We've talked. They have had direct input into this proposal and we have you know, asked if people would use it. I have asked many people, if they would use it and they said that they're not going to like actually use it other than, like, testing it out and small test cases until it is more stable. It's like the same reason typescript is not going to implement it until it is stage3. The reply by Leo who also pleased agrees with that. +KHG: Yes, like we have, we had many of those libraries that use them on regular calls. We've talked. They have had direct input into this proposal and we have you know, asked if people would use it. I have asked many people, if they would use it and they said that they're not going to like actually use it other than, like, testing it out and small test cases until it is more stable. It's like the same reason typescript is not going to implement it until it is stage3. The reply by Leo who also pleased agrees with that. -LEO: Yeah, just want to support Chris here because I think I know the Creator's has been like for so many years. Tariq Ali has been the longest one in stage 2. I know it's been like in different formats, but I'll do like it collected feedback throughout history. So, this is like their resolution through so many feedback from blog posts, from community feedback, from developers, from frameworks. And even this proposal this format is not super new and it's been like it was presented to see TC39 before coming to this. Plenary like in the previous plenary session. Like this is the shape in this is getting too and we have the intention to move these to stage 3, so I think everyone had like a reasonable time to do their homework. How looking at this? We have the CHG held decorators weekly meetings. Even like when we have, like barely, no one going to these meetings no one. But Chris was available like as an office hours for people to come out and come in and like, say give feedback, we had feedback from Frameworks. I think there is a different bar with that. We might be setting here that like, I'm not sure what the parapet. For the Creator's, there is different from others. This has been like a even if we have changes in everything. We've pragmatic and that's good. I think we have an excellent job here and asking for more feedback. Like by the time this proposal is taken by all the burden. I think we need to step back. I think asking for more feedback. I don't think it's time for it. We can do that in like a different stage or I don't think this should be a blocker by itself. +LEO: Yeah, just want to support Chris here because I think I know the Creator's has been like for so many years. Tariq Ali has been the longest one in stage 2. I know it's been like in different formats, but I'll do like it collected feedback throughout history. So, this is like their resolution through so many feedback from blog posts, from community feedback, from developers, from frameworks. And even this proposal this format is not super new and it's been like it was presented to see TC39 before coming to this. Plenary like in the previous plenary session. Like this is the shape in this is getting too and we have the intention to move these to stage 3, so I think everyone had like a reasonable time to do their homework. How looking at this? We have the KHG held decorators weekly meetings. Even like when we have, like barely, no one going to these meetings no one. But Chris was available like as an office hours for people to come out and come in and like, say give feedback, we had feedback from Frameworks. I think there is a different bar with that. We might be setting here that like, I'm not sure what the parapet. For the Creator's, there is different from others. This has been like a even if we have changes in everything. We've pragmatic and that's good. I think we have an excellent job here and asking for more feedback. Like by the time this proposal is taken by all the burden. I think we need to step back. I think asking for more feedback. I don't think it's time for it. We can do that in like a different stage or I don't think this should be a blocker by itself. -USA: Okay. Thank you. LEO, then I suppose CHG. Would you like to ask for advancement? +USA: Okay. Thank you. LEO, then I suppose KHG. Would you like to ask for advancement? -CHG: Yeah, I think I would like to ask for a conditional advancement with splitting metadata out into a separate stage 2 proposal. +KHG: Yeah, I think I would like to ask for a conditional advancement with splitting metadata out into a separate stage 2 proposal. USA: Okay, so we have decorators sans the metadata API for stage 3 and then a metadata split, out proposal, for stage 2. Does anybody have any objections? SYG: I have a clarifying. Question first. I heard that was a PR. I haven't had a chance to look at it yet. Does that PR constitute what you mean by splitting It out? -CHG: No, that PR just proposes a simpler metadata format that would maybe address some of the complexity concerns. +KHG: No, that PR just proposes a simpler metadata format that would maybe address some of the complexity concerns. SYG: Okay. So the contingent advancement here is I have a good idea of what I think it means to split it out. But of course, without the actual thing, so I agree with the so I support the contingent advancement. We should get an actual PR up that we can review to see what exactly the splitting Out means I guess. Yeah, it is. -CHG: I can summarize it for you real quick. But I will also do that. It be to get rid of these two functions right here, getMetadata and setMetadata, and it would get rid of `Symbol.metadata` and anything related to `Symbol.metadata`. So, like go down to the metadata section here. [pointing to sections in explainer] +KHG: I can summarize it for you real quick. But I will also do that. It be to get rid of these two functions right here, getMetadata and setMetadata, and it would get rid of `Symbol.metadata` and anything related to `Symbol.metadata`. So, like go down to the metadata section here. [pointing to sections in explainer] USA: By the way, there's also JHD volunteering to help you out with that. -CHG: Oh, thank you. That's good to know. But yeah, so this entire section would just be removed spec wise, I that actually is a good question. Should I update the spec to have that be a separate proposal. I can do that if necessary. +KHG: Oh, thank you. That's good to know. But yeah, so this entire section would just be removed spec wise, I that actually is a good question. Should I update the spec to have that be a separate proposal. I can do that if necessary. SYG: Yeah, I was careful to not set a specific deadline. I have a good idea what that means, what you have explained makes good sense to me. And from what I understand of the current spec draft, removal of the metadata stuff that seems it can be done in a fairly clean fashion. It's not too intertwined, with all parts of the spec. Basically. I would say - so, again, after your explanation, I remain supportive and I would like to see it within on the order of like, weeks or something. Don't have to do it by the end of plenary. -CHG: I think I could do it by the end of this week, if not the end of next week for sure. I can commit to that. +KHG: I think I could do it by the end of this week, if not the end of next week for sure. I can commit to that. YSV: I just wanted to say, I also support this, I understand what this will mean. And, you know, you can just duplicate this proposal directory and create the metadata and just make it a diff off of decorators in order to dip off of the main spec. So you can just have the changes from that, you're going to remove, that would be totally acceptable. acceptable. -CHG: All right. +KHG: All right. USA: Great, then. I don't see anything on the Queue. So I think you have consensus. All right. Thank you, everybody. Congratulations. Congratulations. diff --git a/meetings/2022-03/mar-30.md b/meetings/2022-03/mar-30.md index 0fc10838..cec6c931 100644 --- a/meetings/2022-03/mar-30.md +++ b/meetings/2022-03/mar-30.md @@ -404,54 +404,54 @@ I don't know, that might be a new proposal. And when we are ready, I will bring ## Minor decorators followups -Presenter: Chris Garrett (CHG) +Presenter: Kristen Hewell Garrett (KHG) - [proposal](https://github.com/tc39/proposal-decorators) - [slides](https://slides.com/pzuraq/decorators-for-stage-3-2022-03) -CHG: So there's just a few issues that have been brought that people are concerned about. So the first one here is the naming of "isPrivate" and "isStatic" on the context object for decorators. These are just two booleans that allow people to understand whether or not the value being decorated, is a private value or is a static value or both. So, as DD notes here, there's precedent for using "is" for functions, and not using “is” prefixed for values. I don't have a strong opinion here. And as far as I understand, just based on all my context. There was not a particular reason to do this. Other than the fact that both static and private are keywords, but that wasn't a conscious design decision when we made this API decision. I think I just didn't realize that there was a naming precedent here. So I don't particularly have a strong opinion here. Does the committee, does anybody on the committee feel it should be one way or the other? +KHG: So there's just a few issues that have been brought that people are concerned about. So the first one here is the naming of "isPrivate" and "isStatic" on the context object for decorators. These are just two booleans that allow people to understand whether or not the value being decorated, is a private value or is a static value or both. So, as DD notes here, there's precedent for using "is" for functions, and not using “is” prefixed for values. I don't have a strong opinion here. And as far as I understand, just based on all my context. There was not a particular reason to do this. Other than the fact that both static and private are keywords, but that wasn't a conscious design decision when we made this API decision. I think I just didn't realize that there was a naming precedent here. So I don't particularly have a strong opinion here. Does the committee, does anybody on the committee feel it should be one way or the other? JSC: With t my developer hat on, I would strongly expect all boolean flags to have, no No, "is" prefix. would have been really surprised at properties named with is do not refer to predicate methods when using them from the options argument. I would prefer not to have Structuring like, have developers either. Not used. you know, `options.private`, or just rename the variables and destructuring like a `private: privateFlag`. The destructuring thing I think is way less important than matching developer expectations with regards to predicate naming. -CHG: Yeah, yeah. And for what it's worth, we have also always said that, you know, decorators usage patterns. Is they're authored by very few people and generally you only have a few of them overall and then they're used in many places. That's the whole point of meta programming in general, right? Is to, to be able to reduce amount of code. Anyways, so the point is the authoring experience can be a little bit less ideal, I think because it's just not as common to have to destructure these. And if you do, there are options for renaming them. +KHG: Yeah, yeah. And for what it's worth, we have also always said that, you know, decorators usage patterns. Is they're authored by very few people and generally you only have a few of them overall and then they're used in many places. That's the whole point of meta programming in general, right? Is to, to be able to reduce amount of code. Anyways, so the point is the authoring experience can be a little bit less ideal, I think because it's just not as common to have to destructure these. And if you do, there are options for renaming them. JSC: Just real quick. Are you also planning to talk about the parentheses after parenthesized expressions? -CHG: Yes, I have these open. I was just wanting to get through each topic before we moved on to the next ones. +KHG: Yes, I have these open. I was just wanting to get through each topic before we moved on to the next ones. KG: I did want to call out that this isn't just that there's a little bit of precedent; that there's an actual w3c TAG style guideline for the web platform that says don't use ‘is’ as a prefix for booleans. So I strongly support dropping the "is" prefix. -CHG: Okay. So yeah, is there any opposition to dropping the “is” prefix? +KHG: Okay. So yeah, is there any opposition to dropping the “is” prefix? [silence] -CHG: Sounds like no. +KHG: Sounds like no. RPR: Agreed. -CHG: So I'll take that as consensus then so I'll make that change the next issue. +KHG: So I'll take that as consensus then so I'll make that change the next issue. -CHG: So the next issue I came up with was kind of a quirk of the previous Babel implementation. I couldn't actually find a fully coherent spec or what the previous iterations agreed upon. But I knew there were when I adopted this proposal. I knew that there were lots of discussions around the syntax that was allowed in decorator expressions. And I also knew that because of a lot of considerations, we, the committee had decided upon having a very restricted set generally with an escape hatch so that the restricted set is you can, is described here. You can chain variables, you can have property access. You can't have basically anything else? No expressions you know with method calls in the chains, you can end that that chain of property accesses with a single function call method call, or you can just put whatever expression you want in parens and that's allowed. I wasn't there for the original discussion. So I'm not exactly sure what the constraints were for this decision. But one thing that the Babel parser currently does allow is calling the results of an expression that is in parentheses and like this example here (`@(foo)() class {}`). And when I was transcribing this back and updating it, I updated it to match Babel because that It was, again, the thing that I could find that was the most concrete from that time period. yeah, this does seem like a little bit - not exactly in line with what was originally described to me and it would be simpler, I think, to not allow it. So just wanted to see if anybody would. I see there's clarifying question So `a(B)` is not allowed `a.b` is allowed to do a Open Bracket, be you. I'd have to do like a The inside parentheses that is allowed. +KHG: So the next issue I came up with was kind of a quirk of the previous Babel implementation. I couldn't actually find a fully coherent spec or what the previous iterations agreed upon. But I knew there were when I adopted this proposal. I knew that there were lots of discussions around the syntax that was allowed in decorator expressions. And I also knew that because of a lot of considerations, we, the committee had decided upon having a very restricted set generally with an escape hatch so that the restricted set is you can, is described here. You can chain variables, you can have property access. You can't have basically anything else? No expressions you know with method calls in the chains, you can end that that chain of property accesses with a single function call method call, or you can just put whatever expression you want in parens and that's allowed. I wasn't there for the original discussion. So I'm not exactly sure what the constraints were for this decision. But one thing that the Babel parser currently does allow is calling the results of an expression that is in parentheses and like this example here (`@(foo)() class {}`). And when I was transcribing this back and updating it, I updated it to match Babel because that It was, again, the thing that I could find that was the most concrete from that time period. yeah, this does seem like a little bit - not exactly in line with what was originally described to me and it would be simpler, I think, to not allow it. So just wanted to see if anybody would. I see there's clarifying question So `a(B)` is not allowed `a.b` is allowed to do a Open Bracket, be you. I'd have to do like a The inside parentheses that is allowed. JHX: If we ban this, how would you write that? -CHG: Yeah, so the way that you would write this is you would do `@((expr)())` because you can put any arbitrary expression inside parens. There are no restrictions inside parens. I have a good example here. To kind of document what is allowed and what is not allowed. And what we're not sure about yet. +KHG: Yeah, so the way that you would write this is you would do `@((expr)())` because you can put any arbitrary expression inside parens. There are no restrictions inside parens. I have a good example here. To kind of document what is allowed and what is not allowed. And what we're not sure about yet. JSC: I strongly support banning trailing parentheses after the arbitrary expression syntax. If developers want to call a function and use that as a decorator, they can just put that inside the original parentheses. Allowing trailing parentheses after the arbitrary expression parenthesized syntax would make parsing the topic reference from the pipe operator. Much more complicated if it's ‘@’ sign, like we decided yesterday, so I strongly The explained already use Use already as the topic says, that it says planning. This, it's a good mental model. I strongly support changing the spec to reflect the explainer. WH: I just want to point out that this will be incompatible with the pipe operator anyway, even if you are going to restrict it this way, because the last allowed form is ambiguous with decorators. -RPR: Okay. Is there anything more you need on this CHG? +RPR: Okay. Is there anything more you need on this KHG? -CHG: No, if nobody objects I'll take that as consensus to not allow this last form this and I'll update the spec to require this to be parenthesized. +KHG: No, if nobody objects I'll take that as consensus to not allow this last form this and I'll update the spec to require this to be parenthesized. JSC: Sorry, just to clarify. Are you banning the last five expressions in that block? -CHG: It would be banning this expression, and these are already banned. +KHG: It would be banning this expression, and these are already banned. JSC: Yeah, what about the? What about the very last one? -CHG: So, the last one, where your that's the next topic to talk about? Okay. Last one to talk about today, - +KHG: So, the last one, where your that's the next topic to talk about? Okay. Last one to talk about today, - LCA: I've one more question about the this previous one. So WH said that the fourth item of the first allowed block would also interfere with the at as a topic reference for the pipe. If that is the case, and we want the pipe operator to use the apps, we would also need to ban this one, right? @@ -461,21 +461,21 @@ WH: We're treading on very thin ice here. In that case I don't understand the ar JSC: To clarify that it would not make it, it would not make it impossible. It would make it more expensive because we will then have to ahead for any parentheses after the first parenthesized expression, following the at sign rather than only having to check right after only the parenthesized expression following the at sign. Does that make sense? Otherwise, we might have to bring in some cover grammars or something like that. Whereas right now, we don't need any cover grammars or whatever to distinguish between a decorator versus a function call on the topic. -CHG: I guess one other option would also be to disallow this for pipe in general, and require you to parentheses the at, if you want to, it involved with the pipe Champion, group probably would be strongly against that. I know TAB is against special casing that requires parenthization of the topic reference. Really. This isn't, it's not like this allowing. This makes it impossible to distinguish. It just makes it more expensive. +KHG: I guess one other option would also be to disallow this for pipe in general, and require you to parentheses the at, if you want to, it involved with the pipe Champion, group probably would be strongly against that. I know TAB is against special casing that requires parenthization of the topic reference. Really. This isn't, it's not like this allowing. This makes it impossible to distinguish. It just makes it more expensive. WH: Okay, I'm getting very uncomfortable with the overload of `@` between these two proposals. -CHG: All right, that's fair, but I don't think it matters for this proposal or this change. So I'll take it as consensus like I said before to continue with that path to ban this form. +KHG: All right, that's fair, but I don't think it matters for this proposal or this change. So I'll take it as consensus like I said before to continue with that path to ban this form. WH: Yes, that's fine. -CHG: Okay. So the last one is, should we allow private fields in decorators? This is like a very not common use case. I can't think of a single time when anybody would really want to do this. But as JHD pointed out and few other people just seems odd to not allow it given we're allowing we're allowing any static, not dynamic expression like just public property name, so might well as allow private names. Is there any opposition to including this? [silence] +KHG: Okay. So the last one is, should we allow private fields in decorators? This is like a very not common use case. I can't think of a single time when anybody would really want to do this. But as JHD pointed out and few other people just seems odd to not allow it given we're allowing we're allowing any static, not dynamic expression like just public property name, so might well as allow private names. Is there any opposition to including this? [silence] RPR: okay, so here's no response. Then we are including private names. MM: I just wanted to interject a question. Is there anything non-obvious about the semantics of it? Is there anything about the semantics including private here? That we should be aware of? -CHG Nope, they would generally work just like public Fields, it would access the value and then attempt to apply it as a decorator function. Just the same as a public value. It just would be accessing it on like if it was a static private field, it would be accessing it on the class, all the same restrictions around private Fields, apply here. You would still only be able to use the private field within the class where the private field was defined etcetera. okay, +KHG: Nope, they would generally work just like public Fields, it would access the value and then attempt to apply it as a decorator function. Just the same as a public value. It just would be accessing it on like if it was a static private field, it would be accessing it on the class, all the same restrictions around private Fields, apply here. You would still only be able to use the private field within the class where the private field was defined etcetera. okay, KG: and in particular, you can already put a private field there, just by wrapping the whole method chain in parentheses. This just allows you to omit the parentheses. @@ -483,33 +483,33 @@ MM: Okay, I'm satisfied. Thank you. Perfect. WH: There's still, I believe, a conflict between using `@` for decorators and for pipeline operators for the cases of expressions in which we have infix non-reserved keywords. -CHG: so you're talking about pipelines versus decorators. Okay. So, like an example that I guess would be like just this like `@foo`, there are some places in the where I +KHG: so you're talking about pipelines versus decorators. Okay. So, like an example that I guess would be like just this like `@foo`, there are some places in the where I WH: I’d need to look more at that, but there are some places in expressions where we have or will have an expression followed by a word. And if the expression is `@` then that starts to look like a decorator. -CHG: Fair enough. I think that's something to consider for the pipeline proposal or do you think that affects decorators? +KHG: Fair enough. I think that's something to consider for the pipeline proposal or do you think that affects decorators? WH: I think decorators should get the `@` and the pipeline operators should use some other sigil. -CHG: Well, I feel like that's not related to the topic at the moment. So I'm going to if allight. Could we schedule a discussion for that some other time? +KHG: Well, I feel like that's not related to the topic at the moment. So I'm going to if allight. Could we schedule a discussion for that some other time? WH: Sure. -CHG: The last thing I wanted to bring up here, was this point, which of people brought up of whether or not whitespace should be allowed between the at sign and the decorator itself. Currently we do allow white space. So any amount of white space could exist, there have been arguments for and against and I don't really have a strong opinion here. +KHG: The last thing I wanted to bring up here, was this point, which of people brought up of whether or not whitespace should be allowed between the at sign and the decorator itself. Currently we do allow white space. So any amount of white space could exist, there have been arguments for and against and I don't really have a strong opinion here. WH: We allow white space between any two tokens, and `@` is a token. -CHG: My instinct would be to keep it as is, is there anybody who would like to change it? +KHG: My instinct would be to keep it as is, is there anybody who would like to change it? SYG: Seems like extra work in the spec and in parsers and scanners to do the work of disallowing. So without a super compelling evidence to the reason to disallow. I would err on the side of allowing. KG: +1 [allow whitespace] -CHG: All right, then I'm going to continue allowing whitespace. Doesn't seem like anybody really opposes that. Cool seems like everything. +KHG: All right, then I'm going to continue allowing whitespace. Doesn't seem like anybody really opposes that. Cool seems like everything. -RPR: All right yeah, that's been an excellent use of time CHG. Thank you. So that concludes all decorators for this meeting. Is that right? +RPR: All right yeah, that's been an excellent use of time KHG. Thank you. So that concludes all decorators for this meeting. Is that right? -CHG: Yep, those are all the open issues at the moment that I can think of. +KHG: Yep, those are all the open issues at the moment that I can think of. ### Conclusion/Resolution diff --git a/meetings/2022-03/mar-31.md b/meetings/2022-03/mar-31.md index 5be88c47..f44c2069 100644 --- a/meetings/2022-03/mar-31.md +++ b/meetings/2022-03/mar-31.md @@ -259,7 +259,7 @@ SYG: No. Yeah, that sounds good. KG: All right. Well, we are basically at time. We have another minute or so if anyone else has something to say, but I think this was a productive discussion at least for me and I am hoping that MF and I can come back with either a concrete proposal for set methods following this discussion, or something to talk about principles that we could write down more broadly if we think we can do that. I'm really excited to have a set that supports union. -RPR: Thank you. you. KG and MF. all right, then, so that concludes the morning session or the morning, according to the schedule, maybe afternoon, or evening, depending on where you are in the world. So for this afternoon, JSC has kindly agreed to give up a little bit of time so that so that CHG can bring back decorators over a few more more small issues. So we're starting off with JSC on the dataflow expiration. And it's decorators and then finally types of comments. So, for now, please do make your way to Hubs 3D world where everyone chats. And thanks to ACE and RGN for taking notes this morning. We will resume in exactly one hour. +RPR: Thank you. you. KG and MF. all right, then, so that concludes the morning session or the morning, according to the schedule, maybe afternoon, or evening, depending on where you are in the world. So for this afternoon, JSC has kindly agreed to give up a little bit of time so that so that KHG can bring back decorators over a few more more small issues. So we're starting off with JSC on the dataflow expiration. And it's decorators and then finally types of comments. So, for now, please do make your way to Hubs 3D world where everyone chats. And thanks to ACE and RGN for taking notes this morning. We will resume in exactly one hour. ## Holistic discussion of TC39 dataflow proposals @@ -337,12 +337,12 @@ JHX: [from queue] Syntax cost is important. This is why we need a much more powe ## Minor decorator tweaks, part 2 -Presenter: Firstname Lastname (CHG) +Presenter: Firstname Lastname (KHG) - [proposal](https://github.com/tc39/proposal-decorators) - [slides](https://slides.com/pzuraq/decorators-for-stage-3-2022-03) -CHG: So a few more issues were brought up for decorators that basically are mostly kind of similar to the Private Fields discussion. So the first one is, should we allow the `this` keyword in the decorator without parentheses, without the Escape? Similarly to private fields There's no real - there's nothing non-obvious about this. It is already possible if you wrap it parens, so this should be ok. Just wanted to confirm with the committee. Are there, is there any reason we would not want to allow this? +KHG: So a few more issues were brought up for decorators that basically are mostly kind of similar to the Private Fields discussion. So the first one is, should we allow the `this` keyword in the decorator without parentheses, without the Escape? Similarly to private fields There's no real - there's nothing non-obvious about this. It is already possible if you wrap it parens, so this should be ok. Just wanted to confirm with the committee. Are there, is there any reason we would not want to allow this? [silence] @@ -356,11 +356,11 @@ KG: Well, I guess I don't know what static and dynamic mean in this context. But JHX: I know that `this` in syntax is okay, but I really feel this is confusing and I really don't like to allow `this`. I think it's in practice no one will write code like that. So it might be disallowed. That will be a bad choice. -CHG: So I agree that in practice nobody will this. I also think that is true of private fields, and I also think that's true of super and new. I think, like JHD said, this is kind of just like the design decision. Here would be that things that look Static. Member Expressions that look static are allowed here and only only things that look Dynamic are It's, and I think that it is, if that's the mental model that people intuit, it will be confusing if they attempt to use this for whatever reason, and they find that it's it's a syntax error. +KHG: So I agree that in practice nobody will this. I also think that is true of private fields, and I also think that's true of super and new. I think, like JHD said, this is kind of just like the design decision. Here would be that things that look Static. Member Expressions that look static are allowed here and only only things that look Dynamic are It's, and I think that it is, if that's the mental model that people intuit, it will be confusing if they attempt to use this for whatever reason, and they find that it's it's a syntax error. JHX: I think we already found many limitations on this place. So why not disallow it? -CHG: I mean, I would argue that if that were the case, then we should disallow private Fields as. Because for similar reasons, private Fields, don't generally make sense here. +KHG: I mean, I would argue that if that were the case, then we should disallow private Fields as. Because for similar reasons, private Fields, don't generally make sense here. KG: Private fields make a lot of sense like you could just be in a context in which a private Fields means a thing. You can be in a nested class, and referring to its private Fields totally reasonable. I agree that `this` is a little more suspicious, but private fields in particular are just like - they're totally reasonable. @@ -368,11 +368,11 @@ TAB: [from queue] Agree with JHD; accidents of grammar that don't have actual pr WH: I just wanted to bring up a procedural issue, which is that we have multiple proposals trying to grab the `@` symbol. It would be confusing if they all got it. So I'm just wondering how we're going to resolve this. -CHG: yeah, that is definitely an issue to discuss. I'm not sure that that is relevant exactly. If you're worried about it being. [audio-issue] I'm just saying like I'm not sure how that's relevant to this particular issue. Unless you're concerned about how `@` is being used in one of those other proposals. +KHG: yeah, that is definitely an issue to discuss. I'm not sure that that is relevant exactly. If you're worried about it being. [audio-issue] I'm just saying like I'm not sure how that's relevant to this particular issue. Unless you're concerned about how `@` is being used in one of those other proposals. WH: I'm asking a procedural question of how we are going to resolve this. I don’t want to discuss the technical issues now, but in case it matters, my preference is that decorators should get `@` and other proposals should not. -CHG: We only have 20 minutes and we have a few of these items to get through. So I'm just not sure that this is the right time to address that because that could be a larger conversation. +KHG: We only have 20 minutes and we have a few of these items to get through. So I'm just not sure that this is the right time to address that because that could be a larger conversation. WH: I'm not asking to address it right now, I'm just asking how are we going to address it. Given the history, I'm going to assume that decorators get the `@` symbol. The other proposals would have to have to pick something else. @@ -382,7 +382,7 @@ WH: No, that's way too confusing. And they will conflict in various contexts. JHX: Disallow it, we could allow it in the future if we really want to. And if we allow it right now, we cannot remove it anymore. -CHG: Like I said, I think this is extremely edge-case-y so it doesn't sound like we have consensus to change it. So I'm happy to move on to the next one. The next one being `super.dec`. I'm guessing for similar reasons people will object to this one. +KHG: Like I said, I think this is extremely edge-case-y so it doesn't sound like we have consensus to change it. So I'm happy to move on to the next one. The next one being `super.dec`. I'm guessing for similar reasons people will object to this one. [audio-issues] @@ -412,11 +412,11 @@ KG: like, if I have a super class and the super class has a static method named JHX: okay, I think if you could add some code example, in the jitsi it would it will help you to understand it. Thank you -CHG: Okay, cool, so I think we can come back to this item, possibly in the next plenary. Then after those examples have been added, does that sound good? +KHG: Okay, cool, so I think we can come back to this item, possibly in the next plenary. Then after those examples have been added, does that sound good? USA: Yeah, sure. -CHG: That's the last one. of these was the `new` keyword `new.target` and `import` keyword `import.meta` So yeah, JHX. How do you feel about these two same position? +KHG: That's the last one. of these was the `new` keyword `new.target` and `import` keyword `import.meta` So yeah, JHX. How do you feel about these two same position? JHX: I hope we wish we could ban all of those @@ -438,15 +438,15 @@ JHX: Okay. Yeah, I think it makes sense. Yeah. Maybe meta property is okay. I'm USA: Yeah. It seems like something that could be discussed offline. -CHG: Yeah, I think we can continue to iterate on this question and bring it back up at the next meeting. I will take it as an item to continue discussion here. So there's one last thing. I know we're at almost that time, but I'd like to get through real quick. I thought I had moved this part of the spec forward in the most recent draft, but I hadn't, it turned out. So I just wanted to see if this is still acceptable. So this was I believe where we landed on the strictness of decorators and the modification I believe is right here. It's essentially that all parts of the class declaration and expression are ‘strict mode’ except for a decorator list at the top level of a class declaration or class expression, so the decorator list applied to the class itself, which is contained in strict mode code there. There's a long Thread about this if anybody wants to read it (issue #204), but this seems to be where we landed. Is anybody objecting to pulling this forward into the current spec? +KHG: Yeah, I think we can continue to iterate on this question and bring it back up at the next meeting. I will take it as an item to continue discussion here. So there's one last thing. I know we're at almost that time, but I'd like to get through real quick. I thought I had moved this part of the spec forward in the most recent draft, but I hadn't, it turned out. So I just wanted to see if this is still acceptable. So this was I believe where we landed on the strictness of decorators and the modification I believe is right here. It's essentially that all parts of the class declaration and expression are ‘strict mode’ except for a decorator list at the top level of a class declaration or class expression, so the decorator list applied to the class itself, which is contained in strict mode code there. There's a long Thread about this if anybody wants to read it (issue #204), but this seems to be where we landed. Is anybody objecting to pulling this forward into the current spec? MM: Yes, I object in the absence. I did not follow the thread. I was not aware of a thread. So let me say in the absence of understanding. What Authority is our objective. We sure I'm getting (?) is correct. Without this addition, the decorator list is interpreted as strict code. And with the addition that you're asking about, the decorator list would be interpreted as sloppy mode, is that correct? -CHG: ah, I mean, I'm not super sure about this strict parts of the spec. I'm not super familiar with them the strictness parts, so I would to kind of look at it. But I think the current spec says all parts of the class declaration and the decorator list would be considered part of the class declaration or class expression. +KHG: ah, I mean, I'm not super sure about this strict parts of the spec. I'm not super familiar with them the strictness parts, so I would to kind of look at it. But I think the current spec says all parts of the class declaration and the decorator list would be considered part of the class declaration or class expression. MM: So I need to understand what the normative difference is. Of Accepting or not accepting this language. I don't know what the current behavior is that this language would change and I don't understand how that language would change. -CHG: So what I understand is that it would allow you to use - like the code for decorators outside of the class body itself, so specifically the decorators applied to the class itself, would not be considered in strict mode. A reason for this was because of a look-ahead concern, so there was concern that we would have to like, you know, parse everything in order to understand, if this module was going to be strict or not. +KHG: So what I understand is that it would allow you to use - like the code for decorators outside of the class body itself, so specifically the decorators applied to the class itself, would not be considered in strict mode. A reason for this was because of a look-ahead concern, so there was concern that we would have to like, you know, parse everything in order to understand, if this module was going to be strict or not. MM: Okay. Thanks. Mentioning that concern makes a huge difference. I understand that sometimes these look ahead concerns can be very painful on people who implement parsers. Were there implementers on that thread that voice a strong desire to avoid the implementation complexity and held by this look-ahead. And and if not, are there any implementers in the room that would like to venture an opinion as to whether the look-ahead in question here would be painful. @@ -456,21 +456,21 @@ KG: No, since decorators are part of classes, but this would amount to a decisio SYG: Exactly. So it comes down to yes, exactly that. So if we want to preclude right now that we don't have non-class decorators, then the rule is just all decorators are strict all the time. -CHG: I think function decorators are the most agreed upon and most desired possible feature. Good place for decorators. I'm not sure I have not dug into them deeply, but I definitely think it would be good to not preclude the ability to add function decorators in the future. +KHG: I think function decorators are the most agreed upon and most desired possible feature. Good place for decorators. I'm not sure I have not dug into them deeply, but I definitely think it would be good to not preclude the ability to add function decorators in the future. SYG: In any case. I'm not comfortable making the decision right now, with the time remaining. Meaning, whether we should preclude. -CHG: Yeah, sounds good. +KHG: Yeah, sounds good. MM: Agreed, I don't want to make a decision right now. -CHG: Okay, so we will take it as an item to continue digging in here and figure out what's going on with the strictness. +KHG: Okay, so we will take it as an item to continue digging in here and figure out what's going on with the strictness. ### Conclusion/Resolution - No conclusions - JHX to think more about `import.meta` etc -- CHG to think more about strictness +- KHG to think more about strictness ## Types as comments (continuation) diff --git a/meetings/2022-06/jun-06.md b/meetings/2022-06/jun-06.md index 3ef6f097..733110b2 100644 --- a/meetings/2022-06/jun-06.md +++ b/meetings/2022-06/jun-06.md @@ -744,29 +744,29 @@ RPR: All right then. Thank you, KG. ## Decorators Normative Change: Flexible Initializers -Presenter: Chris Garrett (CHG) +Presenter: Kristen Hewell Garrett (KHG) - [slides](https://slides.com/pzuraq/decorators-normative-changes-2022-06) -CHG: Okay, it's okay. Sharing my screen. And so yeah, so today we just have a kind of normative update that were considering for the proposal that I wanted to bring to the committee. It was suggested RBN after the proposal, made it into stage three and basically it would change the way that initializers currently work to a little bit more flexible by allowing. users to specify when they're initializer should run from any decorator. So today, when you add an additional initializer, using the app at initializer method on the context of a decorator, that adds the initializer function to one of three possible stages of initialization, if it's an instance field or method then that initializer runs. The beginning of class, instance, initialization. So when a new instance is created, if it is static it runs. Prior to class static class field assignment. So, when the class itself is initialized and if it's a class decorator that it runs after the class has been fully initialized. So all static Fields have been assigned. This code example, kind of shows the different areas where these run essentially. So for instance. Initializers, they run before, the first class field is assigned. This is literally very close to how we transpile it actually in the Babel plugin. For instance or static fields and static initializers. They run prior to the first static bill being signed, and then for class initializes, they run right after the class is defined. so, the proposal would change it so that you could specify the three placements as the first option to add an initializer. You would be required to specify one of the displacements actually. And that would allow it to be placed, you know, in one of those three locations the main two reasons to do this. The first one is that it provides more flexibility overall. There are a number of use cases where you have for instance, and instance method or field that wants to provide do some setup on the class itself wants to initialize the class in some way. An example of this is like props on web components or event listeners on web components as well. So that flexibility to be able to have like an instance and an instance elements be able to add an initialization for the class as a whole would be very useful. But another motivating example motivate action, here would be that this could become a way to add metadata. So previously we broke out the metadata portion of the decorators proposal into a separate proposal and that proposal is currently at stage 2 with this change. We would be able to instance elements and static elements. They would all be able to add their metadata via initializers in the via static initializers, or class initializers. They would do this much like the same way that they currently add metadata by currently meeting like the previous, you know, stage 1 and stage, two proposals added metadata. Meaning, they would just get a reference to the class itself, static initializers and class initilisers get that and they would be able to WeakMap the metadata to the class or just a sign it as a property on the class and expose it that way. So this wouldn't mean that we would still potentially explore the metadata proposal because there would be other benefits to having a shared standard for metadata, but it would also make that proposal not as Necessary for a lot of common use cases. So we would need some of that metadata. And any of the other additional APIs, so that's that's pretty much it. Any questions? +KHG: Okay, it's okay. Sharing my screen. And so yeah, so today we just have a kind of normative update that were considering for the proposal that I wanted to bring to the committee. It was suggested RBN after the proposal, made it into stage three and basically it would change the way that initializers currently work to a little bit more flexible by allowing. users to specify when they're initializer should run from any decorator. So today, when you add an additional initializer, using the app at initializer method on the context of a decorator, that adds the initializer function to one of three possible stages of initialization, if it's an instance field or method then that initializer runs. The beginning of class, instance, initialization. So when a new instance is created, if it is static it runs. Prior to class static class field assignment. So, when the class itself is initialized and if it's a class decorator that it runs after the class has been fully initialized. So all static Fields have been assigned. This code example, kind of shows the different areas where these run essentially. So for instance. Initializers, they run before, the first class field is assigned. This is literally very close to how we transpile it actually in the Babel plugin. For instance or static fields and static initializers. They run prior to the first static bill being signed, and then for class initializes, they run right after the class is defined. so, the proposal would change it so that you could specify the three placements as the first option to add an initializer. You would be required to specify one of the displacements actually. And that would allow it to be placed, you know, in one of those three locations the main two reasons to do this. The first one is that it provides more flexibility overall. There are a number of use cases where you have for instance, and instance method or field that wants to provide do some setup on the class itself wants to initialize the class in some way. An example of this is like props on web components or event listeners on web components as well. So that flexibility to be able to have like an instance and an instance elements be able to add an initialization for the class as a whole would be very useful. But another motivating example motivate action, here would be that this could become a way to add metadata. So previously we broke out the metadata portion of the decorators proposal into a separate proposal and that proposal is currently at stage 2 with this change. We would be able to instance elements and static elements. They would all be able to add their metadata via initializers in the via static initializers, or class initializers. They would do this much like the same way that they currently add metadata by currently meeting like the previous, you know, stage 1 and stage, two proposals added metadata. Meaning, they would just get a reference to the class itself, static initializers and class initilisers get that and they would be able to WeakMap the metadata to the class or just a sign it as a property on the class and expose it that way. So this wouldn't mean that we would still potentially explore the metadata proposal because there would be other benefits to having a shared standard for metadata, but it would also make that proposal not as Necessary for a lot of common use cases. So we would need some of that metadata. And any of the other additional APIs, so that's that's pretty much it. Any questions? MAH: So we are supportive of this change as it really increases the flexibility. However, I think there's still benefits to explore. a solution that empowers metadata and also multiple decorators working together as it's very ergonomic to do with just initializers. and so just to increase, the ergonomics of decorators going to make these of the Creator's. It would be great to continue exploring, In addition, an opaque context were direct that data API. SYG: I'm kind of uneasy about this. But before I say my piece. The title of this was update, but are you proposing this as a post stage 3 change to the proposal? -CHG: Yes. I'm proposing this as a change. Yes. +KHG: Yes. I'm proposing this as a change. Yes. SYG: Okay, so I'm kind of uneasy because part of the redesign ethos was that things that look. Declarative ought to behave declaratively and the idea was that you could syntactically kind of look at the static parts of the decorator and tell the shape changes that would be necessary. And if I understand correctly here, I can no longer tell, for example, that if there are So currently, it's my understanding that. For example, if there are no class decorators than there, no class initialization. Is that correct? -CHG: Yes, that's correct. +KHG: Yes, that's correct. SYG: Okay, so did this increase flexibility means that the presence of any decorators mean that we have we now have to kind of dynamically determine if we need call these three hooking points because any decorator can we can add to these three hooking points? That makes me uneasy. It feels Contra to the original redesign, ethos that we had set out to do, Try to fix from the previous iterations. Maybe this is ok in that it's just like one of three well, understood hooking points, but so far, like the thing that's most compelling to me about this is, does this obviate the need for additional complexity by a simple, meta data and the metadata proposal? If it does not, then I am not in really in favor of this change, but if a little bit more flexibility here, a little bit more complexity here, here, lets us obviate more complexity elsewhere, then. I would be on board. But as it stands right now, I'm somewhat uneasy about this to to be accepted as a stage three change. If it were a follow-up proposal to add the flexibility. if we ship, the current behavior does it preclude. Do you have a path to get to this world? -CHG: Yes. I mean we could either add another method, you know, onto the context object or accept an additional parameter to the add initializer function in the future there that I could imagine ways to get to this world additively for sure but to address the other part of what you were saying. I see it that way as well. Essentially, you know, I think that this would personally like not - it would mean that we wouldn't really need the additional complexity of the metadata proposal. And personally, I've already let others in kind of the decorators meetings know that I would not continue to Champion that proposal just with my time constraints and everything. I feel like this would cover all of the needs that we really have but others have expressed that they would still want to explore it. So and, you know, not going to like, oh, we can't but I yeah, I'm 100% in with what you're saying there. +KHG: Yes. I mean we could either add another method, you know, onto the context object or accept an additional parameter to the add initializer function in the future there that I could imagine ways to get to this world additively for sure but to address the other part of what you were saying. I see it that way as well. Essentially, you know, I think that this would personally like not - it would mean that we wouldn't really need the additional complexity of the metadata proposal. And personally, I've already let others in kind of the decorators meetings know that I would not continue to Champion that proposal just with my time constraints and everything. I feel like this would cover all of the needs that we really have but others have expressed that they would still want to explore it. So and, you know, not going to like, oh, we can't but I yeah, I'm 100% in with what you're saying there. SYG: Then as it stands now, I think am not in favor of accepting this as a post stage 3 change, but I am in favor of a small proposal here to tack on to explore afterwards. All right. I still want more implementation experience under my belt, to be for kind of going against the original redesign, ethos of more statically analyzable. -CHG: Yeah, that's completely reasonable. A big part of the reason to bring it up now, as well was just, you know, the proposal is still fresh and I wanted to make sure that we had considered all the different possible ways to address metadata. Since that is still an ongoing concern and another proposal. So I realized also that it was kind of last minute that's going to be one of the next topics coming up but I just felt that, you know, it would, it would make sense to bring this to the committee as early as possible just to see what the thoughts were. And yeah, get some feedback. +KHG: Yeah, that's completely reasonable. A big part of the reason to bring it up now, as well was just, you know, the proposal is still fresh and I wanted to make sure that we had considered all the different possible ways to address metadata. Since that is still an ongoing concern and another proposal. So I realized also that it was kind of last minute that's going to be one of the next topics coming up but I just felt that, you know, it would, it would make sense to bring this to the committee as early as possible just to see what the thoughts were. And yeah, get some feedback. MAH: So yeah, I just want to say really quick. I think they're complimentary, they're not. There are cases that can that can benefit from both. Yeah, that's all I got. I don't think it's one or the other. There are benefits from having both. @@ -778,11 +778,11 @@ RBN: All right. One thing that I think is kind of interesting with this. Is that JHD: It be reasonable to require this string but like, throw an error if you try to add an instance initializer and you're not an instance thing and so on, so that we leave the design space open? Because if we ship now with that initializer, just taking a function argument, we would then be forced to add a string later and that may or may not be something we want. Like for me, I do think that's a second argument. -CHG: Yeah, I do think that would be possible. I also think adding the string as a second argument also wouldn't be that much worse ergonomically though. I'm open to possibilities here. +KHG: Yeah, I do think that would be possible. I also think adding the string as a second argument also wouldn't be that much worse ergonomically though. I'm open to possibilities here. JHD: So yeah, and then that's a real exercise that we're going to add it as a second argument, then it would probably be wise to add it now as an optional second argument, and if it's not undefined it has to be the correct string. Similarly. So that people don't, you know, start passing things and we have a web compat issue. -CHG: I think that would probably be the best way to approach it because that way we don't incur a permanent issue like DX. It if we don't go this direction. +KHG: I think that would probably be the best way to approach it because that way we don't incur a permanent issue like DX. It if we don't go this direction. SYG: Sorry, I did not understand the second suggestion of the second argument. @@ -790,8 +790,8 @@ JHD: My suggestion SYG was that the current API, `addInitializer()` takes a func SYG: Right. -RPR: We are a good five minutes over and it's the end of the session. CHG. Did you want to just say a few words to wrap up to say? +RPR: We are a good five minutes over and it's the end of the session. KHG. Did you want to just say a few words to wrap up to say? -CHG: Yeah, absolutely. thank you everybody, for the feedback and definitely understand this was a bit late. So sorry about that again. Just wanted to make sure we got that feedback as soon as possible. So, thanks again. +KHG: Yeah, absolutely. thank you everybody, for the feedback and definitely understand this was a bit late. So sorry about that again. Just wanted to make sure we got that feedback as soon as possible. So, thanks again. RPR: Thanks to the note takers! diff --git a/meetings/2023-01/feb-01.md b/meetings/2023-01/feb-01.md index 4ec17ea2..0dd8acb3 100644 --- a/meetings/2023-01/feb-01.md +++ b/meetings/2023-01/feb-01.md @@ -33,7 +33,7 @@ | Eemeli Aro | EAO | Mozilla | | Daniel Minor | DLM | Mozilla | | Jordan Harband | JHD | Invited Expert | -| Chris Garrett | CHG | Invited Expert | +| Kristen Hewell Garrett | KHG | Invited Expert | | Sergey Rubanov | SRV | Invited Expert | | Duncan MacGregor | DMM | ServiceNow | | Duncan MacGregor | DMM | ServiceNow | @@ -638,7 +638,7 @@ RBN: I also want to point out a couple thing. One, as Daniel said, whether or no USA: Right, we have run around two minutes left and next up on the queue we have Chris. -CHG: Hi. So, yeah, I think that another thing to consider about these migrations, decorators are changing -- they’re going to change both the semantics and the syntax. And especial away the semantics, it’s something I have found code bases are typically wanting to do in parts, not via a large code mod. You typically want to try to get it massage your code base into as close as it’s going to be afterward. You know, one file at a time. Sometimes especially with some of the other changes. Before you kind of do anything like that or flip the switch, so to speak. I’ve even talked through situations where people want to run both transforms at the same time, and use both specs at the same time because it is going to be so difficult to migrate just straight. So I do think, like, a solution like a code mod isn’t particularly helpful for this style of migration. And like Ron said, I do think this is like a case where given there is no real other reason, it is significantly easier to migrate, you know, the existing style. So that’s just my experience in what I’ve seen so far in the ecosystem. +KHG: Hi. So, yeah, I think that another thing to consider about these migrations, decorators are changing -- they’re going to change both the semantics and the syntax. And especial away the semantics, it’s something I have found code bases are typically wanting to do in parts, not via a large code mod. You typically want to try to get it massage your code base into as close as it’s going to be afterward. You know, one file at a time. Sometimes especially with some of the other changes. Before you kind of do anything like that or flip the switch, so to speak. I’ve even talked through situations where people want to run both transforms at the same time, and use both specs at the same time because it is going to be so difficult to migrate just straight. So I do think, like, a solution like a code mod isn’t particularly helpful for this style of migration. And like Ron said, I do think this is like a case where given there is no real other reason, it is significantly easier to migrate, you know, the existing style. So that’s just my experience in what I’ve seen so far in the ecosystem. USA: Right. Next up we have a reply from Shu. Could you be really quick, please. diff --git a/meetings/2023-01/feb-02.md b/meetings/2023-01/feb-02.md index 28adc1fb..5c9b62fd 100644 --- a/meetings/2023-01/feb-02.md +++ b/meetings/2023-01/feb-02.md @@ -600,7 +600,7 @@ RBN: That’s correct. IID: And then the second half of my question is like it was a little surprising to me that we only noticed that we needed to be allocating fresh objects and it wasn’t valid for an object to be reused because we asked this question. So to what extent has the sort of object allocation story been scrutinized for reducing unnecessary allocations. I think obviously these are short lived objects in general and the garbage collector will handle it. But if we can avoid having excess GC churn by making a small change, that would be good. I’m not sure whether it is good to freeze the context in access objects and guarantee they’re always the same same. That does require us to hold on to them like as long as the constructor exists, probably. But I know that up until like when we were doing review, we weren’t considering this a lot. I’m wondering has somebody looked at this? Is there anything we can do to – without compromising on any other values – limit the performance overhead of using decorators? -RBN: I’m not sure if CHG who is the champion is able to join the call at the moment. I know they had limited availability until the March plenary. So I imagine CHG would have more context as to the investigations from engines. DE might as well. I know when DE was champion there was a lot of time spent on this. I do know that we had things in the past where we had discussions about how engines can theoretically optimize if you never touched access, then it could be lazily initialized by the engine as long as it is not observably different to user code. In most cases where anyone would actually touch the access object they intend to use it would be a very rare case for somebody to do a dot access look up without intending to use it. +RBN: I’m not sure if KHG who is the champion is able to join the call at the moment. I know they had limited availability until the March plenary. So I imagine KHG would have more context as to the investigations from engines. DE might as well. I know when DE was champion there was a lot of time spent on this. I do know that we had things in the past where we had discussions about how engines can theoretically optimize if you never touched access, then it could be lazily initialized by the engine as long as it is not observably different to user code. In most cases where anyone would actually touch the access object they intend to use it would be a very rare case for somebody to do a dot access look up without intending to use it. DE: I would not assume that that’s possible for engines, because some engines have that they could have a fake or hidden getter and some engines don’t intend to have that path. But concretely if we wanted to make a change so that it doesn’t allocate objects that are kind of proportional to the size of the code or the number of class elements elements, that would be a big change. The assumption has been going into this proposal that it’s okay to pass a couple option bags, allocate a couple options bags per decorator. It’s not option bags per instance. It’s each time the class is being evaluated. I’m sure you noticed this in the review. Making things frozen is pretty – is somewhat fraught in various different ways. Is the concern about when you have a chain decorators? @@ -718,9 +718,9 @@ USA: We have a queue. But before we move on with the queue, this is already over RBN: Thank you. -USA: The next on the queue is CHG. +USA: The next on the queue is KHG. -CHG: I just wanted to weigh in about that type of migration. So I don’t think that this type of migration is necessarily that comment in the ecosystem. When it does happen, it is very tricky to do it all at once. And the style of enabling code bases to migrate incrementally one file or one section at a time has work worked well for us in a few cases particularly in the ember JS community specifically at linked in and where I worked with ember JS, we basically had a decorator pattern and whole class built before decorators were part of the language or part of the process to become part of the language. So when ember decided to adopt decorators legacy decorators, we had to do that type of a migration. And it was just not something that could be done, too many differences and too many small details. Not something that we could do all at once in very large mature code bases. Just based on that experience, I think this strategy is something that I would pursue at a company looking to migrate from Stage 1 and legacy decorators to the final spec. And I think that it’s a valid like way to do it without without, you know, shutting down everything and rewriting your entire app. So I just wanted to weigh in about that. +KHG: I just wanted to weigh in about that type of migration. So I don’t think that this type of migration is necessarily that comment in the ecosystem. When it does happen, it is very tricky to do it all at once. And the style of enabling code bases to migrate incrementally one file or one section at a time has work worked well for us in a few cases particularly in the ember JS community specifically at linked in and where I worked with ember JS, we basically had a decorator pattern and whole class built before decorators were part of the language or part of the process to become part of the language. So when ember decided to adopt decorators legacy decorators, we had to do that type of a migration. And it was just not something that could be done, too many differences and too many small details. Not something that we could do all at once in very large mature code bases. Just based on that experience, I think this strategy is something that I would pursue at a company looking to migrate from Stage 1 and legacy decorators to the final spec. And I think that it’s a valid like way to do it without without, you know, shutting down everything and rewriting your entire app. So I just wanted to weigh in about that. USA: Next we have DRR. @@ -828,7 +828,7 @@ JHD: The other thing it is always uncomfortable when we have to put people on th WH: My views are very similar to JHD’s. -CHG: I don’t mean to interrupt. I had an item on the queue and I wanted to talk about it. It got deleted. I just wanted to respond, just to provide the opposing side. I think I agree with JHD analysis. I actually tweeted earlier this is just really the address in code form. We’re all just seeing it different ways because there’s two different mental models that make perfect sense here. There is the cost of transitioning code around that if you have the mental model of like export X on an expression effectively, that is something that you’ll have to think about. The opposing cost is, you know, if you have multiline statements, if you are reading a lot of code which I think developers tend to spend more time reading code than writing code. The clarity of reading the code and the ability to understand what the code does at a glance is very important because generally people aren’t always reading with like intent to scanning every word, every line and in particular people who have learning disabilities or visual processing issues, it’s going to be even harder for them to see that there’s that export keyword at the top there. So I think there are costs to both sides for sure. I just wanted to voice that that is the cost that is most preeminent in my mind and a mistake I made on code reviews when having to look at decorators after. +KHG: I don’t mean to interrupt. I had an item on the queue and I wanted to talk about it. It got deleted. I just wanted to respond, just to provide the opposing side. I think I agree with JHD analysis. I actually tweeted earlier this is just really the address in code form. We’re all just seeing it different ways because there’s two different mental models that make perfect sense here. There is the cost of transitioning code around that if you have the mental model of like export X on an expression effectively, that is something that you’ll have to think about. The opposing cost is, you know, if you have multiline statements, if you are reading a lot of code which I think developers tend to spend more time reading code than writing code. The clarity of reading the code and the ability to understand what the code does at a glance is very important because generally people aren’t always reading with like intent to scanning every word, every line and in particular people who have learning disabilities or visual processing issues, it’s going to be even harder for them to see that there’s that export keyword at the top there. So I think there are costs to both sides for sure. I just wanted to voice that that is the cost that is most preeminent in my mind and a mistake I made on code reviews when having to look at decorators after. USA: We have a number of comments on either side on the queue. First up you have HAX who says I support option 1 and then there’s WMS who says +1 to JHD’s point and Richard who says that I share JHD’s discomfort with option 1 for essentially similar reasons. At the same time, we’re running out of time. That’s all. @@ -846,7 +846,7 @@ RBN: Yes, please. JHD: My understanding is that nobody wants to try to elide the export keyword from the toString representation. So I feel like we can either pick that decorators are never included, like, decorators on exported things are never included in the toString or we could pick decorators are only included in the toString when they appear after export, although that seems weird if both positions are allowed. And so it feels like either of those two options would satisfy my understanding of MM’s position. Of course, MM can clarify. And I don’t think that that decision should block option 2. I think that’s just something we should figure out in an issue. -RBN: One thing I was going to bring up was that I had a suggestion I had been discussing with other folks with Daniel and with CHG offline which is if we had gone with option 1 and had decided that we didn’t want to include export in the to spring, we could have made the distinction that decorators that come before export would not be included. If you decorated a class that doesn’t have the export declaration they would be included. If you are specifically tailoring the code to use the eval of a toString case that is a niche case as it is and the step of having export declaration for the binding as a separate statement is not a far stretch if you are again trying to custom tailor for the environment. It does feel a bit weird to have a distinction if we allow both but in the same vein allowing both would also make it feasible to have a specific case where you are custom tailoring your code to work with the eval case. That said, I still find evalling a toString to be an unsound and unreliable practice even though it has – it does exist in the ecosystem, I have seen it used well for performance and other things and functions but I also believe that forthcoming proposals or in progress proposals things like module blocks might be potentially a better way to do that as well because it doesn’t require strings and worrying about the CSP, for example, being an issue for making that reliable to use regularly. So I think it might be weird but it also does, like you said, make it so that option 2 is still viable. +RBN: One thing I was going to bring up was that I had a suggestion I had been discussing with other folks with Daniel and with KHG offline which is if we had gone with option 1 and had decided that we didn’t want to include export in the to spring, we could have made the distinction that decorators that come before export would not be included. If you decorated a class that doesn’t have the export declaration they would be included. If you are specifically tailoring the code to use the eval of a toString case that is a niche case as it is and the step of having export declaration for the binding as a separate statement is not a far stretch if you are again trying to custom tailor for the environment. It does feel a bit weird to have a distinction if we allow both but in the same vein allowing both would also make it feasible to have a specific case where you are custom tailoring your code to work with the eval case. That said, I still find evalling a toString to be an unsound and unreliable practice even though it has – it does exist in the ecosystem, I have seen it used well for performance and other things and functions but I also believe that forthcoming proposals or in progress proposals things like module blocks might be potentially a better way to do that as well because it doesn’t require strings and worrying about the CSP, for example, being an issue for making that reliable to use regularly. So I think it might be weird but it also does, like you said, make it so that option 2 is still viable. DRR: Okay. Any responses to that? diff --git a/meetings/2023-03/mar-21.md b/meetings/2023-03/mar-21.md index edab749f..3f08ba27 100644 --- a/meetings/2023-03/mar-21.md +++ b/meetings/2023-03/mar-21.md @@ -844,60 +844,60 @@ The grammar will need to be worked out in a PR, which will need to be presented ## Decorator: Normative update -Presenter: Chris Hewell Garrett (CHG) +Presenter: Kristen Hewell Garrett (KHG) - [proposal](https://github.com/tc39/proposal-decorators) - [issue](https://github.com/tc39/proposal-decorators/issues/499) -CHG: So the first item here is a few normative updates to the spec for decorators. These are all relatively small changes. so I kind of bundled them all together. There's six in total and well we can just go through each one individually and talk about it. +KHG: So the first item here is a few normative updates to the spec for decorators. These are all relatively small changes. so I kind of bundled them all together. There's six in total and well we can just go through each one individually and talk about it. -CHG: ([PR](https://github.com/pzuraq/ecma262/pull/5), [Issue](https://github.com/tc39/proposal-decorators/issues/497)) So the first one is removing the dynamic assignment of the home object for decorated methods. You can see what this actually looks like here. Currently we call perform MakeMethod on the decorated function. This is the second time MakeMethod would be called on this function and that sets the home objects dynamically for that method. So that's a very new thing that's never been done before in the spec and I believe the reason I did that originally was just I didn't understand the full implications of makeMethods. I was just kind of cargo-culted the thing along. So yeah, we've had a few people point out that this can result in very confusing behavior. Rebinding `super` in general, seems really weird. and just seems like a bad idea and doesn't have any really good use cases. So we wanted to just remove this and no longer rebind `super`. Do we have consensus for that change? +KHG: ([PR](https://github.com/pzuraq/ecma262/pull/5), [Issue](https://github.com/tc39/proposal-decorators/issues/497)) So the first one is removing the dynamic assignment of the home object for decorated methods. You can see what this actually looks like here. Currently we call perform MakeMethod on the decorated function. This is the second time MakeMethod would be called on this function and that sets the home objects dynamically for that method. So that's a very new thing that's never been done before in the spec and I believe the reason I did that originally was just I didn't understand the full implications of makeMethods. I was just kind of cargo-culted the thing along. So yeah, we've had a few people point out that this can result in very confusing behavior. Rebinding `super` in general, seems really weird. and just seems like a bad idea and doesn't have any really good use cases. So we wanted to just remove this and no longer rebind `super`. Do we have consensus for that change? RPR: There's no one on the queue. DE: Yes, I support that change, although the committee has in the past thought about making an API for make method this is like it's like has all the cost but they're not be expressiveness. You. that's it for this change. -CHG: Cool. awesome. Okay, So I'm going to assume that that one is okay and we will move forward. +KHG: Cool. awesome. Okay, So I'm going to assume that that one is okay and we will move forward. SYG: +1 yes please we don't know how to implement it otherwise JHD: +1 -CHG: ([PR](https://github.com/pzuraq/ecma262/pull/6), [Issue](https://github.com/tc39/proposal-decorators/issues/487)) The next one is calling decorators with their natural, `this` value, whatever that would be. That would be the receiver. instead of `undefined` currently in the spec we just always called the fecorator function with undefined. undefined. I think that's an oversight because I never really intended for that to be the case. So, for instance, if we call `foo.bar`, this is an invocation of a function. So the receiver `this` value should be `foo` here and if you bound this for `bar`, at some point, it should have the `this` value that it was bound. They basically should work just like a normal function. That is the whole mental module of decorators. So, yeah, not sure why this happened in the first place, but that That would be the change. Yeah. +KHG: ([PR](https://github.com/pzuraq/ecma262/pull/6), [Issue](https://github.com/tc39/proposal-decorators/issues/487)) The next one is calling decorators with their natural, `this` value, whatever that would be. That would be the receiver. instead of `undefined` currently in the spec we just always called the fecorator function with undefined. undefined. I think that's an oversight because I never really intended for that to be the case. So, for instance, if we call `foo.bar`, this is an invocation of a function. So the receiver `this` value should be `foo` here and if you bound this for `bar`, at some point, it should have the `this` value that it was bound. They basically should work just like a normal function. That is the whole mental module of decorators. So, yeah, not sure why this happened in the first place, but that That would be the change. Yeah. DE: +1 good bug fix DLM: +1 I agree with this. -CHG: Any other comments on that one? +KHG: Any other comments on that one? RPR: Nothing. in the room. Nothing on the Queue. So I think, you have consensus on that item. -CHG: Perfect. Okay. ([PR](https://github.com/pzuraq/ecma262/pull/7)) So for three, this is just a new validation that we would do, so add initializers, a function on the context object for adding an initializer function. and currently it can receive any value and it doesn't assert that, it's a function. So we just want to add a statement that that causes it to throw an error if the value is not callable. So, that is basically all that one is the behaviors like really `undefined` if it's basically assumes it's a function after that point. So it definitely should try that or or I don't know what'll happen. Okay any comments on that one? Dan did you want to speak? +KHG: Perfect. Okay. ([PR](https://github.com/pzuraq/ecma262/pull/7)) So for three, this is just a new validation that we would do, so add initializers, a function on the context object for adding an initializer function. and currently it can receive any value and it doesn't assert that, it's a function. So we just want to add a statement that that causes it to throw an error if the value is not callable. So, that is basically all that one is the behaviors like really `undefined` if it's basically assumes it's a function after that point. So it definitely should try that or or I don't know what'll happen. Okay any comments on that one? Dan did you want to speak? DLM: Yeah, looks good to me. RPR: Right. Any corrections or the comments on number three? _silence_. You have consensus on Number three, perfect. -CHG: ([PR](https://github.com/pzuraq/ecma262/pull/8)) So for number four, setting the name of the add initializer function itself currently it just did not have a name said ever set to `undefined` or an empty string. Again, I think this was an oversight. The spec is very large and it was the first time I was writing it so I made a bunch of little mistakes. Yeah. it seems like the thing we should do because that's generally what you do with functions in JavaScript so does everyone agree? +KHG: ([PR](https://github.com/pzuraq/ecma262/pull/8)) So for number four, setting the name of the add initializer function itself currently it just did not have a name said ever set to `undefined` or an empty string. Again, I think this was an oversight. The spec is very large and it was the first time I was writing it so I made a bunch of little mistakes. Yeah. it seems like the thing we should do because that's generally what you do with functions in JavaScript so does everyone agree? DE: +1 NRO: +1 -CHG: OK, I’ll take that as consensus. So now we get to this one. so I actually originally had a PR up to make this change in the opposite direction, which was to allow function names to be dynamically reassigned for decorated methods. The logic was that if you have a method on a class and you decorate it, it's always going to be like that. that new decorated function name. So you could like, decorate three, things and they would all be like, X, right? If the function return from The Decorator was x. Originally my logic was we're going to want as a user, I'm going to want to be able to see what the original function names were. But then a bunch of folks pointed out that this would actually really mess up stack traces because then you would have l the decorated function calling the original function and they would both have the same name. would be kind of confusing. There's we would have to kind of rethink how second function name works and everything for that as well. And what somebody mentioned was we could actually have this be something that you know is non-normative or I guess. I don't know if error text is not normative, but this could actually be something that stack traces insert, in order to make it easier for people to read what method is actually being called. Any clarifications needed for that one? +KHG: OK, I’ll take that as consensus. So now we get to this one. so I actually originally had a PR up to make this change in the opposite direction, which was to allow function names to be dynamically reassigned for decorated methods. The logic was that if you have a method on a class and you decorate it, it's always going to be like that. that new decorated function name. So you could like, decorate three, things and they would all be like, X, right? If the function return from The Decorator was x. Originally my logic was we're going to want as a user, I'm going to want to be able to see what the original function names were. But then a bunch of folks pointed out that this would actually really mess up stack traces because then you would have l the decorated function calling the original function and they would both have the same name. would be kind of confusing. There's we would have to kind of rethink how second function name works and everything for that as well. And what somebody mentioned was we could actually have this be something that you know is non-normative or I guess. I don't know if error text is not normative, but this could actually be something that stack traces insert, in order to make it easier for people to read what method is actually being called. Any clarifications needed for that one? ACE: Sorry, I’m not on the queue, but didn't follow what's being proposed exactly. -CHG: Okay. So let me see if I can make an example real quick, so, actually, I think. RBN has some example here. so currently a b and c. When they get decorated we return this anonymous function right here. So, a b and c. These names would be the name of whatever this anonymous function is. And what that leads to is. You have like really odd stack traces because you, have two a's or to b's. Because you know this function is going to call the original function. and yeah, it's just kind of confusing behavior. So the solution would be Instead. you redefine, if you want to redefine the name to match, the original name, you can do that yourself manually. and otherwise it'll just be this new decorated method. So like every function here would have the name X by defaults Okay, thanks. +KHG: Okay. So let me see if I can make an example real quick, so, actually, I think. RBN has some example here. so currently a b and c. When they get decorated we return this anonymous function right here. So, a b and c. These names would be the name of whatever this anonymous function is. And what that leads to is. You have like really odd stack traces because you, have two a's or to b's. Because you know this function is going to call the original function. and yeah, it's just kind of confusing behavior. So the solution would be Instead. you redefine, if you want to redefine the name to match, the original name, you can do that yourself manually. and otherwise it'll just be this new decorated method. So like every function here would have the name X by defaults Okay, thanks. ACE: So the proposal is we don't do anything special with the name. The name of the function is just the name of the function, as it would be whenever right? -CHG Yes. Any other? questions? +KHG: Yes. Any other? questions? ACE: I'll just add: that is what I've been doing with decorators already, setting the name myself manually. So it seems good. -CHG: Does anyone object? +KHG: Does anyone object? MAH: I was thinking we didn't make sense to conditionally sets the name to the original method name. If the original function is an animus. So if it has an empty empty name, if you return the same anonymous function for multiple providers. yeah, so if you return an anonymous function, the decorator machinery would automatically set the name to the name of the methods that was degraded. @@ -905,31 +905,31 @@ LCA: What I'm saying is what if what if you create an anonymous function outside MAH: Yeah. but that would only happen the first time I guess but yeah, that would be problematic. -CHG: It sounds like that. We agree. That would be a bad idea. +KHG: It sounds like that. We agree. That would be a bad idea. RBN: Yeah, I was just going to say the same thing and that was Illustrated. although not Illustrated within unnamed function, but in the example that Chris had up a moment ago where with no op, If this were a function, that did not have an assigned name and I were using it the same way then the difference is instead of sun functioning resulting in logging acc, would log abb in still end up with that same situation. So I still don't think that's viable. SYG: (from queue): Prefer no conditional setting. "Things that look declarative ought to be declarative" -CHG: All right. so it sounds like consensus to remove set function name and dynamically setting the name. Great. Yes. Cool. +KHG: All right. so it sounds like consensus to remove set function name and dynamically setting the name. Great. Yes. Cool. -CHG: Okay. (PR pending, [issue](https://github.com/tc39/proposal-decorators/issues/468)) So the last issue here. is a bit more involved. Basically we've added this new accessor keyword, right? That if everybody remembers is basically a way to define a getter and a setter on the class, in a single statement. That access a private storage, that is backing that getter and setter. And the idea is that it works like a kind of field, but via decoration, and potentially, in the future via othe like property syntax. You would be able to intercept that get and that set. and replace it. So in classes, on class instances this works just fine because you can see like basically desugars to something like this. Imagine it without the static on a class instance. It's just like a private field, a getter and a setter that can access that private field. cool. But once we add `static`, we run into a problem because all class fields get to find on every instance and are inherited class fields as well. for instance private fields, but for static ones, they don't. static private fields, get defined just on just like normal Fields, on. on the class itself and they’re inherited on subclasses. classes via shadowing or prototypical inheritance. Whichever it is. So what this results in is if somebody tries to access on a child class here, this will throw an error because they can't access the private banks on the Sea. On the child class. It has to be on the superclass. and this kind of just makes not at all on for inheritance on. static. properties. So the proposed change is that instead of having it desugar, essentially to this. hashtag X, we would have a desugar to a direct reference to the class itself, which is basically how you would solve this problem if you're using static private fields today, if you you were doing that and a accessing it with, you know, get and set. You would just replace this with a typically and things would work. So yeah that's that's basically the proposal. Any questions about that? +KHG: Okay. (PR pending, [issue](https://github.com/tc39/proposal-decorators/issues/468)) So the last issue here. is a bit more involved. Basically we've added this new accessor keyword, right? That if everybody remembers is basically a way to define a getter and a setter on the class, in a single statement. That access a private storage, that is backing that getter and setter. And the idea is that it works like a kind of field, but via decoration, and potentially, in the future via othe like property syntax. You would be able to intercept that get and that set. and replace it. So in classes, on class instances this works just fine because you can see like basically desugars to something like this. Imagine it without the static on a class instance. It's just like a private field, a getter and a setter that can access that private field. cool. But once we add `static`, we run into a problem because all class fields get to find on every instance and are inherited class fields as well. for instance private fields, but for static ones, they don't. static private fields, get defined just on just like normal Fields, on. on the class itself and they’re inherited on subclasses. classes via shadowing or prototypical inheritance. Whichever it is. So what this results in is if somebody tries to access on a child class here, this will throw an error because they can't access the private banks on the Sea. On the child class. It has to be on the superclass. and this kind of just makes not at all on for inheritance on. static. properties. So the proposed change is that instead of having it desugar, essentially to this. hashtag X, we would have a desugar to a direct reference to the class itself, which is basically how you would solve this problem if you're using static private fields today, if you you were doing that and a accessing it with, you know, get and set. You would just replace this with a typically and things would work. So yeah that's that's basically the proposal. Any questions about that? DE: Okay, so I'm getting a plus one. This is a good fix. We spent two years discussing this case, about what the static private semantics should be. I don't know if we need improved documentation or something? Anyway, the fix seems correct. RBN: I just want to make sure and I need I regret that I did not see the there is no PR the addresses of fixing this, but I want to make sure that when we're talking about this that we're talking about, this isn't actually about return a.hash X. It's actually because if a itself decorated with something that replaces the constructor. It's not the value of a, at the end of decoration, it is the value of a before any decorators are run so that we're not making that confusion because that would be just as bad as this. this. -CHG: I believe that it will be the same A that private fields. access in general. I believe that. all instances of a get rebound to the return value of the decorators that are applied to the class itself. I'm pretty sure what you would need to make sure that it is whatever the value is that the private field is installed on. +KHG: I believe that it will be the same A that private fields. access in general. I believe that. all instances of a get rebound to the return value of the decorators that are applied to the class itself. I'm pretty sure what you would need to make sure that it is whatever the value is that the private field is installed on. RBN: yeah, my comment is correct. It should be the decorated class. We had this discussion before about the fact that the all private static fields end up installed on the decorated version, otherwise, static methods don't work? So yes, that's correct, I'm sorry. It should be the whatever the final version of what that class binding is -CHG: Yes, And that is the other thing we tried to preserve with decorations, is that you wouldn't ever end up in a split world where you'd have like one reference to a meeting one thing? and another reference to a meeting like the undecorated thing. So I'm pretty sure it's that all references to mean the decorated thing I'd have to have to look again to be 100% sure, but I'm pretty sure. Sure. Okay, I remember the reason why people didn't want that. to happen. The reason was they wanted decorators to run after fields were assigned and which would have forced fields to run in the un-decorated world. But we solve that with class initializers that can run after fields have been assigned. Okay. any other topics on the queue? +KHG: Yes, And that is the other thing we tried to preserve with decorations, is that you wouldn't ever end up in a split world where you'd have like one reference to a meeting one thing? and another reference to a meeting like the undecorated thing. So I'm pretty sure it's that all references to mean the decorated thing I'd have to have to look again to be 100% sure, but I'm pretty sure. Sure. Okay, I remember the reason why people didn't want that. to happen. The reason was they wanted decorators to run after fields were assigned and which would have forced fields to run in the un-decorated world. But we solve that with class initializers that can run after fields have been assigned. Okay. any other topics on the queue? NRO: Yes. I'm sure that this least like PR for this practice. We make it through here, but the private field is only on the Decorator class appears on the credit class and like that. but that's the only option as we work. I would be happy to review this spec for this PR, stuff like that. There is only a very possible answer here. -CHG: Yes, yeah. you can, you can look at the spec text in general for that, that has been rebound and everything properly in the specs currently. So we would just continue through with that. +KHG: Yes, yeah. you can, you can look at the spec text in general for that, that has been rebound and everything properly in the specs currently. So we would just continue through with that. -CHG: Do we have a consensus for this change? Pending the actual spec update? +KHG: Do we have a consensus for this change? Pending the actual spec update? RPR: Any. any voices of support for this? @@ -939,7 +939,7 @@ JHD: +1 RPR: All right, any objections? Doesn't. sound like it, so yeah, congratulations. You have consensus on number 6 as well. -CHG: Awesome. +KHG: Awesome. ### Conclusion @@ -954,46 +954,46 @@ Consensus of all 6 changes: ## Decorator Metadata Update -Presenter: Chris Garrett (CHG) +Presenter: Kristen Hewell Garrett (KHG) - [proposal](https://github.com/tc39/proposal-decorator-metadata) - [slides](https://slides.com/pzuraq/decorator-metadata-update-march-2023) -CHG: So yeah, Where we left off last time with decorator metadata is we broke it out from the decorator proposal which was at stage 2. So decorator metadata started at stage 2. and we ended up having a incubator call where we discussed it, and we all came to the conclusion on that call that yes, metadata is definitely needed, and there are some valid use cases for it. and we came up with the basic strategy for how we wanted to pursue metadata in that call. However, there has been some debate over exactly how that will be implemented and everything. So today I'm going to talk about the kind of the current proposal, a few different options, the current proposal, which is my preferred option, and several others, as well. Very strongly, but then a more minimal version, that would be a little bit more restrictive in some ways. And then what I see as kind of a compromise solution. +KHG: So yeah, Where we left off last time with decorator metadata is we broke it out from the decorator proposal which was at stage 2. So decorator metadata started at stage 2. and we ended up having a incubator call where we discussed it, and we all came to the conclusion on that call that yes, metadata is definitely needed, and there are some valid use cases for it. and we came up with the basic strategy for how we wanted to pursue metadata in that call. However, there has been some debate over exactly how that will be implemented and everything. So today I'm going to talk about the kind of the current proposal, a few different options, the current proposal, which is my preferred option, and several others, as well. Very strongly, but then a more minimal version, that would be a little bit more restrictive in some ways. And then what I see as kind of a compromise solution. -CHG: Quick refresher. Why is metadata useful? Well, it's used for a lot of things like dependency injection. ORMs, runtime type information for like, you know, various type checking frameworks and frameworks that use that type information. serialization unit, testing routing debugging, membranes, and to top it off, `Reflect.metadata` is the single most used decorator library, which definitely suggests that this is a useful pattern overall. +KHG: Quick refresher. Why is metadata useful? Well, it's used for a lot of things like dependency injection. ORMs, runtime type information for like, you know, various type checking frameworks and frameworks that use that type information. serialization unit, testing routing debugging, membranes, and to top it off, `Reflect.metadata` is the single most used decorator library, which definitely suggests that this is a useful pattern overall. -CHG: How metadata used to work: In legacy TypeScripts, or a Babel decorators, they would receive the class itself directly and because they received the class itself, we could do things like place a value directly on the class, You could define, underscore underscore types, or symbol types, and for other types. And put your Types on the class directly or you could use a WeakMap to associate it in a way that was private with the class. So, this gave people a lot of flexibility when defining metadata. However, this is no longer possible because in order to make sure that decoration was as static as possible, and didn't allow people to change the shape of a class dynamically. we no longer give people the reference to the class itself. In fact, we don't give them a reference to any value that they can tie back to that class. So there really is no way that you can currently. with the stage 3 decorators proposal. side-channel any metadata. specific to that class in an ergonomic way. In a way that would be one to one with what was previously possible. There have been some proposals where you would maybe create an entangled decorator like have that decorator itself hold the metadata. But that has been called out as having way too much boilerplate. Basically, every time it's been brought up. So that's why we're adding metadata as a first-class supported thing. +KHG: How metadata used to work: In legacy TypeScripts, or a Babel decorators, they would receive the class itself directly and because they received the class itself, we could do things like place a value directly on the class, You could define, underscore underscore types, or symbol types, and for other types. And put your Types on the class directly or you could use a WeakMap to associate it in a way that was private with the class. So, this gave people a lot of flexibility when defining metadata. However, this is no longer possible because in order to make sure that decoration was as static as possible, and didn't allow people to change the shape of a class dynamically. we no longer give people the reference to the class itself. In fact, we don't give them a reference to any value that they can tie back to that class. So there really is no way that you can currently. with the stage 3 decorators proposal. side-channel any metadata. specific to that class in an ergonomic way. In a way that would be one to one with what was previously possible. There have been some proposals where you would maybe create an entangled decorator like have that decorator itself hold the metadata. But that has been called out as having way too much boilerplate. Basically, every time it's been brought up. So that's why we're adding metadata as a first-class supported thing. -CHG: So yeah. Let's talk about the current proposal. so, basically, what we would do is pass in a plain JavaScript object called metadata on the decorator context object. Every decorator, applied to the class would receive the same object and they would be able to define whatever they wanted on that object. And then at the end of class definition that object would be assigned to Symbol.metadata on the class itself. In addition this metadata object would inherit from any parent classes metadata object. So it would look up prior to being passed in prior to decoration, we would look up `Symbol.metadata` on the parent class, we would, you know, `Object.create` with the parent classes, `Symbol.metadata` objects and if it existed and the child class would be able to then look up parent class metadata using standard prototypical inheritance. +KHG: So yeah. Let's talk about the current proposal. so, basically, what we would do is pass in a plain JavaScript object called metadata on the decorator context object. Every decorator, applied to the class would receive the same object and they would be able to define whatever they wanted on that object. And then at the end of class definition that object would be assigned to Symbol.metadata on the class itself. In addition this metadata object would inherit from any parent classes metadata object. So it would look up prior to being passed in prior to decoration, we would look up `Symbol.metadata` on the parent class, we would, you know, `Object.create` with the parent classes, `Symbol.metadata` objects and if it existed and the child class would be able to then look up parent class metadata using standard prototypical inheritance. -CHG: So the pros of this approach are it's very simple and straightforward. We can do public metadata where if a decorator author wants to for instance share type information or validation information, they can share that in a public way. they can create a well-known key. Either. a symbol or a string key, and then other decorators can then read that information and use it in a way. And this is something that we see a lot of in the ecosystem. And at the same time, you can create truly private metadata by using a WeakMap. You just would use the metadata object itself as the key in the WeakMap and then it would work. kind of similarly to you how it would work previously. and then we have inheritance with that, you know? works just like class inheritance, just like prototypical inheritance. by default things Shadow and it's pretty easy to override metadata on a child class but just like with prototypical inheritance, you can manually crawl the prototype chain to find out what the parent classes metadata was. so, the major con with this approach that has been pointed out, is that this creates a shared namespace, a global namespace effectively where anybody could and will add string names to this object. and it could become a space where people are fighting for particular names or decorators are stepping on each other's toes. And it could cause weird undefined behavior and things breaking, in other places. +KHG: So the pros of this approach are it's very simple and straightforward. We can do public metadata where if a decorator author wants to for instance share type information or validation information, they can share that in a public way. they can create a well-known key. Either. a symbol or a string key, and then other decorators can then read that information and use it in a way. And this is something that we see a lot of in the ecosystem. And at the same time, you can create truly private metadata by using a WeakMap. You just would use the metadata object itself as the key in the WeakMap and then it would work. kind of similarly to you how it would work previously. and then we have inheritance with that, you know? works just like class inheritance, just like prototypical inheritance. by default things Shadow and it's pretty easy to override metadata on a child class but just like with prototypical inheritance, you can manually crawl the prototype chain to find out what the parent classes metadata was. so, the major con with this approach that has been pointed out, is that this creates a shared namespace, a global namespace effectively where anybody could and will add string names to this object. and it could become a space where people are fighting for particular names or decorators are stepping on each other's toes. And it could cause weird undefined behavior and things breaking, in other places. -CHG: So, with that in mind, we come to option 2. So the option 2. idea is basically we kind of similar, we pass in that object. that metadata object on. context. However, it is a frozen object. and as a frozen object, it is only meant to be used as a key in a WeakMap, and it would also have a `parent` property, so you could look up parent parent metadata as well. so this this would basically force people into using private metadata all the time and there would be no way to have a shared namespace. The pro is it is private by default, and generally encourages what is probably the best practice by default, and there is no shared global namespace for people to accidentally collide in. The cons are there is really no way to share public metadata. with this setup. And we've discussed this. Supporters of this particular solution had pointed out that if you wanted to make public metadata, you could export a WeakMap or an API to look up the metadata for a decorator. My personal worry there is that, that really just exposes the intricacies and details of the build systems themselves that are exposing those modules. I mean, we already live in a world where duplication is very common, and it is possible that you could get multiple modules from the same library in a single build of the app. And if we haven't fully duplicated every single one, you might end up with a split world where metadata that is logically part of the same set can only be accessed partially from one part of the app or the other. And if that's the case, you might say, well, you could just put the metadata on the window, and make sure that every instance of the library that is exposing it shares all of its state. But that brings us right back to where we were before. We have a shared global namespace. What's worse is that that doesn't work in secure ECMAscript contexts for we wouldn't be able to because you're not allowed to put things on window. So I'm not sure that it would be better to push people in that direction. And in addition inheritance is a little bit trickier to use, but that's not a major driver for me, personally, I'm more worried about the complexity that this solution would introduce for sharing public metadata. +KHG: So, with that in mind, we come to option 2. So the option 2. idea is basically we kind of similar, we pass in that object. that metadata object on. context. However, it is a frozen object. and as a frozen object, it is only meant to be used as a key in a WeakMap, and it would also have a `parent` property, so you could look up parent parent metadata as well. so this this would basically force people into using private metadata all the time and there would be no way to have a shared namespace. The pro is it is private by default, and generally encourages what is probably the best practice by default, and there is no shared global namespace for people to accidentally collide in. The cons are there is really no way to share public metadata. with this setup. And we've discussed this. Supporters of this particular solution had pointed out that if you wanted to make public metadata, you could export a WeakMap or an API to look up the metadata for a decorator. My personal worry there is that, that really just exposes the intricacies and details of the build systems themselves that are exposing those modules. I mean, we already live in a world where duplication is very common, and it is possible that you could get multiple modules from the same library in a single build of the app. And if we haven't fully duplicated every single one, you might end up with a split world where metadata that is logically part of the same set can only be accessed partially from one part of the app or the other. And if that's the case, you might say, well, you could just put the metadata on the window, and make sure that every instance of the library that is exposing it shares all of its state. But that brings us right back to where we were before. We have a shared global namespace. What's worse is that that doesn't work in secure ECMAscript contexts for we wouldn't be able to because you're not allowed to put things on window. So I'm not sure that it would be better to push people in that direction. And in addition inheritance is a little bit trickier to use, but that's not a major driver for me, personally, I'm more worried about the complexity that this solution would introduce for sharing public metadata. -CHG: Okay, option three. The idea behind option three is basically to have it be the same as option one in terms of what actually gets exposed: it's an object, it has inheritance, and it's just a plain JavaScript object, not frozen, but we would guard access to that object with getter and setter functions on the context that the decorator receives. The getter and setter functions would force users to only use symbols as keys. This would help us to prevent collisions because by defaults users when they make a new symbol unless they're using `Symbol.for` will be making a unique simple. And unless they, you know, expose that symbol if they export that symbol the only way for anybody else to get it would be to use object. prototype or get own property symbols. And that would have to be used on a class after being decorated. It's multiple steps. and it makes it just a bit more inconvenient to use a well-known name and accidentally have collisions. Other than that, it's basically exactly the same as the option one. And the idea is that it kind of addresses some of the concerns: it encourages people to avoid the issues that come up with option two, but still allows people to intentionally share public metadata. When they want to That's that's pretty much all three options. +KHG: Okay, option three. The idea behind option three is basically to have it be the same as option one in terms of what actually gets exposed: it's an object, it has inheritance, and it's just a plain JavaScript object, not frozen, but we would guard access to that object with getter and setter functions on the context that the decorator receives. The getter and setter functions would force users to only use symbols as keys. This would help us to prevent collisions because by defaults users when they make a new symbol unless they're using `Symbol.for` will be making a unique simple. And unless they, you know, expose that symbol if they export that symbol the only way for anybody else to get it would be to use object. prototype or get own property symbols. And that would have to be used on a class after being decorated. It's multiple steps. and it makes it just a bit more inconvenient to use a well-known name and accidentally have collisions. Other than that, it's basically exactly the same as the option one. And the idea is that it kind of addresses some of the concerns: it encourages people to avoid the issues that come up with option two, but still allows people to intentionally share public metadata. When they want to That's that's pretty much all three options. MM: Okay so I have a question that's mostly about option number one. In the normal use um, for embedded where you're concerned about putting things in ROM and for security where you're concerned about hardening things, making many properties, many objects frozen, for option number one and option number three, where you've got a object that's mutable. During initialization, if I do understand. this proposal does not end and given the nature of the proposal should not for options. One in three. specify that after the class is initialize that the object, The Meta object get transitively frozen. My question is in an environment in which something else would transitively freeze them after the class is initialized, do you expect that the patterns of usage that you know, that you've seen that, you expect people to use the meta object for would or would not get broken. by transitively. Freezing The Meta object basically transitively, freezing, the meta object, at the same time. That one is transitively is transitively freezing the class itself, the class prototype and the methods of the class—basically everything, transitively. Freezing the class means, of course, freezing the things that are reachable from the class that would include the metaobject, right? -CHG: I would not expect that to cause any breakage metadata is typically used in a very static way, The values that are provided on there are not mutated after the fact, they really just define declaratively what's expected of the class or whatever from a particular decorator. The only usage that you I've seen, that is mildly problematic with these cases the case where, you know, to decorators choose the same key on metadata and collide but I've never seen The metadata object used directly as a store of information. +KHG: I would not expect that to cause any breakage metadata is typically used in a very static way, The values that are provided on there are not mutated after the fact, they really just define declaratively what's expected of the class or whatever from a particular decorator. The only usage that you I've seen, that is mildly problematic with these cases the case where, you know, to decorators choose the same key on metadata and collide but I've never seen The metadata object used directly as a store of information. MM: And then with regard to option, three, you said that the context object would enforce with accessor properties, that you could only set symbol-named properties on the metaobject. So that means it's only just confirmed because I think I initially misread the proposal as implying that option. Number one, option number three, The Meta object need to be exotic. in order to allow the creation of symbol name. Properties. but not allow the creation of string name properties. where you're not saying that. but the Text object would also. not as so, how would the context object? enforced us without the context? Object itself needing, either something exotic or proxy? -CHG: So, the context object would just have two functions `setMetadata`, and `getMetadata`. It would not have direct access to the object that gets defined on `Symbol.metadata` users would be to use context set metadata to set a key on that object that it's backing. this. And for instance, if they wanted to use a WeakMap, they could either set the key to a value that is a symbol and then then use As WeakMap key. now that we can or just set it to an object and that use that object as WeakMap key. So it would be one more step for people who want to use WeakMaps for privacy, But it's not that much overhead. Okay, thank you. +KHG: So, the context object would just have two functions `setMetadata`, and `getMetadata`. It would not have direct access to the object that gets defined on `Symbol.metadata` users would be to use context set metadata to set a key on that object that it's backing. this. And for instance, if they wanted to use a WeakMap, they could either set the key to a value that is a symbol and then then use As WeakMap key. now that we can or just set it to an object and that use that object as WeakMap key. So it would be one more step for people who want to use WeakMaps for privacy, But it's not that much overhead. Okay, thank you. MM: I'll refrain from stating an opinion at this time. but you've answered everything that would have been an objection to any of these three proposals. Yes. KG: So Chris knows this but for everyone else, I am very strongly in favor of Option 2 over Option 1, and in particular the shared namespace aspect of option, one seems like it ought to be fatal to me. I understand not everyone shares that intuition, but for me, the con is: we are introducing a new Global shared namespace. I would prefer to kill most proposals over having a new global shared namespace. So, for option 2 the only listed cons, there are two. One was that it makes inheritance trickier, which I kind of agree with. The other is that it doesn't allow you to share public metadata, but of course it does allow you to share public metadata as Chris pointed out. You share the way that you always share data between libraries, which is that you export a function that allows people to look up data. The downside of this as again, Chris pointed out is that this means that you might have multiple versions of a library built into your application and they would have different versions of the metadata. But to my mind, this is like I'm actively good thing. This is a property that we want, the whole reason that the build system in, for example, npm, works the way that it does is because the requirement that you have like a globally unique version of every library and as soon as you start including multiple versions of a library things break, that was a very bad situation and the situation that we like is where two different things can import. from different versions. of the same library and both bits of the library can be in the same application. And that works. I don't have to worry about if I upgrade you know, 1.0 to version 2.0, which changes how the type property on the metadata works that breaks everything because I have a different library that's expecting version 1 of the type meta data and like have one library that expects version 1 of the type meta data and one version that expects version 2 of the type meta data. And now, those fundamentally cannot operate because they are working in the shared namespace that is a bad situation. which we should avoid it. But we avoid it the way we always avoid it, which is that you used imports and exports and the build system just wires things up for you. so, I really don't like having a shared Global namespace. I think, that is very bad thing and importing and exporting works great for everyone except TypeScript to as a genuinely unique constraint, but you do get shared metadata with option two, you just export a thing that lets you share the same way you always share. -CHG: I do want to respond to that. It's not as simple as you make it seem a great example of where this could absolutely fall down very easily is dependency injection. If you have a single container for your app, which is the entire point of dependency injection, and that container gets a version of the metadata that does not fully describe everything that is supposed to be injected, your entire app will fall apart and you can easily get into that situation if you have a minor version difference between two libraries, not a major version even just a minor version. And so now, they're bundling two separate minor versions, and build tools. make these types of decisions all the time. This is not spec'd. We do not have a spec for when you deduplicate modules and when you don't. So you basically are pushing this problem to modules, and you're saying like, Okay, it's up to the build system to figure out, and now everybody has to learn all the details of the build system to figure out. To duplicate everything just so they can have their dependency injection. +KHG: I do want to respond to that. It's not as simple as you make it seem a great example of where this could absolutely fall down very easily is dependency injection. If you have a single container for your app, which is the entire point of dependency injection, and that container gets a version of the metadata that does not fully describe everything that is supposed to be injected, your entire app will fall apart and you can easily get into that situation if you have a minor version difference between two libraries, not a major version even just a minor version. And so now, they're bundling two separate minor versions, and build tools. make these types of decisions all the time. This is not spec'd. We do not have a spec for when you deduplicate modules and when you don't. So you basically are pushing this problem to modules, and you're saying like, Okay, it's up to the build system to figure out, and now everybody has to learn all the details of the build system to figure out. To duplicate everything just so they can have their dependency injection. KG: So you have exactly the opposite problem with option one, which is that now, if I have a version bump, that should have been not breaking because I have one part of my library that expect it to work, and now, the format changes And like now I can't have two versions of the library. Like, I was that not exactly the same problem problem I didn't. Grade, it shouldn't have broken anything because I just needed like some separate part of the application. I have a different version of the library, But like now, the format of the public namespace has changed. And so the thing that previously worked didn't I mean this is -CHG: this is one of the things that when you're working on a dependency injection framework or something like that, you’re very careful about those changes because you're aware of that +KHG: this is one of the things that when you're working on a dependency injection framework or something like that, you’re very careful about those changes because you're aware of that KG: okay? So if the solution to this problem is that people should be very careful, we shouldn't produce a new thing they have to be very careful about. They should just live in the world that they're already in, where deduplication and non-duplication of libraries is a thing that comes up. That's a thing that is familiar to people already. -CHG: and that is it's a thing that doesn't necessarily even have a solution like some build tools. Don't give you the option to deduplicate things properly. great, but like the names will just collide. +KHG: and that is it's a thing that doesn't necessarily even have a solution like some build tools. Don't give you the option to deduplicate things properly. great, but like the names will just collide. KG: That is not a solution to the problem, it's - "You only get deduplication" is no more of a solution to this problem than like "deduplication works for metadata the way that it already works in the rest of your application". @@ -1009,11 +1009,11 @@ DE: I think we seem to have a shared understanding that Library duplication happ MAH: Yeah. I'm not sure that module identity discontinuity is problem re specific to metadata decorators made of metadata. This can happen in a lot of other cases and it's more General ecosystem problem. problem. that I'm not sure should wait that heavily on the decision here. -CHG: I think the reason I bring that up is not because it is a specific problem to decorators.I don't think that’s the way it was being framed. Was that Global namespace is have all the problems and modules fix those problems. And thus, they have no problems. And my point was just like modules had problems, too. like. we have a hard problem here and I think no matter what the solution we choose is, there's going to be a lot of trickiness in dealing with all of the problems of it because the goal is to share public metadata in a global way that is act that is the actual goal. by the way, +KHG: I think the reason I bring that up is not because it is a specific problem to decorators.I don't think that’s the way it was being framed. Was that Global namespace is have all the problems and modules fix those problems. And thus, they have no problems. And my point was just like modules had problems, too. like. we have a hard problem here and I think no matter what the solution we choose is, there's going to be a lot of trickiness in dealing with all of the problems of it because the goal is to share public metadata in a global way that is act that is the actual goal. by the way, MAH: I've have a little nit on that. It's not a global name space. It's a namespace scope to the class being decorated -CHG: yeah. I think we're using that as a shorthand, but yeah. we tend to move forward. +KHG: yeah. I think we're using that as a shorthand, but yeah. we tend to move forward. DE: so, just overall, I think it's important that we keep this system simple and I'm happy that stage one that option 1 is a very simple proposal. It's great that the decorator proposal just keeps getting similar and simpler. @@ -1025,7 +1025,7 @@ CDA:. I don't have anything to add from what's already been pointed out, just ex JHB. Yeah. So I'm asking basically what's wrong with option 2? But it like with it, take away the frozen object question and just provide a symbol Yeah. -CHG: So the reason we're using a frozen object is so that you can access parent metadata during decoration. Otherwise we could use a symbol but it has all of the downsides of option to and basically has all the same problems. +KHG: So the reason we're using a frozen object is so that you can access parent metadata during decoration. Otherwise we could use a symbol but it has all of the downsides of option to and basically has all the same problems. JHD: Well, I guess I'm confused. In the frozen object case, the object is meant to be a key in a weak selection, right? Ah, the prototype has a parent always, so you climb up the frozen object, right, thank you. @@ -1033,19 +1033,19 @@ JFI: Yeah, just real quick. I want to iterate because it gets asked a lot when w MAH: Yeah. I want to say option 3 for me is a non-starter because it actually enables for a managed decorator to interfere with another decorator. by having a disconnect between the context subjects which in Option 1 & 2 is the identities preserved the creator can set this metadata that would conflict. The fact, it's the symbol doesn't mean there is no possibility of overwriting, another decorators metadata. It just means like non-malicious ori by chance overriding would not happen, So imagine decorator can go and set. the metadata. of another decorator and override it and if even if they do and give an option 3 forces, if you want private data you have. to use a single entry and associated with a WeakMap key. So now all the sudden you could get that overridden and there is no way to protect against against that -CHG: that's, a good point. Yeah, I do think that that would be something we'd have to design around. maybe we could make it so that when you initially define metadata, like, what's that metadata, you could specify that it has makes the property like non-writable or something but that again that seems like extra complexity that personally I would not prefer, +KHG: that's, a good point. Yeah, I do think that that would be something we'd have to design around. maybe we could make it so that when you initially define metadata, like, what's that metadata, you could specify that it has makes the property like non-writable or something but that again that seems like extra complexity that personally I would not prefer, MAH: right. -CHG: so, I don't know where we're at now with this. Basically, my plan was to try to get consensus here. on one of these options. so that we could propose for stage 3 at the next plenary. It sounds like we do not have consensus for any of the options at the moment though. +KHG: so, I don't know where we're at now with this. Basically, my plan was to try to get consensus here. on one of these options. so that we could propose for stage 3 at the next plenary. It sounds like we do not have consensus for any of the options at the moment though. KG: I'm not going to say that this proposal can't advance unless it has my preferred semantics. I have said my piece. There are people who still prefer option one. We are not going to reconcile those. So if the proposal is to advance, we need to pick one. I acknowledge I am in the minority and am ok saying we can live with option one. MM: So, I'm going to register that option 3, given the answer to MAH’s question for me is clearly disqualified so that I'm okay with either one or two. -RPR: I don’t think anyone is pitching option 3 at this point. So as DE says, how about CHG would you like to ask for consensus on your preferred option? +RPR: I don’t think anyone is pitching option 3 at this point. So as DE says, how about KHG would you like to ask for consensus on your preferred option? -CHG: Yeah, Do we have consensus for option one? one? +KHG: Yeah, Do we have consensus for option one? one? RPR: Hey, is there any support for option one? I think there was so DE, PDL, CDA. So you have three supporters for option one. Are there any objections to option one? Or any non-blocking concerns? @@ -1057,7 +1057,7 @@ MF: I also agree with KG. RPR: Okay. So we have MF, KG, and JHD who prefer option 2. and we had another voice supporting option 1 from Justin. So the moment looks like we have consensus for option one. -CHG: Okay. the nice thing is also like a spec. It has. already been written for that. So if y'all want to review it, I will be presenting for stage 3 at the next plenary. So yeah, cool Thanks everyone. +KHG: Okay. the nice thing is also like a spec. It has. already been written for that. So if y'all want to review it, I will be presenting for stage 3 at the next plenary. So yeah, cool Thanks everyone. ### Summary of Key Points diff --git a/meetings/2023-03/mar-23.md b/meetings/2023-03/mar-23.md index c240ee23..32c02a89 100644 --- a/meetings/2023-03/mar-23.md +++ b/meetings/2023-03/mar-23.md @@ -805,7 +805,7 @@ DE: But . . . I would like people who have strong concerns to think about whethe CDA: We are over time. But . . . I think we can use the last few minutes here to maybe hopefully get through the last items in the queue, if that’s all right. -RBN: I want to respond to DE if we could and a response to KG as well. I fully intend to bring a proposal for function declaration decorators and object decorators most likely this year. This is something I’ve been discussing with CHG and others over time. However, because of the existing TypeScript eco system and the potential – migrating everybody to native decorators I wanted to get out here first to have these discussions first. Regardless of what state function declaration decorators end up being. I plan to have those as part of the discussion. Talking about class and method, this is higher than bringing them themselves. +RBN: I want to respond to DE if we could and a response to KG as well. I fully intend to bring a proposal for function declaration decorators and object decorators most likely this year. This is something I’ve been discussing with KHG and others over time. However, because of the existing TypeScript eco system and the potential – migrating everybody to native decorators I wanted to get out here first to have these discussions first. Regardless of what state function declaration decorators end up being. I plan to have those as part of the discussion. Talking about class and method, this is higher than bringing them themselves. DE: Yeah. I think that’s reasonable. But I also think we can see that we will have to have the bigger picture together. Before we can advance these things beyond Stage 1. diff --git a/meetings/2023-05/may-16.md b/meetings/2023-05/may-16.md index 19869979..0089dc0c 100644 --- a/meetings/2023-05/may-16.md +++ b/meetings/2023-05/may-16.md @@ -264,84 +264,84 @@ JRL: Okay. So we just need the urgent communication channel and implementers wil ## Decorator field/accessor initializer order -Presenter: Chris Garrett (CHG) +Presenter: Kristen Hewell Garrett (KHG) - [issue](https://github.com/tc39/proposal-decorators/issues/508) - [slides](https://slides.com/pzuraq/decorators-field-accessor-initializer-order) -CHG: This issue got brought up recently by someone who was playing around with the decorators implementations in the transforms and Babel and what not. They thought it was a bug at first, and we started looking at it and realized that this actually may be an issue, and may warrant a change. So I just thought I’d bring it to committee to see what everybody thinks. So basically the issue right now is that field and accessor initializers run from the innermost decorator to the outermost decorator. So in this example here, an Int of times 4 is called four and then-2 is called. So we take 5, multiply it by 4, and subtract 2 and the result is 18. However, getters and setters are replaced from inner most to outer most and that what this means is they execute in the reverse order from outer most to inner most. So in this example here we have minus 2 gets called first when we set the value to update it to the exact same value it started as. Minus 2 is called first and then times 4. And that is a result of 12. So after looking at this for a while, I realized there wasn’t really a way to have an accessor specifically that can set the initial value and the updated value given the same input through the same output. So, yeah, this could be an issue for people who would expect that and are trying to write decorators that do that. +KHG: This issue got brought up recently by someone who was playing around with the decorators implementations in the transforms and Babel and what not. They thought it was a bug at first, and we started looking at it and realized that this actually may be an issue, and may warrant a change. So I just thought I’d bring it to committee to see what everybody thinks. So basically the issue right now is that field and accessor initializers run from the innermost decorator to the outermost decorator. So in this example here, an Int of times 4 is called four and then-2 is called. So we take 5, multiply it by 4, and subtract 2 and the result is 18. However, getters and setters are replaced from inner most to outer most and that what this means is they execute in the reverse order from outer most to inner most. So in this example here we have minus 2 gets called first when we set the value to update it to the exact same value it started as. Minus 2 is called first and then times 4. And that is a result of 12. So after looking at this for a while, I realized there wasn’t really a way to have an accessor specifically that can set the initial value and the updated value given the same input through the same output. So, yeah, this could be an issue for people who would expect that and are trying to write decorators that do that. -CHG: So why is this an issue that’s coming up now? First off, previously, TypeScript and Babel legacy, you know, the original decorators transforms that we based the proposal off of and that it evolved from did run initializers in this current order. And it worked for a very long time and there were really no issues with it. The reason, though, that it worked, that we didn’t realize was an issue here was they would also then take that initial value and assign it to the field with set semantics, so it would trig for setters for that field and it would set that value on the instance through the setters. With the switch to define semantics, that kind of -- it’s no longer the case and the current proposal does not do that. So the initial value just gets set directly and the setters are never triggered. +KHG: So why is this an issue that’s coming up now? First off, previously, TypeScript and Babel legacy, you know, the original decorators transforms that we based the proposal off of and that it evolved from did run initializers in this current order. And it worked for a very long time and there were really no issues with it. The reason, though, that it worked, that we didn’t realize was an issue here was they would also then take that initial value and assign it to the field with set semantics, so it would trig for setters for that field and it would set that value on the instance through the setters. With the switch to define semantics, that kind of -- it’s no longer the case and the current proposal does not do that. So the initial value just gets set directly and the setters are never triggered. -CHG: So we have two proposals potentially for how we can solve this. One is to simply reverse the order of the initializers so they would run from outermost to innermost. Conceptually we can think as if the value is being set and the initializers are running through same order as if you called a setter on this field. And this would mean that basically all execution of decorators would run from outermost to innermost in all cases. To be clear, decorators themselves would still evaluate and apply their transform from innermost to outermost, but the value they return, for instance, the method or the setter or the initializer, that would be called from outermost to innermost, which is already the case for methods. So that’s one option. The other option would be to restore the previous behavior. We would essentially have setters be called with -- so the initial value for accessors specifically would still be initialized in the current order and then it would run through the setters of the accessor, so in this case, with the original implementations, we would end up with 64 as the initial value, but that’s because the initial value is going through this twice. So what you would really do is if you wanted to implement this, you would just remove this init from both of these and the setters would call like normal and you would end up with the same value, so the benefits of this one are that it is basically similar to what the current system is doing so it’s less churn overall, and, yeah, it really only affects auto accessors, fields would remain exactly the same, methods would remain exactly the same. And so on. The only other downside of this approach is that it does make it slightly harder to distinguish between the initial value and the updated value. Like, if the setter has ever been called, but it should still be possible to do via a WeakSet. So, yeah, I do think both of these would work. Any thoughts, questions, clarifications? +KHG: So we have two proposals potentially for how we can solve this. One is to simply reverse the order of the initializers so they would run from outermost to innermost. Conceptually we can think as if the value is being set and the initializers are running through same order as if you called a setter on this field. And this would mean that basically all execution of decorators would run from outermost to innermost in all cases. To be clear, decorators themselves would still evaluate and apply their transform from innermost to outermost, but the value they return, for instance, the method or the setter or the initializer, that would be called from outermost to innermost, which is already the case for methods. So that’s one option. The other option would be to restore the previous behavior. We would essentially have setters be called with -- so the initial value for accessors specifically would still be initialized in the current order and then it would run through the setters of the accessor, so in this case, with the original implementations, we would end up with 64 as the initial value, but that’s because the initial value is going through this twice. So what you would really do is if you wanted to implement this, you would just remove this init from both of these and the setters would call like normal and you would end up with the same value, so the benefits of this one are that it is basically similar to what the current system is doing so it’s less churn overall, and, yeah, it really only affects auto accessors, fields would remain exactly the same, methods would remain exactly the same. And so on. The only other downside of this approach is that it does make it slightly harder to distinguish between the initial value and the updated value. Like, if the setter has ever been called, but it should still be possible to do via a WeakSet. So, yeah, I do think both of these would work. Any thoughts, questions, clarifications? NRO: Yes, can you share the first example with a set and init. So if in this example we also added a get -- now a set would first run the minusTwo setter and then the timesFour setter, right? -CHG: Yes. +KHG: Yes. NRO: Okay. If you also did a get to both the decorators, that does the same thing. So minusTwo that subtracts 2 from the value, and timesFour that multiplies by 4. Would the result here be that the values first subtract 2 and multiply by 4 or multiply by 4 and subtract 2? -CHG: So with a getter, they run from timesFour to minusTwo, I believe, because you’re calling the original getter first, and then -- so the outer one calls the inner one. You know, you’re replacing the getter with another getter. Yeah, that calls the inner one. And you could get the correct behavior, quote, unquote, here, by replacing both of these with a getter, but the reason you might want to do this style of using set and init is to cache that value to you’re not calling it on every single get. So that’s one of the reasons why this particular issue could be a problem. To be clear, the getter is the -- the outermost getter still runs first, it just calls within its own function the timesFour decorator and then that calls within its function the getter that gets the initial value or the value that’s stored in the private slot. Like, first and last here is kind of not really -- it’s like -- that’s why I say outermost and innermost. You could order your logic in minusTwo to happen before or after timesFour. Yeah. +KHG: So with a getter, they run from timesFour to minusTwo, I believe, because you’re calling the original getter first, and then -- so the outer one calls the inner one. You know, you’re replacing the getter with another getter. Yeah, that calls the inner one. And you could get the correct behavior, quote, unquote, here, by replacing both of these with a getter, but the reason you might want to do this style of using set and init is to cache that value to you’re not calling it on every single get. So that’s one of the reasons why this particular issue could be a problem. To be clear, the getter is the -- the outermost getter still runs first, it just calls within its own function the timesFour decorator and then that calls within its function the getter that gets the initial value or the value that’s stored in the private slot. Like, first and last here is kind of not really -- it’s like -- that’s why I say outermost and innermost. You could order your logic in minusTwo to happen before or after timesFour. Yeah. NRO: Yeah, so just to clarify, getter and setter would always run in, like in the same direction, which means that the transformations applied to the value are in different directions, because for one it's happening on the return value and for the other on the parameter? -CHG: Yes. I believe. +KHG: Yes. I believe. NRO: Okay, thank you. WH: I had the same question, and I do not understand the answer. To give a concrete example, if `minusTwo` also had a getter which added 2, and `timesFour` also had a getter which divided by 4, then what would be the value actually stored and what would the getter show you if you had both the setter and the getter? -CHG: that would make this example more confusing. Because then you would be doing it twice. So if you had a setter and a getter and they were both doing this, and you set the value, +KHG: that would make this example more confusing. Because then you would be doing it twice. So if you had a setter and a getter and they were both doing this, and you set the value, WH: The scenario is this. The setters are as on the slide, but the getter of `minusTwo` would add 2 and the getter of `timesFour` would divide by four. -CHG: okay, so set would be called first, and say we set it to 6, and so minus two times four is 16 and 16 is stored in there and when we get the value of 16, it will divide it by 4 and that is 4 and add 2 and that is 6 again. +KHG: okay, so set would be called first, and say we set it to 6, and so minus two times four is 16 and 16 is stored in there and when we get the value of 16, it will divide it by 4 and that is 4 and add 2 and that is 6 again. WH: The getters are running in the opposite order of the setters, correct? -CHG: kind of like, the effects of getters are going to be in the opposite order of setters, but again, the reason is because the outer getter is calling the inner getter and the outer getter can replace the inner getter entirely and not call it at all if it wanted to. Which is the point of decoration and you are turning a new function that will replace the old function. I guess. Like the effect is that the inner getter will run before the outer getter. +KHG: kind of like, the effects of getters are going to be in the opposite order of setters, but again, the reason is because the outer getter is calling the inner getter and the outer getter can replace the inner getter entirely and not call it at all if it wanted to. Which is the point of decoration and you are turning a new function that will replace the old function. I guess. Like the effect is that the inner getter will run before the outer getter. WH: And the inner setter will run before the outer set? -CHG: yes +KHG: yes WH: Okay, that is good. That is the correct answer. JRL: Option two does not seem to be solving the bug but adding a new bug. On the issue thread, the bug is that the order of the init and the set call order are different. And we can see that still here in this option 2. If you noticed init does times `initValue * 4 - 2` and the set value will do `initValue - 2 * 4` and it is still in the opposite order. We have not solved the bug, in fact we will have made it worse, because init will call all of your setters? -CHG: two points there, because of the setters, you no longer need the init, you could remove it and have the behavior that you want. The other part of this is the existing behavior that many things need init on top, it is not my preferred behavior, I would prefer proposal 1 but that would mean less churn and be a smaller change overall in some ways. +KHG: two points there, because of the setters, you no longer need the init, you could remove it and have the behavior that you want. The other part of this is the existing behavior that many things need init on top, it is not my preferred behavior, I would prefer proposal 1 but that would mean less churn and be a smaller change overall in some ways. JRL: The churn is happening because we chose Define semantics. And we are adding back Set semantics in Option 2. -CHG: I would be happy with reversing the initial order. +KHG: I would be happy with reversing the initial order. JRL: Option 1 is my preferred option as well. SYG: So let me make sure I fully understand. So my initial thought is that reverse order initializers and this is just different. So could you remind me again the like why we should fix the ordering to be completely the same here? -CHG: The reason would be let’s say you wanted to make these decorators, right and you wanted them to cache the value. We would really not be able to do it. You would have to implement this as a getter that completes the value, and that is only way to do it. And additionally, like for our use cases for this type of thing where people will want to take a value or transform it or wrap it and cache the that result. So it does seem to make sense to enable that. Yeah. +KHG: The reason would be let’s say you wanted to make these decorators, right and you wanted them to cache the value. We would really not be able to do it. You would have to implement this as a getter that completes the value, and that is only way to do it. And additionally, like for our use cases for this type of thing where people will want to take a value or transform it or wrap it and cache the that result. So it does seem to make sense to enable that. Yeah. SYG: Okay, I am not deep enough into the ecosystem, and I can take that at face value.But given that, I think I agree with what Justin was saying we have made a decision on Define for fields, as opposed to Set, and the proposal 2 feels very strange given that starting point. So if this needs to be fixed, or the behavior needs to be changed, seems 1 is better there. RBN : I want to clarify and if we change the initializer for accessor field we would be changing the initializer for non-accessor field because decorator design is specifically designed to allow you to overload a decorator and switch on kind and for some examples accessor field could apply to non-accessor field and switch unkind and make sure it happens in both cases. -CHG: Absolutely, and this would apply to fields and accessors if we changed it. +KHG: Absolutely, and this would apply to fields and accessors if we changed it. JHD: I think if you go back to the example slide? Yeah, so this seems super clear to me. And in simple cases decorators feel like they should be sugared for wrapped function and this should in all cases to my reading only b five times four minus two and always multiply by 4 and subtract 2, and nothing else should happen. This seems like it is a bug but the second bullet here from innermost to outermost, so yeah if that happens, and I am not entirely sure if I am advocating for proposal 1 but if proposal 1 addresses that behavior so those things are always consistent and that should be consistent for accessor or non-ACK second error any field or for methods and anything should be innermost to outermost. -CHG: to clarify decorators are evaluated from innermost to outermost but should be executed always from outermost to innermost. When assigning a value. The proposal would make that always the case. And I understand that seems a kind of counterintuitive but think about it from the setter perspective. What we are doing with the decoration is replacing the setter with a new method that has to call the original setter. +KHG: to clarify decorators are evaluated from innermost to outermost but should be executed always from outermost to innermost. When assigning a value. The proposal would make that always the case. And I understand that seems a kind of counterintuitive but think about it from the setter perspective. What we are doing with the decoration is replacing the setter with a new method that has to call the original setter. JHD: It is currently implemented that way, but does not need to be implemented that way. -CHG: how would it work in the reverse? +KHG: how would it work in the reverse? JHD: I would have to think about it. But I am saying from a broader perspective, it feels like the only right behavior to me is both evaluation of decorators and on execution of them from assignment value going from innermost to outermost. -CHG: Let’s think about this from a getter perspective, right. Like getters like WH pointed out and what you’re asking is that thinking about things like assignments I think should be from outer to inner and kind of get or executions should be from inner to outer, if that makes sense? +KHG: Let’s think about this from a getter perspective, right. Like getters like WH pointed out and what you’re asking is that thinking about things like assignments I think should be from outer to inner and kind of get or executions should be from inner to outer, if that makes sense? JHD: I clearly have not paged in enough of this to speak about this clearly and I feel strongly, by reading this code, that timesFour should happen first and minusTwo should happen second and it would be confusing to me if it was different. Before I don’t know if that answers the question on how to implement and that seems like the challenge and not something – we should focus on what the reader of the code believes what it should do. -CHG: I don’t think we can, and I don’t think it logically makes sense to have an inner decorator replace the outer decorator setter. In order for this to work, actually, minusTwowould have to decorate before timesFour and do it is recovery placement first and so then receive minus 4 to replace minus 2. +KHG: I don’t think we can, and I don’t think it logically makes sense to have an inner decorator replace the outer decorator setter. In order for this to work, actually, minusTwowould have to decorate before timesFour and do it is recovery placement first and so then receive minus 4 to replace minus 2. JHD: I will take this off life to see how it can implemented but reading this code it should be timesFour and minusTwo @@ -355,27 +355,27 @@ WH: When you have two decorators, each doing one level of quoting/unquoting, the JHD: Thanks, that helps clarify it for me a lot, eg with JSON stringifying and parsing and back and forth. Okay, so yeah, I think in that case, I am reacting because this example is about setters, and with a mix of getters and setters, I would not have such a strong opinion. -CHG: The proposed solution would treat the initial definition of the field as a set in that case. Instead of an access so it would run minus two times four because you are setting the value. +KHG: The proposed solution would treat the initial definition of the field as a set in that case. Instead of an access so it would run minus two times four because you are setting the value. PFC: We were talking about the example. I would like to give my compliments on how clearly it illustrated the problem. I think that the code sample really showed something that was unintuitive, and I shared the same intuition as JHD at first. I think the example really helps justify why we should consider a normative change here. I don’t have anything to say about which option it should be, just giving my compliments. EAO: Do we lose much functionality by restricting the syntax to only support one decorator on a thing rather than figuring how multiple decorators combine? As I have looked at the read of the proposal, and that only has examples that only ever use one decorator at a time. And I have looked through the issues as well and I was not able to find anything that discussed this. And as context I am not much of a decorator user and I will presume that this is something, this is obvious that it does not need to be stated but I am asking for it to be stated. Why do we need multiple decorators on any one thing? -CHG: so I can answer that in different parts. There are a lot of examples in the ecosystem that use multiple decorators and so you have ORM and define a column through multiple decorators and combinations of decorators and it really is like what the pattern of decorators is. And the idea is that you have a decorator that will take a value and transform it into the same type of value but add some decorations to it. This is how decorators and annotations have worked in other languages so it would be counterintuitive to say that JavaScript will only support a single decoration and both, conceptually, it is crucial and in the ecosystem it is extremely common. +KHG: so I can answer that in different parts. There are a lot of examples in the ecosystem that use multiple decorators and so you have ORM and define a column through multiple decorators and combinations of decorators and it really is like what the pattern of decorators is. And the idea is that you have a decorator that will take a value and transform it into the same type of value but add some decorations to it. This is how decorators and annotations have worked in other languages so it would be counterintuitive to say that JavaScript will only support a single decoration and both, conceptually, it is crucial and in the ecosystem it is extremely common. NRO: Yes, so if `init` was designed to be used the way `set` is, and instead of returning the value it would transform value and call the next initializer, this would solve the issue. Like now if we call all the `set` hooks and they are in order because one happens in the next decorator, and init happens after the initializer from the previous decorator returns. While if we use the same style of transform them passing it, would that solve the problem. -CHG: Are you saying proposed solution 1 is what you would prefer? +KHG: Are you saying proposed solution 1 is what you would prefer? NRO: If you go back to the first slide --- If we modified this example by adding `init` together with `get` and `set` in the destructuring, and calling `init` inside the `init` hook exactly as we do for `set`. -CHG: right, so okay so that would actually work. However that was a hard constraint placed by implementers, that we could not capture the init function. If you could capture the init function you could maybe change the ordering. +KHG: right, so okay so that would actually work. However that was a hard constraint placed by implementers, that we could not capture the init function. If you could capture the init function you could maybe change the ordering. NRO: If that is something you could not do, my preference would be option 1. RPR: That is the end of the queue. -CHG: this is a late addition. So because this issue just came up last week, so, we can wait for consensus but I would like to wait for anyone and do we have consensus for normative change of proposal solution # and reverse order of initializers and treat it as a set? +KHG: this is a late addition. So because this issue just came up last week, so, we can wait for consensus but I would like to wait for anyone and do we have consensus for normative change of proposal solution # and reverse order of initializers and treat it as a set? RPR: Dan is on the queue. @@ -391,17 +391,17 @@ DE: Very weak support. I have not prepared for this topic so I don’t have stro WH: How do the two solutions behave in the case where you don’t want a setter and only want an initializer? -CHG: if all you wanted was an initializer and in this case, the minusTwo timesFour and that is it and the getter and setter just initialize the slot. And proposed solution 2, it would be times four and then minus two and that would be set and the values would be 18 and there would be no getter or setter that would access the private slot directly. +KHG: if all you wanted was an initializer and in this case, the minusTwo timesFour and that is it and the getter and setter just initialize the slot. And proposed solution 2, it would be times four and then minus two and that would be set and the values would be 18 and there would be no getter or setter that would access the private slot directly. WH: Just to make sure I understand this, one can initialize without running the setters? -CHG: In proposed solution 2. it does run the setters but the setters is just setting the value on the private slot. If we are adding the setters there, like back, if it is exact implementation as is here, then what we would have initial value of times 2 – then again you would update the implementation here to just have setters and remove the initializer entirely so if you set it to the same initial value, you would end up with the same result. +KHG: In proposed solution 2. it does run the setters but the setters is just setting the value on the private slot. If we are adding the setters there, like back, if it is exact implementation as is here, then what we would have initial value of times 2 – then again you would update the implementation here to just have setters and remove the initializer entirely so if you set it to the same initial value, you would end up with the same result. WH: This makes option 2 unpalatable to me, so I will go with option 1. RPR: So we have some opposition to solution 2. -CHG: I am happy to wait for consensus if no one wants to strongly support option 1. +KHG: I am happy to wait for consensus if no one wants to strongly support option 1. RPR: We have explicit support for solution 1. Any others? @@ -413,7 +413,7 @@ RPR: I will check because this was a late breaking item. So it is possible to ob WH: I support option 1 but I would like to ask the champion to come back to this topic in a future meeting and actually explain all the details including examples with setters and getters. I want to understand the consequences of option 1, but this does not block consensus. -CHG: okay that sounds good. So next meeting I can set that up. +KHG: okay that sounds good. So next meeting I can set that up. RPR: Chris will come back with a greater explanation of proposal of solution 1. So far no particular opposition. Thank you. @@ -421,7 +421,7 @@ NRO: To clarify we do not have consensus yet until the next meeting? WH: I am not withholding consensus — I support option 1. I’m just asking for a future full presentation out of curiosity. -CHG: okay. +KHG: okay. RPR: It seems that we are agreeing we should return before we stamp this as accepted, we will return to the next meeting? That is the course of action? @@ -429,11 +429,11 @@ JHD : So sounds like we have consensus, and Chris will hopefully will come back RPR: Okay thank you. So then we do have consensus on accepting solution 1. And but with the request to come back, and can you verbally dictate the conclusion? -CHG: so we have consensus to accept the proposal solution 1 which is to reverse the initializer order for field and accessors and treating them like a set to the value like we are updating the value. So the same order that setters went in. And we will make that change and I will return in the future meeting to discuss more thoroughly that change. +KHG: so we have consensus to accept the proposal solution 1 which is to reverse the initializer order for field and accessors and treating them like a set to the value like we are updating the value. So the same order that setters went in. And we will make that change and I will return in the future meeting to discuss more thoroughly that change. DE : In the summary a quick explanation of option two. And can someone dictate a summary if? -CHG: objection to option 2 it was more confusing it did not seem – technically did addressed the bug possibly introduced more because people would not understand that initializers run and setters run. It could be counterintuitive. +KHG: objection to option 2 it was more confusing it did not seem – technically did addressed the bug possibly introduced more because people would not understand that initializers run and setters run. It could be counterintuitive. WH: If you had only initializers you want the initializers to do the transformations. If you had only setters you want the setters to do the transformations. But with both, option 2 would run the transformations twice which would be really bad. @@ -451,64 +451,64 @@ WH: If you had only initializers you want the initializers to do the transformat ## Decorator Metadata for Stage 3 -Presenter: Chris Hewell Garrett (CHG) +Presenter: Kristen Hewell Garrett (KHG) - [proposal](https://github.com/pzuraq/ecma262/pull/10) - [slides](https://slides.com/pzuraq/decorator-metadata-for-stage-3) -CHG: Decorator metadata, last time we talked about the design, and we kind of came to consensus of the overall design. And we updated the spec and everything and so yeah we are proposing for stage 3. And so a refresher and why metadata is useful and there are a lot of cases that use it: *ORM’s and so we have meta-data and what type of columns are being – what types they are and constraints are and et cetera. And runs on type information, and routing type*`reflect.metadata` is the single most-used decorator library and so it has this valuable capability. +KHG: Decorator metadata, last time we talked about the design, and we kind of came to consensus of the overall design. And we updated the spec and everything and so yeah we are proposing for stage 3. And so a refresher and why metadata is useful and there are a lot of cases that use it: *ORM’s and so we have meta-data and what type of columns are being – what types they are and constraints are and et cetera. And runs on type information, and routing type*`reflect.metadata` is the single most-used decorator library and so it has this valuable capability. -CHG: How it used to work, a quick refresher: in legacy TypeScript decorator the class is the first parameter. So they could assign metadata to the class and add it to a WeakMap, and there is any number of ways they can key into that metadata. Decorators in the current proposal do not have this capability and they never receive the class so there is no way to do that publicly expose metadata and proposal is a shared metadata object and when we are decorating the class the decorators will receive this object on the context, and it is just a plain JavaScript object and we can use it to assign values and use it in a key in a weak map, and passes to all decorators and get assigned to `Symbol.metadata` on the class itself. +KHG: How it used to work, a quick refresher: in legacy TypeScript decorator the class is the first parameter. So they could assign metadata to the class and add it to a WeakMap, and there is any number of ways they can key into that metadata. Decorators in the current proposal do not have this capability and they never receive the class so there is no way to do that publicly expose metadata and proposal is a shared metadata object and when we are decorating the class the decorators will receive this object on the context, and it is just a plain JavaScript object and we can use it to assign values and use it in a key in a weak map, and passes to all decorators and get assigned to `Symbol.metadata` on the class itself. -CHG: So, yeah. I will say in review, just before the plenary there were some issues raised with the current spec and the first one was that some so decorators context object does inherent from parent class data object and this will lead to it eventually – something is inheriting and we want it to make a null – no okay, so it is inheriting from class from the `Symbol.metadata` from the simple class and that will come from the `Symbol.metadata` function and that cease like a bad thing if someone replaces that and people could inject metadata into everything and the proposed solution were to have it be define `Symbol.metadata` function to be non-configurable null, or we don’t inherit the superclass is function itself. +KHG: So, yeah. I will say in review, just before the plenary there were some issues raised with the current spec and the first one was that some so decorators context object does inherent from parent class data object and this will lead to it eventually – something is inheriting and we want it to make a null – no okay, so it is inheriting from class from the `Symbol.metadata` from the simple class and that will come from the `Symbol.metadata` function and that cease like a bad thing if someone replaces that and people could inject metadata into everything and the proposed solution were to have it be define `Symbol.metadata` function to be non-configurable null, or we don’t inherit the superclass is function itself. -CHG: The other issue that was brought up and the other one the spec currently just blanket assign `Symbol.metadata` for every class. And that was not my initial intention and I did intend for it to only be assigned on classes that are decorated and that was my review after the last implementation. So I would need to make that change. So happy to withhold stage 3 based on those. +KHG: The other issue that was brought up and the other one the spec currently just blanket assign `Symbol.metadata` for every class. And that was not my initial intention and I did intend for it to only be assigned on classes that are decorated and that was my review after the last implementation. So I would need to make that change. So happy to withhold stage 3 based on those. KG: It is important not to add metadata by classes by swapping out `Symbol.metadata` on Function.prototype. So for our solution to that problem, I don’t have a strong opinion about which way to go, and I lean towards making the get conditional. But the thing said in the presentation was not what was proposed in the issue. The thing said in the presentation was to the get if the superclass is function.prototype. But the proposed thing or at least I think the proposed thing was to only do – only make the metadata object be derived when the class itself is derived, which is syntax. You can syntatically extend function and you do want the get to occur in that case. I would say the metadata object is derived based on whether the syntax is derived. -CHG : One issue with that if we combine that with the other change where the only decorated classes get metadata assigned at all, um, then the idea is that if you have like class A which has metadata and class B which does not have metadata and class C has metadata, and so class C would inherit from class A metadata. And then up the chain of the prototype. So define it as non-configurable and not enable null, that is not an issue because that will be just be null. +KHG: One issue with that if we combine that with the other change where the only decorated classes get metadata assigned at all, um, then the idea is that if you have like class A which has metadata and class B which does not have metadata and class C has metadata, and so class C would inherit from class A metadata. And then up the chain of the prototype. So define it as non-configurable and not enable null, that is not an issue because that will be just be null. KG: That makes sense and in that case, I like that option. I would also want to make the get conditional even though it does not solve the problem. It just seems silly to do the get in the case of nonderived classes. But we should also have nonconfigurable nonwriteable null Symbol.metadata on Function.prototype. -CHG: That is an optimization we should put in there. +KHG: That is an optimization we should put in there. SYG: I zoned out why it is non-sufficient. -CHG: the idea is that say you have class A, class B which extends to class C which extends B, and class A has metadata, and class C has metadata and class B does not and intermediary class does not and update is that class D would not get a single metadata object and class C and its metadata would inherent from class A metadata directly and we would do that on doing a get about the superclass to get that property which is inherited, `Symbol.metadata`, and it would get the metadata object from class A. And then it would inherit from class A. So, you know if class A did not have metadata, it would then skip class A and get a function that prototype again. So you know, that case where we would need the prototype that could not be changed. +KHG: the idea is that say you have class A, class B which extends to class C which extends B, and class A has metadata, and class C has metadata and class B does not and intermediary class does not and update is that class D would not get a single metadata object and class C and its metadata would inherent from class A metadata directly and we would do that on doing a get about the superclass to get that property which is inherited, `Symbol.metadata`, and it would get the metadata object from class A. And then it would inherit from class A. So, you know if class A did not have metadata, it would then skip class A and get a function that prototype again. So you know, that case where we would need the prototype that could not be changed. SYG: I had understood that if it was tactically extending it would get the metadata, and if it was not extending, it would not get the metadata -CHG: even if it is syntactically extending it could still get the metadata on function of that prototype because it is going to get it in the superclass and it is going to call get and go through a normal process. +KHG: even if it is syntactically extending it could still get the metadata on function of that prototype because it is going to get it in the superclass and it is going to call get and go through a normal process. SYG: Oh yes, yes, I understand. Thank you. JHD: My queue item says only decorated classes that assigned metadata get the symbol, but it was pointed out in Matrix that that would violate previous implementer constraints here that the shape of the class would be determined based on syntax. But then that always means that classes that are currently decorated would suddenly start acquiring metadata as this feature gets shipped, and as we add new protocols we add them to the tree. And so maybe there is no other way to do it. It struck me as strange that everyone would get the burden of metadata even if an application is not using metadata at all for example. -CHG: So the constraints from implementers I think is more that we need to be able to tell the shape of the class from the syntax. Right? So if we added decoration to a class and that will result in always having `Symbol.metadata` then we can tell what the shape of the class would be from it is syntax and we can tell it get some of that metadata on the instance at that Point because there is a decorator. What they are opposed to is “maybe the decorator will create metadata, and maybe that will create Symbol.metadata, and so I think – +KHG: So the constraints from implementers I think is more that we need to be able to tell the shape of the class from the syntax. Right? So if we added decoration to a class and that will result in always having `Symbol.metadata` then we can tell what the shape of the class would be from it is syntax and we can tell it get some of that metadata on the instance at that Point because there is a decorator. What they are opposed to is “maybe the decorator will create metadata, and maybe that will create Symbol.metadata, and so I think – JHD: That is what my queue item proposed and the Matrix comment made me realize that would not work for that reason. To preserve the static shape, we would have to add another keyword like `accessor` syntactically for metadata. -CHG: We would also need to change the API as we agreed on previously because this metadata objects just exists, passed to the decorators. And if you don’t use it will still get defined on the `Symbol.metadata` and we previously talked about having admin.metadata which is a function and there was a security issue with that. And yeah, I do think this API is both intuitive and does tend to work. And I also not super concerned with the the cost of adding that because it is just one object on class definitions. And if it were like an objects on every single instance, I would just be concerned but they are just on the definitions themselves and typically, and unless you are dynamically defining classes, it is 0 tens of thousands. +KHG: We would also need to change the API as we agreed on previously because this metadata objects just exists, passed to the decorators. And if you don’t use it will still get defined on the `Symbol.metadata` and we previously talked about having admin.metadata which is a function and there was a security issue with that. And yeah, I do think this API is both intuitive and does tend to work. And I also not super concerned with the the cost of adding that because it is just one object on class definitions. And if it were like an objects on every single instance, I would just be concerned but they are just on the definitions themselves and typically, and unless you are dynamically defining classes, it is 0 tens of thousands. JHD: I have one other question then - the `Symbol.metadata` object on a decorated base class, what is its prototype? -CHG: The object inherits its prototype is superclass, oh on a base class? It would be `null`. +KHG: The object inherits its prototype is superclass, oh on a base class? It would be `null`. SYG: Backing up what Chris is saying: our requirement is that the object shape be determinable statically, and things that look declaratively will look declaratively with respect to shape, and adding to `Symbol.metadata` to classes that have decorators still meets that constraint. So I’m not excited about adding extra properties on every decorated class, but if it is just classes, in that instance like Chris was saying that would be okay. KG: We talked about a lot of stuff, and I want to recap, since it sounded like we were on the same page about a solution. Just to confirm: the idea is that there is no symbol.metadata property created on any class that does not have a decorator, and for any derived class that does have a decorator, during class creation the metadata property is looked up on the parent class and whatever value you get is used for the `Symbol.metadata` object for the derived class. And in addition, there will be a non-configurable and nonwritable null `Symbol.metadata` property on Function.prototype to avoid this problem where you have a base class without decorators and derived class with decorators. Is that an accurate summary? -CHG: Yes. +KHG: Yes. KG: I am happy with that state of things. It does require a couple of small tweaks to the spec text but I think we can do that readily. -CHG: only tricky part is getting like figuring out how to whether a decorator exist on that class and answering that question on the spec, and I should figure that out pretty quickly. +KHG: only tricky part is getting like figuring out how to whether a decorator exist on that class and answering that question on the spec, and I should figure that out pretty quickly. MHG: So consensus? Anyone? Does anyone oppose to consensus before changes or are we okay moving to stage 3 conditional on these changes? KG: I would be happier if we can come back tomorrow with spec text and ask for consensus then. I think it would be pretty straightforward. We have a little bit of extra time, it is only Tuesday, and I would be happier to have all of the boxes checked first. -CHG: cool okay that sounds good. And I will get it done by Thursday for the committee to review. Thanks everyone. +KHG: cool okay that sounds good. And I will get it done by Thursday for the committee to review. Thanks everyone. ### Summary of Key Points diff --git a/meetings/2023-05/may-18.md b/meetings/2023-05/may-18.md index 5f225ba7..9eda9de3 100644 --- a/meetings/2023-05/may-18.md +++ b/meetings/2023-05/may-18.md @@ -547,7 +547,7 @@ KG: That seems like a valid concern, if you are writing to metadata outside of a JRL: I don’t use decorator metadata or have any experience, maybe this is not something that ever comes up. -KG: Unfortunately, I don’t either. I am only presenting this because I asked CHG to write the spec text, which he did; we agreed on the semantics on Monday or Tuesday or wherever day. I can’t speak to it either way. I don’t know if there any people who have more thoughts on that topic. But this is the semantics we agreed on. +KG: Unfortunately, I don’t either. I am only presenting this because I asked KHG to write the spec text, which he did; we agreed on the semantics on Monday or Tuesday or wherever day. I can’t speak to it either way. I don’t know if there any people who have more thoughts on that topic. But this is the semantics we agreed on. RBN: First to clarify, which mutability concern are you discussing? Talking about mutability of making a change to the decorator after it’s been defined or talking about making a decorator trying to write a mutable property that might be a object – @@ -557,7 +557,7 @@ RBN: This is because the subclass does not have a own `Symbol.metadata` with its JRL: Correct. -RBN: I don’t know if CHG put thought into this. The purpose of metadata, the expectation is that mutations that occur to metadata after the fact are a bad idea. So I don’t really know that I have a perspective on what that really should be. I think that the expectation with metadata, at least in the libraries that use it today, is that even the reflecting metadata allows metadata to be mutated after the fact so there is the possibility, although it hasn’t come up in practice. And it’s always possible to have a class that might be concerned about mutations to have a class decorator that freezes its metadata before it’s written to the class as well. +RBN: I don’t know if KHG put thought into this. The purpose of metadata, the expectation is that mutations that occur to metadata after the fact are a bad idea. So I don’t really know that I have a perspective on what that really should be. I think that the expectation with metadata, at least in the libraries that use it today, is that even the reflecting metadata allows metadata to be mutated after the fact so there is the possibility, although it hasn’t come up in practice. And it’s always possible to have a class that might be concerned about mutations to have a class decorator that freezes its metadata before it’s written to the class as well. JRL: Okay. I don’t have the experience to say whether or not this happens. If RBN who has extensive experience with decorators, shouldn’t have any experience writing after the fact, then that’s totally fine.