Decorators for functions

Isiah Meadows isiahmeadows at gmail.com
Thu Oct 22 06:47:59 UTC 2015


I think the main debate here is ergonomics. And by the way, since most
descriptors simply replace the `value` property (especially most that are
generic functional utilities), it could just as easily be made to deal with
both. I already make most of my descriptors that way now, so they can be
applied to either a class or function.

```js
function descriptor(f) {
  return function (target, name, desc) {
    if (arguments.length < 3) return f(target)
    desc.value = f(desc.value)
  }
}

const memoize = descriptor(f => function () {
  // stuff
})

const fibs = memoize(x =>
  x < 0 ? 0 :
  x <= 1 ? x :
  fibs(x - 1) + fibs(x - 2))

class Foo {
  @memoize
  method(x) { /* ... */ }
}
```

My personal opinion is that the decorator looks better than function
application. It also reads more clearly in that it's a function modifier,
not a function simply taking a function value (like Array.prototype.map or
Promise.prototype.then).

Python function decorators work similarly, IIRC.

```js
@decorator
function memoize(f) { /* ... */ }

@memoize
function fibs(n) {
  if (x < 0) return 0
  if (x <= 1) return x
  return fibs(x - 1) + fibs(x - 2)
}
```

On Thu, Oct 22, 2015, 00:34 Jordan Harband <ljharb at gmail.com> wrote:

> One thing that seems to be missing from this thread is acknowledgement
> that decorators are not just simple function wrappers. They take a property
> descriptor as an argument, and they can return a new property descriptor -
> which allows an object or "class" to have its shape determined at creation
> time, allowing for massive engine optimization, as well as allowing for
> things like enumerability, configurability, writability, getters, setters,
> and various other metadata to be determined *before the object in question
> is mutated, or even exists*.
>
> Decorators are certainly something that can be quasi-polyfilled, but when
> applied to object or "class" properties, it allows access to the property
> descriptor without needing to assign, then reflect, and then define the
> resulting descriptor. `@foo` isn't merely sugar for a function call without
> parens - it's an imperative way to define property descriptors at object
> initialization time, which is something that does not currently exist in
> the language beyond `get foo() {}` and `set foo() {}`.
>
> If this has been mentioned and I missed it, please ignore me, but the
> thread seems to have overlooked this facet of the proposal. Also, if I'm
> reading the proposal incorrectly, please correct me!
>
> - Jordan
>
> On Wed, Oct 21, 2015 at 7:10 PM, Rick Waldron <waldron.rick at gmail.com>
> wrote:
>
>> Or just use call constructor:
>>
>> class F {
>> #decorator
>> call constructor() {
>> ...
>> }
>> }
>>
>>
>> Rick
>>
>> On Tue, Oct 20, 2015 at 9:19 AM Matthew Robb <matthewwrobb at gmail.com>
>> wrote:
>>
>>> Why not just do:
>>>
>>> ```
>>> const {myFunc} = {
>>>   @someDecorator;
>>>   myFunc() {
>>>
>>>   }
>>> };
>>> ```
>>>
>>>
>>> - Matthew Robb
>>>
>>> On Tue, Oct 20, 2015 at 9:00 AM, Andrea Giammarchi <
>>> andrea.giammarchi at gmail.com> wrote:
>>>
>>>> You completely misunderstood me Bob, I don't think there's any valid
>>>> use case for functions at all, including methods and ... .**specially**
>>>> methods!!!
>>>>
>>>> I was thinking about decorators for classes, when you enrich their
>>>> prototype in case the decorator receives a function instead of an object,
>>>> or you enrich the object in every other case.
>>>>
>>>> You transform at runtime prototype methods??? Good for you, but that's
>>>> something I'd never do, unless we are talking about lazy evaluation on the
>>>> instance, where I don't see how lazy evaluation for an inherited method has
>>>> anything to do with *functions* decorators.
>>>>
>>>> The difference is huge, methods will most likely have a `this`
>>>> reference to be promoted on eventually, in  the other case you have a
>>>> function that unless its body has "switches" can cannot really promote much
>>>> by itself and passing it around as higher order function that mutates? ...
>>>> yak!
>>>>
>>>> As summary: does anyone has a valid use case for a generic function
>>>> decorator? 'cause I still don't see one, and having decorators for any sort
>>>> of function would be problematic in terms of code portability, which is all
>>>> I am saying.
>>>>
>>>> Regards
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> On Tue, Oct 20, 2015 at 1:40 PM, Bob Myers <rtm at gol.com> wrote:
>>>>
>>>>> So wait, you agree there are valid use cases for decorating functions
>>>>> when they are methods on an object (although I don't see much along that
>>>>> line in the proposal). But if the function is "stand-alone" suddenly the
>>>>> use cases evaporate?
>>>>>
>>>>> For example, I hack on and off on a framework involving transforming
>>>>> functions into self-updating versions of themselves. Of course I can write
>>>>> this as
>>>>>
>>>>>     self_updatify(function a() { })
>>>>>
>>>>> but it would be more compact and readable to say
>>>>>
>>>>>     @self_updatify
>>>>>     function a() { }
>>>>>
>>>>> Which is, please correct me if I'm wrong, all decorators are about. To
>>>>> take one example, Ember wants to use decorators not to get new
>>>>> functionality, but to make the writing of computed properties less ugly,
>>>>> among other reasons. (The fact that Ember makes little use of non-method
>>>>> functions may also be one reason for the low priority placed on figuring
>>>>> out how to decorate functions.)
>>>>>
>>>>> We can work to develop more examples and motivations and use cases for
>>>>> decorated functions, although frankly it seems a little odd, as I mentioned
>>>>> above, that there could be compelling use cases for decorated methods but
>>>>> not for decorated functions. For the purposes of this discussion I will
>>>>> stipulate that having decorated functions is an idea worth pursuing. If you
>>>>> disagree, there's not point in reading further (but you might want to stop
>>>>> and ask yourself why if it's such a great idea to have decorated methods,
>>>>> no-one will ever want decorated functions).
>>>>>
>>>>> The only problem as far as I am aware is how to handle hoisting.
>>>>>
>>>>> AFAICS, hoisting is not an issue if the decorator has no side effects.
>>>>> Of course there is nothing wrong with writing decorators with side effects,
>>>>> and there are valid use cases for doing so, but they are rare. Furthermore,
>>>>> even if a decorator does have side-effects, in only some subset of such
>>>>> cases will the side effects together with hoisting result in unexpected
>>>>> behavior.
>>>>>
>>>>> So to say that we will simply give up on decorated functions because
>>>>> of the few cases where decorators have side effects, and those side effects
>>>>> cause unexpected behavior due to hoisting, is really throwing out the baby
>>>>> with the bathwater. We are telling people that you cannot decorate
>>>>> functions at all, ever, or to decorate functions they must wrap them in a
>>>>> class or object, because of some potentially unexpected behavior in what is
>>>>> decidedly an edge case.
>>>>>
>>>>> Various proposals have been made on this topic, including hoisting
>>>>> separately from decorating, hoisting and decorating at the same time,
>>>>> change hoisting behavior for decorated functions, etc. etc. Each of these
>>>>> ideas has its proponents and those who think it is the work of the devil. I
>>>>> will not go into the details of these approaches here, and to do so is
>>>>> actually a bit above my pay grade.
>>>>>
>>>>> I would just say that it is odd in the extreme that a group of
>>>>> world-leading language designers would just throw in the towel when
>>>>> confronted with a pretty small roadbump, instead of figuring out ways to
>>>>> solve it. The alternative, which is to implement decorators only for
>>>>> methods and classes and leave out functions because we couldn't figure it
>>>>> out, seems like a major admission of failure.
>>>>>
>>>>> Bob
>>>>>
>>>>>
>>>>> On Tue, Oct 20, 2015 at 4:03 PM, Andrea Giammarchi <
>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>
>>>>>> You haven't provided a single use-case example, like how are you
>>>>>> going to decorate a function or why.
>>>>>>
>>>>>> IMO if implemented it will be incompatible with non ES6 code unable
>>>>>> to distinguish between classes and functions unless fully transpiled,
>>>>>> making decorators less portable.
>>>>>>
>>>>>> One thing I like about current state is that you can use decorators
>>>>>> even in ES5 browsers [1]
>>>>>>
>>>>>> Just my 2 cents, Regards
>>>>>>
>>>>>>
>>>>>> [1] as shown in the second example of the universal mixin module
>>>>>> https://github.com/WebReflection/universal-mixin#universal-mixin-
>>>>>>
>>>>>> On Tue, Oct 20, 2015 at 10:30 AM, Axel Rauschmayer <
>>>>>> rauschma at icloud.com> wrote:
>>>>>>
>>>>>>> https://github.com/wycats/javascript-decorators/blob/master/README.md
>>>>>>>
>>>>>>> The decorator proposal does not include decorators for functions,
>>>>>>> because it isn’t clear how to make them work in the face of hoisting.
>>>>>>>
>>>>>>> However, it would be great to have them. I see two possible
>>>>>>> solutions:
>>>>>>>
>>>>>>> – A decorator on a function declaration prevents hoisting.
>>>>>>>
>>>>>>> – Enable decorators for function expressions, arrow functions and
>>>>>>> generator function expressions.
>>>>>>>
>>>>>>> Does either one of those make sense?
>>>>>>>
>>>>>>> Axel
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>> _______________________________________________
>>>> es-discuss mailing list
>>>> es-discuss at mozilla.org
>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>
>>>>
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20151022/2e512839/attachment.html>


More information about the es-discuss mailing list