Skip to content
This repository has been archived by the owner on Jan 25, 2022. It is now read-only.

Need to clarify what a decorator actually is. #27

Closed
carlsmith opened this issue Feb 1, 2017 · 5 comments
Closed

Need to clarify what a decorator actually is. #27

carlsmith opened this issue Feb 1, 2017 · 5 comments

Comments

@carlsmith
Copy link

carlsmith commented Feb 1, 2017

People are using different definitions of what a decorator is. The spec is [as ever] hard to read, so it doesn't help with this issue.

There's a definition on ponyfoo.com, and I've seen it used elsewhere, that says...

A decorator is:

  • an expression (that’s preceded by an @ sign)
  • that evaluates to a function
  • that takes the target, name, and decorator descriptor as arguments
  • and optionally returns a decorator descriptor to install on the target object

IMO a decorator is not an expression; it's a function used to decorate other functions. The definition above states that an expression that uses the new invocation sugar is a decorator. That implies that decorators couldn't be used until ES6, which is incorrect.

Just to be clear, the following code defines a decorator IMO:

let decorator = function (decoratedFunction) {
    return function (...args) {
        doSomethingBefore();
        let result = decoratedFunction(...args);
        doSomethingAfter();
        return result;
    }
}

That decorator can then be applied using plain ES3 syntax or the new ES6 sugar:

// ES3
let square = decorator( function (x) { return x * x } );

// ES6
@decorator
function square(x) { return x * x }

I'm not asserting that my understanding is the correct one, but some people would concur, while others obviously do not. If only for the sake of docs authors, can we decide on the definition and add a note to the spec please?

Thanks.

@MMeent
Copy link

MMeent commented Feb 1, 2017

Hi, I agree that the definition of decorator might be not clearly specified, as there is no real example of how one would implement a decorator, while there are enough examples of usage.

IMO a decorator is not an expression;

It is an expression in that context, a js-expression like this.that (an expression that is a lookup in an object and evaluates to the value of that lookup) or func(arg) (an expression that is a function call, evaluating to the result of that function).

A note on how decorators are currently designed (iirc): A function,when used as decorator, will get as its argument an object which is the descriptor of the decorated object (1), which can be altered by the decorator-function to fit the needs of the user/developer, such as wrapping a function, making an attribute read-only (once class attributes are available), or adding attributes/methods to a class. When you return the updated descriptor that descriptor will then either be used as argument for the next decorator, or, when that decorator was the last, it will be used to construct the class with.
This does however mean, that you cannot one-on-one replace assignments with decorators, as function calls don't get a descriptor when they are an assignment.

(1) object is not a js-object, but class definition/method definition/attribute definition, like class A {}, class A {function b(){}} or class A {c = expression}

@carlsmith
Copy link
Author

carlsmith commented Feb 1, 2017

Thanks for looking at this.

Hi, I agree that the definition of decorator might be not clearly specified, as there is no real example of how one would implement a decorator, while there are enough examples of usage.

Users must implement any decorator before anyone can use it??

As long as a language has first class functions, you can implement [and apply] decorators in that language. There's normally no need for special syntax or anything else. Some languages provide sugar to make applying a decorator easier, but that's just a nice-to-have. Are you saying JavaScript decorators work differently than decorators in other languages? If so, that may be why I'm so confused.

It is an expression in that context, a js-expression like this.that (an expression that is a lookup in an object and evaluates to the value of that lookup) or func(arg) (an expression that is a function call, evaluating to the result of that function).

I don't think we're on the same page here either.

Naturally, using a decorator requires some kind of expression, in the same way that you have to express a Number to use it, but a Number is not an expression. A decorator [at least, as I've always understood it] is a callable, typically a function, that conforms to the decorator pattern. The decorator is the function itself.

Decorators are defined using regular JavaScript syntax, as it's just a function that meets some criteria. You can apply decorators using the @name sugar, but that just references a decorator.

Sorry if I've totally misunderstood something, but I've been using decorators in JavaScript (and CoffeeScript) for years, and can't see how adding a little sugar to JS syntax changes the nature of decorators in any way. Unless I've missed some important point [which is quite possible], this spec will confuse a lot of people who are totally comfortable using JS decorators normally.

@MMeent
Copy link

MMeent commented Feb 1, 2017

No problem,

Hi, I agree that the definition of decorator might be not clearly specified, as there is no real example of how one would implement a decorator, while there are enough examples of usage.

Users must implement any decorator before anyone can use it??

I'm talking about the 'how do I write a decorator-function which does ' where some functionality is fairly generic. There are examples on how to use the decorator pattern, but none for an actual implementation of a working decorator-function, which would help a lot with clarity (see #28 as well).

It is an expression in that context, a js-expression like this.that (an expression that is a lookup in an object and evaluates to the value of that lookup) or func(arg) (an expression that is a function call, evaluating to the result of that function).

I don't think we're on the same page here either.

Yes, decorator can be both mean the syntactic usage of a function (@decorator), or the function used in that syntax (function decorator(){}). For me, it's the syntactic usage of the function.


Anyway, in my opinion the current spec is quite clear on what the decorator-function gets as arguments and what it should return. It is indeed a syntactic sugar (Object.defineProperty() as rough alternative), but, just as the es2016 class notation for classes, it is now a lot more straightforward to use this feature.

@carlsmith
Copy link
Author

I just looked through the spec again, and ESDiscuss etc. trying to understand this stuff better, and realise why I was so confused now. ES6 classes have turned a simple, elegant pattern into a convoluted mess. Anyway, it was my misunderstanding. Thank you for taking the time to explain.

@carlsmith
Copy link
Author

Your last comment didn't appear until I posted mine. We'll have to agree to disagree on classes, but I understand what you were explaining now. Thanks again.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants