-
Notifications
You must be signed in to change notification settings - Fork 106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow plain thunks to execute as a decorator element #44
Comments
i would not expect a class decorator to be able to have any ability to see or manipulate lexical class declarations; any more then i would expect a method decorator to have any ability to see or manipulate lexical declarations inside the method. |
The manipulation would not be of the lexical bindings, just the code to initialize them. The problem I'm trying to solve here is, class decorators have the power to reorder static public field declarations, but then it is unclear what order the lexical declarations (which cannot be decorated) should be executed in. I see a few possibilities here:
Do you have a preference among these there? Or do you see other possibilities? |
When you say "reorder", can you clarify what you mean exactly? Do they get a list of initializers, and can replace it with an alternate list? |
Yes, class decorators can already do this with static field declarations. |
Is there an example of where a lexical declaration would depend on the ordering of a specific static field? (it's easy to conceive of the reverse). I'm wondering if "when a class is decorated, all lexical decls are evaluated first, and all static fields after that" would be reasonable. |
It's possible I'm overthinking this, but my intuition is that more passes will be more counter-intuitive. I don't have a practical example on hand, but here's a case where the issue is observable. let arr = [];
function decorator(desc) { return desc; }
@decorator
class C {
<placeholder> let x = arr.push(1);
static y = arr.push(2);
<placeholder> const z = arr.push(3);
static w = arr.push(4);
}; My intuition would be that But, what if we have the following decorator? function decorator(desc) {
desc.elements.reverse();
return desc;
} This decorator will make the |
I think losing the interleaving is fine - the interleaving is a property of the original lexical code, and the decorator can’t rewrite the original code - it can only replace the result of it. |
Could you explain a little more why losing the interleaving is fine for you? I agree that I don't have a great use case for decorators changing things here, though. |
It's more that, I don't see any value in preserving it, and I think that if these are lexical class declarations, then exposing any information about them to decorators is breaking the way lexical declarations work elsewhere. It wouldn't make sense to decorate a function and get access to the variables it declared lexically inside it, why would it make sense for a class decorator to do so? |
OK, I think we don't have to add this feature in the first round for decorators. @rbuckton's alternative for tc39/proposal-static-class-features#23 doesn't require it. We could always add this as a follow-on feature, but let's keep it in our back pocket in case any killer use cases come up in continued discussions with programmers. |
This proposal seems to exactly address #153 / mobxjs/mobx#1732, no place to run initialization code as soon as a decorator produces a The proposal itself, {
kind: "initializer",
placement: "prototype" | "own" | "static" // or just limit to "own"?
initializer(target) {
// target is instance, prototype or constructor based on placement?
}
// no: descriptor,
// no: key
finisher // as-is
extras // as-is
} For reference, the real life use case: https://github.com/mobxjs/mobx/blob/6092288297c0cc596064c555ec4203c5c57f5a94/src/api/observabledecorator.ts#L57-L95 |
@mweststrate It looks like ObservableObjectAdministration uses a Map to hold the underlying observed properties, right? I was hoping that, with decorators and private fields, you could hold the underlying backing store as a synthetic private field, whose initializer could do the setup action (e.g., evaluating the initializer expression); I was also hoping that prototype (not own) getter/setters could be usable. Now I can see that would be a rather big code change for MobX, but I am still wondering if it might be a possible way out without this feature. |
@littledan that would probably work indeed, but here are my concerns in order of least to most importance:
The biggest concern however is: using decorators should not force where properties descriptors are stored, or how they are backed! Not being able to control the initialization of an object from properties properties was a big concern in the earlier proposal, and it is not entirely solved yet. (I thought it was from review, but giving the work arounds in the MR shows some stuff is still missing): namely extending the 'constructor' by running instance initialization code. Yes, a significant rewrite of MobX, using private properties will probably work within the current proposal (I expect), but needing such a rewrite, that not just changes the decorator implementation (which is fine), but also requires changing the entire internal administration should raise some alarms in the first place. |
@littledan, @mweststrate, why not just allow an UPD: Oh I see disadvantages of my approach. Only-initializer field is more universal. |
Thanks for the detailed explanation, @mweststrate . See this patch out for review, based on @mweststrate 's original API proposal, which other reviewers also preferred: #165 |
@littledan thanks! this seems to match my use cases nicely. |
Proposal: Allow
undefined
as a key for field decorators. The semantics would be to just execute the initializers for its side effect. (Another superficial alternative would be to make this a new element type, which doesn't have a key field.)A couple reasons this comes up:
arguments
an earlier error in lexical declarations.)The text was updated successfully, but these errors were encountered: