Attendees:
- Shu-yu Guo (SYG)
- Kevin Gibbons (KG)
- Kristen Hewell Garrett (KHG)
- Philip Chimento (PFC)
- Ron Buckton (RBN)
- Chengzhong Wu (CZW)
- Richard Gibson (RGN)
- Justin Fagnani (JFI)
(Note that below is a Google Meet transcription, not hand-written notes.)
SYG: All right, let's get started.
KHG: Sounds good. Cool. So today we're talking about the decorator metadata proposal. So for anyone who's not aware when decorators advanced to stage three, we broke out a part of the proposal, that was a little bit more controversial, into a separate proposal. That is currently at Stage 2 and that was the metadata portion of decorators
KHG: So yeah. let's, Quickly review what metadata is for? So use cases for metadata include things like dependency injection or MS. Runtime type information, serialization and marshalling unit, testing routing, debugging and membranes. And they're also more. This is not an exhaustive list. These are just some of the larger more commonly used, use cases reflect that metadata is also the single most used decorator library with over 5 million monthly downloads currently, which suggests that the users find the pattern valuable
KHG: So, how to decorators used to add metadata in the legacy pre-stage three proposals. Well, in those proposals decorators could do it because every decorator received the class itself. So it was it simply a matter of creating like a weak map or something or potentially, just adding it directly on to the class and then exposing that via your library. So here we have an ad metadata Decorator it receives a value, It then returns a decorator, which gets applied to a class and we use the class itself as a key into our weak map, to store that metadata. And later on, we can access that by using the class as the key in the week.
KHG: There were obviously some limitations, for instance, you couldn't add anything for private elements but private elements also weren't decoratable in the previous versions. And this doesn't work anymore because elements class elements no longer receive the class. They have no access to the class definition. At all. So there is no way for instance, for this ad meta pub to X, that that wouldn't be possible with today's proposal as it stands. So, that's that's kind of the gap that this proposal is trying to solve. So, the current proposal extracted directly from the Stage three prior to stage, three proposal for decorators.
00:05:00
KHG: Is basically based on this idea, of get metadata and set metadata, which are two functions that are passed into the decorator on the context object. So each decorator receives, the value that is being decorated as the first argument. And then a context object with a variety of context, contextual information as the second argument. And these would be two functions that would allow you to set metadata or get the metadata set by a previous decorator.
KHG: So, basically, users could use this and based on what you were decorating, we would expose that value on the class itself on simple.meta data. So this is an example of how you would for instance access class metadata public element metadata, and private element metadata on that object. Um, the set metadata. Like function takes as its first argument a symbol and the reason for that was so that every user would be able to distinguish their metadata from other decorators metadata pretty easily. And then we have this set up where each metadata
KHG: Type of metadata has its own key on the object. That is a put on. The metadata. Symbol. So for instance, own is class metadata public is public element metadata, which is a, you know, key value mapping. It's just a plain object, but it has the keys being the name of the, the elements, and the values, being the metadata that was saved with the element and then private is an array. And the reason for that is private elements don't really have a name per se and not in the same way that public elements do. Um, it's also you know worthy that this is inherited. So the prototype of the object is the
KHG: Points to the same metadata object on the parent. And that's why we have for instance public metadata. With I like public dot X here, X could shadow, its parent classes, metadata naturally, again with private elements, you can't really shadow, so it's not really an issue. So this is definitely a complex proposal as part of the reason why there was a lot of pushback against it. So let's talk about some of the alternatives. so, Yeah, the first one. Is a simpler metadata object. So rather than, you know, having this whole set up where we have own metadata public metadata private metadata and it's all set on, you know, divided by a metadata key. So that we are mixing metadata and so on and so forth.
KHG: We could just toss it all into an array or, you know, there are. We could also bike shed on that specifically. But I think the simplest version of this proposal is that you add metadata and that just gets added to an array and that's entirely additive This basically leaves all that inheritance stuff and the student distinguishing metadata from other decorators stuff up to the user. And what I think we would see with this solution is a lot of metadata users in the ecosystem, basically rebuilding a lot of this. on their own, but that said not every user needs the complexity of
KHG: The full private public. Separation, etc. So maybe that's a better way to go.
KHG: Alternative to is a shared key object. So this has been proposed by a few people. Basically, the idea is that we would pass in a value on the context object, it would be like a frozen object of some kind. And you would use that as a key into a weak map, it's kind of replacing the previous pattern, we had where you would use the class itself as a weak map. This would be a shared reference as a week map key brother. This would be a shared reference to an object that every decorator would get on a class and then you would be able to use that to access the weak map via simple. Dot metadata on the class. So we would assign that object to Symbol.meta data after the class has been defined. so,
00:10:00
KHG: like I said, this is the most similar to the previous paper and probably would be the most straightforward for the existing ecosystem to adopt. So yeah that's any questions so far. Any any clarifications or anything?
KHG: Okay, cool. So then we have a kind of variation of that alternative, which some folks have suggested as well, where we would
KHG: Basically do the same thing pass that object around, but we would not expose it via Symbol.meta data. Some folks were hesitant to add a new global symbol and apply that to classes. So, in this case, you would basically have to have a separate decorator that would expose the metadata, which would be applied at the class level. So you would like add metadata to this context object, and then you'd have this decorator, take that context object and Expose it either like it could set it on a symbol or it could, you know, set it via weak map. Lots of options there.
KHG: Okay, then there's this alternative three. Which is based on the ad initializer functionality that decorators have so decorators can add initializers, that run to initialize the class and when the initializer runs, depends on what you're decorating. Currently, if you're decorating, an instance, element, you are.
KHG: That that decorator will run or that, that initializer rather will run whenever the classes instantiated, and it will run on the instance of the class. If you're decorating aesthetic element, however, it will run a Basically prior to class fields, being assigned, static class fields, but it runs once it runs with the class definition and it has access to the class definition. So what we would do here is we would allow any decorator to choose the placement of what's of when the initializer runs. And so any decorator would be able to say I want this initializer to run as a static initializer and that would run once when the class is defined and thus it could add metadata To the class.
KHG: Similar to the existing patterns where we would set use the class as a key in a weak map. This. Importantly. Is a not, it doesn't allow users to do things like redefine class fields. So this couldn't
KHG: do bad things that we previously that it couldn't subvert. The reason why we got rid of class, definitions being passed to every decorator. At least in that sense. It's it's not like it can fundamentally change the shape of the class.
KHG: it in a lot of ways and I guess it can in some ways it could add,…
SYG: where, I'm a little bit confused about that.
KHG: it's but,
SYG: It's The decorator itself cannot but if the static initializer receives its class definition, why can't the static initialize but it so it's the static initializer can? It's just the decorate yourself.
KHG: Yes, I guess what I'm gonna say there is that the common patterns that we were worried about were mostly like users,…
SYG: Okay.
KHG: installing getters, and setters, for instance, for class fields and because class fields can't be redefined and can't be moved. They're just gonna overwrite those getters and setters. So I users could add method if they wanted to, but there's not really a reason to do that. That's not a pattern. We've observed very often. So I think the most dangerous types of shape changes that we, we were worried about. I couldn't happen, but yes, you are. You're correct. Shape changes can happen, dynamically? um, Okay, and I had something there, I don't know.
KHG: Alternative for is Do nothing. So some folks have also suggested that we don't actually need metadata and that users can basically figure it out themselves with the current proposal and this is kind of what that looks like. Essentially what we would have to do is create entangled decorators where where we would use closure state to share the metadata between them and then expose that metadata. so here we define a function that makes two decorators, that can share metadata between each other, and then one of them exposes that metadata publicly This has been a really not received well by users of metadata.
00:15:00
KHG: They have argued that this makes it much more difficult to do the patterns that they use. It means that users have to remember to not reuse a decorator, only use it once per class, it makes things very stateful. When defining a class in the whole point of decoration is to not be STATEFULS to be declared if it's to be, you know, not. Yeah, so that's this is definitely not preferable for users of metadata as the feedback we got but I felt like I had to bring it up because some folks have suggested that it could work. So yeah, that's pretty much. Everything. Are there any questions or any clarifications needed?
SYG: Thanks for presenting the recap. I guess my main question to you Chris. So you and the Champion group out of the four alternatives I guess four and a half counting two. What is the champion group's preferred alternative currently.
KHG: um, I personally would Like the either, the first one where we just have ad metadata and we just shut the metadata into an array. There are definitely techniques you can use to Hide metadata that way. Like you can use passing an object that you use as a weak map key, and there should be enough context there for you to basically do anything you need to do. And I think it's very easy for users to understand, right? Like you just call out metadata and it will add it to the array.
KHG: I would prefer that or I would prefer the ad initializer approach where we would. Allow Users to Pass in Static as a Placement. The reason I like that one is it just builds on the existing mental model that we already have for initializers and makes them slightly more powerful. So it's not a whole additional concept for users to have to learn um it does have the issue of potentially like allowing dynamic shape changes though so that that is a yeah Ron you want to talk
RBN: Yeah, I just wanted to point out that the dynamic shape changes you exists with or without the Add initializer.
RBN: So you can already add initializers, just changes that a public field on an instance could theoretically also add a static initializer. I will also say that the one issue with the at initializer approach is that metadata would not be available to other decorators of the same element.
RBN: Three or the first two alternatives, made that feasible that you could access some of this information from the metadata context object or through the methods available. But at initializer since that runs during static initial agent initialization, it's too late for decorators to also be able to read that metadata and, During normal decorator evaluation, they would also have to write at initializers and then everything becomes deferred which is a downside. It does have the upside of it requires the least amount of changes to the spec to make it work.
RBN: Some existing libraries, like reflect metadata metadata or some variant thereof could be could be written to support it. But also to use metadata in that way does require a third party library of some sort to convert the AT initializer approach into something that is really roughly reusable.
KHG: I will note also that the ad initializer approach,…
RBN: Yeah.
KHG: the Alternative one is a It may not work. If all we do is have AD metadata and that just puts them metadata in the array, The whole point of the get and set metadata was the idea that you could get the metadata from the previous decorator. So we may need to add, We may need to have this, be slightly more thought out. So maybe maybe you can call like get metadata to potentially or something like that.
00:20:00
KHG: Yeah.
KG: So my biggest concern with this is just that it's very shared like it's true that just a basic usage where you're just shoving things into an array. If the array is not exposed, then the different decorators are definitely not competing with each other. but as soon as you try to use it, now that kind of are like,
KG: if a, if your library is like trying to expose something, then it could do the thing that I would hope libraries would do where it would expose a function that like, takes this array and filters it down to the library's own metadata and gives you that or whatever. But it could also just say, Well, just walk through the array and find the thing that like has type, you know, fancy or whatever, or it could even say, Well, I assume you're the might it decorators, the only decorator you're using that. Certainly, the easiest thing to document and then you just say like Look at, you know, symbol metadata property zero. And as long as my decorator is the only decorator you're using that works fine. And as soon as that's not, now you have a much harder coordination problem.
KHG: Right. so, I do think
KHG: So, I do think that with approach one we can we we can kind of build something in between. Also, like the whole idea of the requiring, a symbol was set metadata in in the initial proposal was specifically to avoid that case, right? Like you, you don't miss any have to expose the symbol and it would allow users to really quickly access their metadata. So maybe we just do that and then it's an array on that symbol that is simpler than the whole like own public private inheritance, all of that stuff still, but it does solve that problem. So that that could be an option as well.
JFI: Um, sorry, I joined in here a little late. Um, as someone writing decorators here, like I, when I saw the alternative to proposal, it really clicked for me, that it was like, As simple as possible. But still gets the job done for the decorators. I need to write because basically Everything our decorators do have some kind of map that is in hanging off the class. Anyway, so it basically acts as something that would be keyed off of a Um class unique key like this and I feel like it with the arrays approach. I would probably just build an API like this on top of it. Right. That I would probably stick a symbol in the array. Which would roughly be the same as the symbol sitting on simple.meta for the class and then I would use that to look up something in a weak map, that was private to the decorator. Implementations or the several decorator implementations collaborating.
KHG: Yeah.
JFI: so, I don't know that this seems
KHG: The.
JFI: Build the array API on top of this but just kind of isolated, right? Like any set of decorators or public APIs that need to collaborate could have a generic array. Exposing a public API that is keyed off of this metadata object like whatever API you want to build. I feel like you can build on this. API here.
KHG: Yeah. Also I think it's noting that in this one we don't have the issue of like decorators would be able to communicate with each other as their decorating via the context object because it it just would be an object that everybody can access and use this a key. So so that issue wouldn't be, that would be a capability. Kevin
KG: um yeah, so another thing that is possible with this, which I guess isn't hasn't really come up with any of these is whether we want to make it easy to get metadata for The Parent class. When I I wrote a sketch of this in an issue and I just assumed that was a thing that we wanted. I didn't even really think about it. I just like assumed that was definitely a requirement. And so I had this like Put a parent property on this object so that you can walk up the Yeah inheritance chain. And of course that gets tricky. If you're using the return override trick or your dynamically changing the inheritance chain, but on the other hand, so does everything if you are doing those sorts of things. So
00:25:00
JFI: It would be interesting. Oh.
KG: I guess this is more of a question if like this is something we actually think we want because if if we do want this then some designs make it easier than others.
JFI: It would be interesting to see which cases you need to access parent. Metadata on. I don't have many myself, but I think the ones I have seen all our cases, where the parent classes also decorated Right. And if the parent classes,
KG: Well, you don't there's no metadata if you don't decorate the pairing class. So
KHG: Right.
JFI: Right. But so then it's like Can you can you build that on top of this if each class? Only has a key that's not linked to the parent, right? In which case the decorators on the parent can use the parent classes key, In stash things. I guess. You need to child parent relationship. Yeah. So Yeah.
KG: Right, that's it. Exactly that. You don't the child's decorators, don't know what the parent class is. And so they can't do things that are based on its metadata.
JFI: Right. But I guess they, they do have they do at runtime, right? Like, after decoration time. So right,…
KHG: Right.
JFI: like you could walk to the parent prototype, get its key and look things up. Right.
KHG: So most today, most uses of metadata are inherently lazy. It is very rare to like change decoration during decorations. It's more that you add the metadata and then something later on comes and reads the metadata and does something with that. And so that's the time where you generally handle inheritance and solve it. Usually, but this, this would enable people to To do that if we added that parent and I do think that might be valuable. I also just don't think I haven't seen abuses of that. That are Odd. I haven't seen, you know, patterns that I like Anti-patterns that, I would want to prevent there. So I I'd be okay with adding it. I'm I don't have to be honest.
JFI: I mean. How would that work with a dynamic heritage? expression, I mean, what our decorators
JFI: Decorators would be evaluated like, for mix-ins, decadworders would be evaluated at like mixing application time, right? So there would be a concrete super class at that time.
KG: The heritage expression is evaluated before decorators themselves are expert.
JFI: Before the decorators. Okay.
KG: Yeah. So you can you can just read off the Symbol.meta data property of the parent. Like the runtime,…
JFI: I mean.
KG: runtime can read that off so that it can construct the subject.
JFI: right, I mean, one nice thing about this is it does seem like, you know, adding the parent Property. To the metadata object should be fully backwards compatible. So that could come as a follow on.
KHG: And as long as the object is frozen. Yeah, I think that would be true.
KHG: Shu.
SYG: So zooming out a bit, I between one. And so the speaking, as an implementer with my implementer hat on which like, if I'm ignoring actual use cases, in terms of simplicity, and, The foot gun argument of like how much do we want to encourage folks to write or use decorators, that may change class shape to make it less declarative? Alternatives one or two seem preferred to me in terms of simplicity I think they're like alternative to is marginally more complex. I don't think it really matters in a in a material way like you have to create this frozen. Objects, sure, whatever. That seems fine.
SYG: So, I want to hear. I don't also don't have really have an opinion right now between two, and two way I suppose if it's possible to not added global symbol, that would be nice but I don't really have any thoughts deeper than that, but I want to hear from you.
KHG: If?
SYG: Chris that you would socially did not list too in the preferred approach of the champion group. It was one or three. Could you say more about? Why you did not prefer to?
KHG: Yeah for what it's worth two. A is kind of similar to four in terms of like impact to usability. And I think most users of metadata would not prefer to a but so, for two, it's that Sorry.
JFI: Alright, I I would like to hear more about that actually as a decorator author. I don't quite see that but okay.
KHG: Sure. I think it's mainly just about having to add an additional class level decorator, which not every library uses. That's what the difference between.
00:30:00
JFI: Oh, sorry. I was assuming a was the first one to be was Okay,…
SYG: You.
JFI: okay, sorry, yes, yeah, okay, I agree. Sorry.
KHG: Yeah, okay, so for alternative to the reason I don't like it as much is, it's harder for decorator, authors to understand like I still meet JavaScript users who don't understand what we maps are for, and like, forcing people to, like understand those details can can be a little bit. Especially with like you have like this frozen object. I think it would actually be better if we could use symbols this week map keys because then people would understand, Oh, it's a symbol that I can use as a key. That's, that's rockable
SYG: We're we have that now right? We have symbols this week map,…
KHG: Do that finally went through.
SYG: please. Now. Yeah. Stage 3.
KHG: Okay, never mind.
SYG: We're implementing it anyway. Okay, seems we have a long queue now. So I'll wrap up with,…
KHG: Yeah.
SYG: with, as an implementer at the risk of sounding callus. If the risk is that we we favor, we disfavor decorator authors. I'm okay with that trade for simplicity. Okay,…
KHG: I, yeah, same
SYG: let's get to Let's get to the queue Ron Buckton first.
RBN: Yeah, I wanted to clarify something on the alternative to that we're showing here. One of the discussions I had at one point. Was that the Context metadata. And so, it's not, I guess I should clarify, it's not listed as one of the alternatives. But one was that the metadata object is something that you could just assign properties to that, it would be then frozen at the end of decorator application, and stored on classes symbol.meta.
RBN: And it could also be used as a weak map key. And one of the reasons for this is that there are use cases for publicly accessible metadata that don't necessarily require going through an API one of those some typescripts compiler in its legacy decorator emits supports emitting runtime type information metadata for use with decorators because typescript can run as in a script context as well as a much or the typescript code can run any script context as well as a module context, we can't necessarily depend on importing a library to store and read metadata from. So it becomes a little bit trickier for a compiler that has to run any script context that can't depend on external modules to leverage a function to make it. Make such metadata reachable by any library, or API that wants to reach it.
RBN: and without a lot of strange hoisting and having to store something in a global scope and that global then has to be patchable, which might be not permitted in something like an SES environment. So it one of the reasons that I was kind of in favor of having a mutable metadata object was, was to support that kind of scenario.
KHG: And just a quick addition there is that that's not just a typescript's capability. For instance, there are validation libraries where people add type information in JavaScript because they find that valuable to have the type information but they don't want to go all in on typescript and that metadata could definitely be publicly accessible and usable and in a similar way.
RBN: Yeah, and then we list of use cases, for metadata. One of them, was one of the ones that was listed was Orms and many of the orms like Type O, R M micro ORM that currently supports the typescript Legacy metadata. They leverage typescript decorator emit or can leverage typescripts metadata met rather for decorators to get the type of information. So if I say that this field is A is a number in the type system, the type compiler will write a metadata entry that says that the type of this was number with a capital and so that the ORM system can then look at that and say Okay this is the type, I should apply to the column whenever I'm generating. Database Table.
RBN: So it's having access to that so that the ORM can then access the compiler. Generated rtti or the user-defined rtti is extremely valuable. And that it's really hard to do again from a compiler. If without some mechanism for writing public metadata
KHG: Okay, I think Kevin is up next.
KG: Sure, I have three things, which I've probably forgotten two of them by now but let's see. So the first is in response to Ron, we were going back and forth on that thread on the decorator metadata. Issue Tracker and I still didn't really understand you made the same point there and I still didn't really understand that. So the thing that makes typescript unusual here. That it can't. So, for most libraries that want to have metadata that they expose to other people, they can just expose an API. But as you say typescript can't do that because typescript can't rely on users being able to import an additional API to call to get access to the metadata which is
00:35:00
KG: A property that typescript uniquely has on any other library, you can people can just import things. On the other hand typescript is in a position to just rewrite, the other decorators. So, I didn't understand what didn't work about. Just free writing the other decorators to pass the metadata you want.
RBN: I'm not sure what you mean by rewrite,…
RBN: the other decorators.
KG: So, I have an example in the issue.
JFI: There might not be any decorators.
KG: The thing that I mean is so you you're talking specifically about exposing information to the other decorators and the thing that you could do is you can transform the decorators. So it's like at Foo you can make it instead like at ad metadata to the context object before calling Foo.
KG: And that seems like that works. Fine.
KHG: So it I don't think it's about exposing the metadata to other decorators. It's about exposing the metadata publicly in general. Yeah.
JFI: In general.
RBN: Which issue number was this? It's been a while…
KG: Issue number five,…
RBN: since look at it.
KG: issue number five on the proposal. Decorator, the data here.
RBN: Thank you.
KG: I'll drop it in chat.
KG: Anyway.
KHG: If?
KG: I had other points. Oh, one of them was just Chris to your point about people not understanding weedmaps. I agree that's true. On the other hand, you only need to understand them if you're writing a decorator and not. If you're just using a library that Uses them and like people aren't going to understand how to write decorators either and that's like fine. It's it's a like the people providing decorators are can be assumed to know more about what they're doing in general.
KHG: Yeah, that has been that has been a design principle for decorators and my preference. There is very light like all three of the main alternatives. Here to me are fine. So yeah.
KG: And then I forget my method point was so I'll see the Q.
KHG: okay, Justin
JFI: Okay, yeah. I mean I just wanted to kind of comment on the Simplicity and ease of understanding from decorator implementer side. It's a personal opinion but I find two alternative to much easier to understand. Actually generally our decorators that do involve metadata right now are putting it hanging it off a property off of the off of the class. And so all we would have to do to update our decorators is swap out. This In our static methods with this bracket Symbol.ed metadata and a weak map.
SYG: For the for the broader group, you're talking about Lit, the framework.
JFI: Lit. Yes. And that's the primary place. We've used decorators. And, you know, we're one of the few, I guess, right now, that does this all at runtime, I guess. Mobex also. Right. We don't have a compiler.
KHG: Ember. Ember too,…
JFI: So yeah, like huh? Okay, that's an intercom compiled.
KHG: and Our (??).
JFI: Awesome. Yes, so um Yeah alternative to. This is very very straightforward to me, right? Like instead of accessing a static property, you Access the static property and use it as a key to map. It just seems way less roundabout to me than alternative one where you basically try to emulate that same setup by filtering the array. So I don't I don't actually think in my opinion too, is more complex, I think it's less complex, it's the easiest you can see how we would use it. To me.
KHG: Yeah, that's fair.
SYG: Okay. Ah Q is empty. I think from implementation point of influential point of view I'm okay with I'm certainly, okay, with two, I haven't given much thought about Ron's point on whether context that metadata should be immutable object to start and then frozen, I don't know when I guess after decoration is finished. Like, all decorations finished, was that the proposal?
RBN: Potentially. Yes, I'm going back through. Kevin's comments on 85 and I'm trying to find it determine if there's a way to make that feasible because my biggest concern would be finding a way to expose metadata publicly.
00:40:00
RBN: and, I think the easiest if that were possible would be to do because we would not have if we went with option, two or alternative to we wouldn't have the ability to add static initializers when working with an instance field, but I could, as a compiler inject, a class constructor that has a Class initializer, that could.
RBN: Potentially. Trap the context of metadata object and then use it. But then I think I also end up having to inject a weak map, if that context object is frozen at start. And then, How do I attach public metadata to that week map? I think there's potentially ways of making it work. So I think alternative to could still work with the downside of
RBN: and just additional injection that we'd have to do, but As an as a sorry,…
JFI: Run if metadata. If metadata was immutable object,…
RBN: go ahead.
JFI: how would you hang the typescript metadata off of it? Which is magic strings because you wouldn't have a spot to put a symbol There, if you can't add a global right?
RBN: yeah, if the metadata object is immutable, we'd have to inject some other property and that just becomes another problem that we'd have to solve,…
JFI: I'm saying…
RBN: we either have to create
JFI: if if it is mutable, what keys on that object with the compiler used to inject the type metadat
RBN: most likely a either a key, the assemble.4 or just a string named key that is Relatively unique like the typescript right now, when it emits a decorator metadata using reflective metadata even though that uses a weak map. Because reflective metadata reflect metadata is a shared set of data that everybody has access to. It's still essentially a like a string-based key. and, Open up a copy of the compiler to.
JFI: Right.
RBN: picking up one second, but basically,
KHG: Here.
RBN: when we object emit that, we just administering key today, that is like
JFI: Yeah, it's like TS colon something or I can't remember. It's
RBN: I'm looking for it right now.
KHG: If?
RBN: It's basically I know we admit design colon type as the name of the key and then we've just been using the same thing consistently. And it also means that anybody could emit a design colon type that referenced that matches that and be able to work even if they're not using the typescript compiler. And we're not having to leverage Symbol.4 because our the legacy decorators, we had supported everything down to es5. If you're running in an environment that supports weak maps like a pre-standardized week map would still be perfectly viable to be able to use decorator metadata and Turkey S5. So, we didn't have a dependency on using symbols.
KG: So, I should say. the reason I wanted this to be frozen is just so it's not another shared namespace where, like, Everyone's decorators are contending over the string named keys of this property. So that like, if you know, Alice's fancy library has a like renderer metadata property that she sticks on there. And Bob also has a renderer metadata like string named property that he sticks on there. Like you can't use their libraries together and that's annoying. It's not the end of the world. I just would prefer to avoid making new string named namespaces when possible. and,
KG: If? yeah, like I said, I'm not Dead set against it. I just really would prefer not to. So, To go in this direction. I would want to. I would want to talk more about whether there is An alternative. And like, I would want the costs of the alternatives to be pretty high before. I thought that cost would outweigh the cost of having more string named namespaces. Now, for typescript, in particular, typescript is kind of in a unique privilege position and typescript adding string named properties. I am fine with. But the thing I am worried about is like other people, basically trying to do the same thing.
KHG: I think it's worth mentioning though that the same logic we had about, like, not everybody's gonna write a decorator and not everybody has to understand these details. Kind of also applies here, right? Like if not everybody is going to Use these things then probably majority of people who do will have enough expertise to understand that they shouldn't just use a random string name. They shouldn't do that. Like, you know, very basic anti-patterns.
00:45:00
KG: And I don't know about that. I would be Very little surprised…
JFI: Right.
KG: if like it ends up. Like if we do this, if we make this immutable namespace that like one ORM library puts an ORM property there and then everyone else is just direct. Like there's no other or…
JFI: Well. But it requires it requires two bad actors to have this problem,…
KG: I'm property that gets to do that.
JFI: right? So as long as you're able to like, if you are doing the right pattern yourself as long as that protects you against other people being sloppy, then it's okay. So if you can still use this object as a weak map key, And say, I don't want to be subject to the whims of other people's, you know, metadata names choices, and you should be fine, right?
KG: Well, so…
KHG: Or use.
KG: what I am imagining is suppose there are two or on libraries and one of them is like Ah I will just make a ORM property on the metadata object and the other one is like I will be a good citizen. I will stick this in a week map, it'll be no possible. Contention the second one ends up being more awkward to use. and like even if they're like, all right, I will
JFI: But why would it be more awkward to use?
KG: Because for it's only a little bit. But like, for other time, decorators to access that metadata they form the first library, they just read the orem property, the same way they read that design colon TS property or whatever, as opposed to importing a librarian calling.
JFI: Right.
KG: That now the second thing is only marginally more complicated, which is why I think it's an acceptable alternative to force everyone to do it that pattern but it is marginally more complicated and the use of the like ORN string makes it kind of like it's kind of claims by the first library. And yes it's true. They're not like contending because the second one has been a good citizen but like The first one ends up seeming more official and blessed and like, that seems bad. This is like an inherent problem with having namespaces is that they get claimed.
JFI: Right. yeah, I mean As in author of decorators here,…
KHG: If?
JFI: mine don't like really collaborate with their party decorators and I'm like basically can I make sure that my behaves? Well their API is only the decorator themselves, so I'm not kind of concerned about External things, but I see that point, although it does raise a thing for me. And something we've been dealing with a lot with our libraries. So our our library is also fairly unique in that. We only publish JavaScript modules. You don't publish any kind of umd, common JS or anything and in the places where we have relied on module level variables to share state between things. Sometimes we have gotten into a problem because NPMS
JFI: You know, proclivity to duplicate modules in your node modules graph, right? And so you get different shared state objects and so if somebody somehow gets an import like decorators coming from one version to lit in the base class, coming from another or something like that, then you get a problem and the way out of that is to, instead of using module level caches is to have some well-known, global variable, and stick your caches on the global. And that solves big user problems where they're like, you know, you know you need to run npmd, do you know, and oh, you have some library that's forcing an old version here and you need to fix that and people do not want to do with that. So like using global variable names or namespaces or something actually is in many cases gonna be a best practice to protect against NPM. even with this opaque, Metadata key.
KG: Going to Dispute Best Practice. I agree with you that it solves a problem. On the other hand, there is a very good reason that MPM works that way and like we have a global namespace. It's the global you can use it if you really want to, but you should understand that. That's what you're doing. And there's a reason that like you don't and that it's it's because it's a shame space, but like, if that's the thing you want, that's a one we already have.
JFI: Yeah. So, I mean I wonder…
SYG: All right.
JFI: if it would be interesting to have something like some kind of metadata thing that acts as a map. That only takes symbols and skis. Right? And then you're like, encourage people to use just you know the symbol function but if they really really want to have it shared across Module scripts, whatever. They can use simple.4.
SYG: so wait, let me It's the reason context that metadata is a frozen object.
KHG: Four.
SYG: Only. Because at the time we didn't have Symbolsis, we've met keys.
KHG: The other reason would be if we do want to have the inheritance, if we want to have a parent property or just use are the typical inheritance,…
SYG: Nicely.
KHG: then that would be,…
SYG: I say.
KHG: but but I think it's also debatable whether we need that capability or not.
00:50:00
JFI: But but it's not just symbols as weak map keys, right? Because immutable metadata object like in in the case Ron's talking about like allows for purposeful sharing. of the
SYG: Well, then I'm talking about the That the thing on this slide…
KG: Yes.
SYG: which is especially a frozen object, that's frozen from the start. Like, why was that Kevin's?
JFI: Okay.
SYG: Designed from the beginning. Was it? Just because of symbols but now I guess. Yeah. If you were thinking about because you did say in the beginning, Kevin that you you assume that like the the heritage is something that we would want.
KG: Yes, yes.
KHG: If we don't want it though, I do think a symbol would make more sense than frozen object.
SYG: Okay, so
KG: Right. So why?
RBN: I'd also like to.
KHG: Because you can do everything else with it like use it as a weak map, key and everything. If we don't want evidence…
KG: but, What advantage does a simple have over a frozen object?
KHG: then it
KHG: Conceptually. It's just a little bit. like, this is meant to be a key versus
KG: Oh, okay. I guess I don't have that conceptually
JFI: You could also use it as a key and plain objects.
SYG: Run.
RBN: Yeah, I wanted to talk about that the parents. Thing for prototype change as well. I'm kind of there's, two ways to look at it One is that if we're if we care about the parents of a class
RBN: based on what it was at the time, the class was declared and not based on what it actually is due to dynamic prototype. a patching or
RBN: A super return override capabilities. We could put the parent information on the context object rather than the metadata object.
KHG: If?
RBN: That I not sure…
KG: The whole chain.
RBN: where that ended up but I did have a proposal for a comment on the proposal trackers about it could be valuable to actually have a this information about the
RBN: The. Super class for a class even if it is a very limited set of information. Like maybe it's just the class name and
RBN: the context object from that superclass rather than the actual superclass constructor. If there was concerned there, Or it's also a good place to attach other information. We might want to eventually have for decorator context so we could possibly put this some other than on the context dot metadata object and or value and then that could be a symbol rather than being an object and then be perfectly acceptable. I think to me
KG: If you are just exposing the parent name and parent contexts. How do you get the Grandparent class? I guess. The context object, you could look up the same property on the Context object. Okay.
RBN: And the parent context would be essentially a lightweight reference to whatever the context was at the time. The other class was defined, the problem is that it doesn't mean something that has to be stored on the class declaration. So it's just additional It's an additional property with additional memory overhead. That is a per classic declaration cost, if it's dynamic prototyping or prototype chaining if we want to do dynamic lookup of prototype chains, then none of this matters because it has to be done all the runtime and we wouldn't have the parent anyways.
KHG: so in that, with that, in that regard, we have Typically said like any changes to the prototype like If you're gonna do dynamic prototype changes so far in the design process we've said that that's now your responsibility to then handle other dynamic changes as well like changes the metadata inheritance and stuff like that. I we can definitely reach that design decision. That was just something we used to like simplify earlier on especially when we were doing like all the inheritance stuff, but I feel like that's a reasonable thing to do. Like dynamic inheritance is already a really tricky thing and if you're doing it like and you care about metadata, then you should handle the metadata case.
RBN: I'm going to post the issue.
SYG: all right, so last
RBN: I was talking about in chat, it's not the same one because it talks about a Nesta decorator referencing. It's having some limited information about the class, but we can also consider the same thing for a class setting it. Limited information about it superclass, but
SYG: So for the last two minutes, I want to wrap up here. I think that the big question I wanted this. answer which my reading up the room is that folks are We all can live with two. So, I take that as the main takeaway from from this call. Is that the to get this to get metadata back to stage? Three, two, seems like the most promising approach in this room by judging by opinions.
00:55:00
KG: With perhaps an open question of whether it's frozen and whether it's there's a symbol or…
SYG: Right. The
KG: a parent property or there's details there.
SYG: Right? Those are the sub detail.
JFI: Yeah, but also the The current state is unique in that it allows forward progression like a frozen object allows us adding the parent property or…
SYG: Yeah, go ahead.
JFI: making it unfrozen later. So it's very flexible I think as well.
SYG: and then,
SYG: Yeah. Okay no I think that was it. So I'm happy with with more iteration on two. I think the remaining I was hoping Yule would be here since Mozilla also expressed complexity concerns about the previous design. So be good to double check with with her that that alternative two is also acceptable to them. but otherwise, yeah, looking forward to I don't know, I don't personally care too much about the details of happy to let Kevin and Ron, and, and Chris, and them figured that out. And then you're looking forward to getting this represented. In plenary.
KHG: Awesome. Do you know what? The best way to contact you Leah. Is a, yeah.
SYG: Um, I would try her Mozilla email. I know that Mozilla Uses matrix as well for themselves. So she's probably responsive on matrix is she on vacation actually is that one?
KHG: Okay. I don't have her email so I yeah, I If you maybe…
SYG: Oh yeah, okay, yeah,…
KHG: if you get it to…
SYG: I'll forward it.
KHG: Cool. Awesome.
KHG: And then yeah, because I did want to check with her and that sounds good. I will keep iterating on alternative to, we will Keep the decorators meetings that we're doing, currently bi-weekly to discuss the details here. So anybody who wants to join to kind of further hash out the details and figure out what we think is the best solution there. Please join they. The meetings are at on a. I forget the times I think it's like 8am one day. One once a month that then 10 am the other time Pacific time so yeah, sounds good.
SYG: All right, and this is I didn't, I didn't take notes. Hopefully the transcription has something legible. So please review if you if you talk but if it's not legible too bad, we'll see.
KG: Hey, let me try to recap Briefly of the options.
KHG: oh,
KG: We talked about tended like option. Two was generally the most favorable and they're specific details. That would need to be worked out. Is Is it a symbol? Is it a frozen object? And is there some way to expose information about the parent either via putting it on a context, object as Ron suggested or putting a parent property on a frozen object or some other alternative? And I think that was it. Those are the only details for this design.
KHG: also, is it a mutable namespace can
KG: Sorry, yes. Is it is that a symbol immutable object or a frozen object is question,…
KHG: Yes.
KG: 1. And then question 2 is whether and how to expose whether how and what information about the parent to expose,
KHG: Yep. Sounds good. Alright, thanks everyone. This is super helpful.
SYG: All right. Yeah, thanks all see you all next week.
JFI: Cool. Thanks.
KHG: Later.