Decorators for functions

Ron Buckton Ron.Buckton at microsoft.com
Thu Oct 22 20:41:33 UTC 2015


> -----Original Message-----
> From: Andrea Giammarchi [mailto:andrea.giammarchi at gmail.com]
> Sent: Thursday, October 22, 2015 12:53 PM

> Ron, there's **no way** you can distinguish a class from  a generic function
> in current specifications.

Yes, this is true. However, decorators aren't in the current specification either. If this becomes a must-have then we should investigate an API or meta-property that could expose this information, as I mentioned in my previous reply.

> Having one argument won't tell me much, having a way to know that is not a
> class I need to decorate (traits/mixins) but just a function, so ignoring its
> prototype and do something else, would be cool but it's unfortunately not
> possible or portable.
> 
> How would you distinguish between a class or a function for a generic
> decorator? Or all you are saying is that decorators shouldn't be able to
> distinguish at all between a class, rather than a function?

While I think it would be a valuable feature to be able to distinguish between a class and a function, it may make it difficult to properly reason between an ES6 class and an ES5/3 function-as-a-class-constructor. The possibility of adding a "call constructor" further complicates this.

It's useful to be able to disambiguate within the decorator, so I can know whether I would need to maintain a prototype chain:

```js
function someDecorator(target) {
  // using "function.decoration" as a possible meta-property
  if (function.decoration === "class") {
    return class extends target {
      constructor(...args) {
        // do something in constructor...
        super(...args);
      }
    };
  }
  else if (function.decoration === "function") {
    return function(...args) {
      // do something in function...
      return target(...args);
    };
  }
}
```

Alternatively, it would be interesting if all class declarations were implicitly given a Symbol.class property on the constructor declaration. This way older function-as-a-class-constructor implementations could opt-in to stating "I'm a class":

```js
function someDecorator(target) {
  if (arguments.length !== 1) throw new TypeError(); // only for class/function
  if (target.hasOwnProperty(Symbol.class)) {
    // class
  }
  else {
    // function
  }
}

// up-level
@someDecorator
class ES6Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

// down-level
function Point(x, y) {
  this.x = x;
  this.y = y;
}
Point[Symbol.class] = true;
Point = someDecorator(Point) || Point;
```

Ron 



More information about the es-discuss mailing list