-
Notifications
You must be signed in to change notification settings - Fork 107
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
Decorator call signature ambiguity #81
Comments
I'm really confused by this issue. I don't know of any cases where just adding or removing parentheses around an expression changes the receiver like that. The cases I know of are more like this: > ({x() { return this.y }, y: 1}).x()
< 1
> (0, ({x() { return this.y }, y: 1}).x)()
< undefined The receiver semantics I'd expect for the paren auto-insertion case would be more like, when calling the decorator the first time, use the receiver that's textually there (if any), and for the second call, use |
The only place this happens in ES is with |
Where is the ambiguity? Decorators are functions that needs to be declared within the evaluator expresión There is no ambiguity whatsoever |
We should not encourage developers to use this within decorator scope because there should be no context. IMO |
Since the meeting, a number of people including @jridgewell, @ljharb and @gsathya have expressed some reservations about the decision that weren't expressed in the meeting, among other people. I'd like to spend some more time thinking about all of this before we fully settle on the semantics we discussed in the meeting. @k1r0s When we spoke about this issue, you had some interesting use cases where the parens issue comes up--it sounded like the new auto-insertion semantics made those cases less ergonomic. Could you explain more? |
After researching it more, I'm meh with it. We just need to communicate clearly (many many many times) that decorators are two-part functions, a factory and an implementation: function DecFactory() {
return DecImpl;
}
function DecImpl(descriptor) {
}
@DecFactory; // evaluates to DecImpl(descriptor)
@DecFactory(); // evaluates to DecImpl(descriptor)
@(DecFactory); // evaluates to DecImpl(descriptor)
@(DecFactory()); // evaluates to DecImpl()(descriptor)
@(DecFactory())(); // evaluates to DecImpl()(descriptor) Given that, the current spec is exactly like function FooFactory() {
return FooImpl;
}
function FooImpl() {
}
new FooFactory; // evaluates to FooImpl
new FooFactory(); // evaluates to FooImpl
new (FooFactory); // evaluates to FooImpl
new (FooFactory()); // evaluates to FooImpl {}
new (FooFactory())(); // evaluates to FooImpl {} |
Yes, so having for example this like: function beforeInstance (...advices) {
return function(t, k, descriptor) {
...
}
} @beforeInstance(inject.args(AxiosProvider, StorageProvider))
class WhatEver {} the only requirement is that expression to be evaluated as a function. then we can asign this thing into an alias if we don't need to tweak it for other entities: const InjectParams = (...args) => beforeInstance(inject.args(...args))
const Inject = beforeInstance(inject.args(AxiosProvider, StorageProvider))
@InjectProviders(AxiosProvider, StorageProvider)
class WhatEver1 {}
@Inject
class WhatEver2 {} You can simplify expressions and its very handy. Again, I don't see any ambiguity on current api. What I do see is developers having to write two functions when they don't need to. |
Making the identifier case hard to misuse and not require defensive programming on every single decorator factory is the better approach here. EDIT: It seems that I misunderstood one detail, in that // proposal
@foo // call foo as a factory; same as @foo() and @(foo())
@foo() // call foo as a factory; same as @(foo())
@foo(bar) // call foo as a factory with an argument; same as @(foo(bar))
@(expr) // will call expr result directly with the descriptor instead of as a factory If that's not feasible, then making it behave exactly like |
For me, this is the same case as doing this: function bar(arg1) {
console.log(arg1);
}
function foo() {
return "foo"
}
bar(foo); // logs [Function foo]
bar(foo()); // logs "foo" JavaScript developers understand this perfectly.
|
It looks easy in tiny examples. Making |
For me, this is not enough argument in order to do API changes .. Decorator expressions are outside of program logic, they are pretty simple to remember. I don't think people will be forced to defensive programming if they don't need to. And that's not even driven by decorator syntax. And, in the other hand, decorators are here to avoid code duplication and encourage encapsulation so, afterall it makes sense to make some validations if you're gonna put that pattern in a single place to be used everywhere. |
The best of decorators is that you have a lot of freedom as long as you provide a valid expression with the current working typescript version: k1r0s/kaop-ts#89 (comment) I can provide a lot of examples. I hope you're familiar working with decorators in production environments |
@nicolo-ribaudo , @rbuckton and I discussed this issue. All of us would be OK with doing what the decorator champion group previously proposed of not inserting the parentheses. We'll have to discuss this again in a larger group which includes people who argue in favor of the other path. |
So those parens are just because of being able to decorate with dynamic decorator? In that case I think explanatory variable is far better (more readable) choice:
vs.
Edit: apparently this is offtopic, sorry :-) |
Actually this issue is about the parentheses which contains the parameters ( |
with the current spec (which im using): Its posible as long you force users to keep a factory function that returns the decorator function even if they don't use parameters. And I'm not agree |
@wycats @bterlson @rbuckton and I discussed this issue again. The consensus among that group has been to push back against inserting the parentheses, but to make a tweak to the previous branding strategy: Instead of multiple Does anyone want to write the patches and docs updates for this change? |
Hi, do you think that babel/babel#7773 is still needed? |
Many people have pointed out, if we think about static decorators, we may want to reopen this issue. Right now, I'm leading to auto-parens if we go with this alternative. |
OK, now that we're back to function-based decorators given #310, re-closing this issue, to leave it with the resolution described in #81 (comment) |
This was previously discussed in the old repository, and was brought up during the last TC39 meeting.
If we are considering auto-inserting parentheses, we can generally modify the algorithm for DecoratorEvaluation to be:
This would preserve the correct
this
, but we would need to articulate the difference between this:And this:
As it aligns with the behavior of
new
:The text was updated successfully, but these errors were encountered: