Decorators for functions
Andrea Giammarchi
andrea.giammarchi at gmail.com
Fri Oct 23 15:25:56 UTC 2015
Salvador
> could you provide an example of how decorators on functions could break
the web?
we were talking about the ability to distinguish, not anymore about
decorators. I think this thread went off topic so ... let's see what TC39
will decide.
Cheers
On Fri, Oct 23, 2015 at 2:25 PM, Salvador de la Puente González <
salva at unoyunodiez.com> wrote:
> No, sorry, I don't think so. Maybe I don't get your point so could you
> provide an example of how decorators on functions could break the web?
>
> As far as I understand, if you start to use foreign code beyond its API
> you could break the old code with and without decorators.
>
> On Fri, Oct 23, 2015 at 1:52 PM, Andrea Giammarchi <
> andrea.giammarchi at gmail.com> wrote:
>
>> OK let me rephrase: it is **not inter-operable** with well known
>> libraries that might have factories in the wild and no way to distinguish
>> if they are dealing with new ES6 syntax or old one.
>>
>> Having no way to distinguish easily breaks the web.
>>
>> Regards
>>
>> On Fri, Oct 23, 2015 at 11:44 AM, Salvador de la Puente González <
>> salva at unoyunodiez.com> wrote:
>>
>>> Well, I see, it's not worse than other dynamic typing issues (think
>>> about `invokeThat.call()` being called on undefined or null, the exception
>>> only gives you a runtime error and you could always wrap in a try-catch,
>>> see the message and translate to yoour own exception or recover) but that
>>> does not relate at all with decorators which is my point. I agree on
>>> `Reflection.isClass` although I should check the spec in the search for
>>> something related with that specific topic but returning to the previous
>>> discussion about which syntax to use when decorating functions, I don't see
>>> this is a blocker for extending present decorator syntax to functions.
>>>
>>> On Fri, Oct 23, 2015 at 12:17 PM, Andrea Giammarchi <
>>> andrea.giammarchi at gmail.com> wrote:
>>>
>>>> well
>>>>
>>>> > Can you point me some example where not distinguishing between
>>>> functions and classes would be fatal, please?
>>>>
>>>> the fact a class throws once invoked like a function isn't enough fatal
>>>> to you?
>>>>
>>>> ```js
>>>> function invokeThat() {
>>>> var result = Object.create(this.prototype);
>>>> return this.apply(result, arguments) || result;
>>>> }
>>>>
>>>> invokeThat.call(function sum(a, b) { return a + b; }, 1, 2); // 3
>>>>
>>>> invokeThat.call(class Point{constructor(x,y){this.x=x;this.y=y;}}, 10,
>>>> 15);
>>>> // Uncaught TypeError: Class constructors cannot be invoked without
>>>> 'new'(…)
>>>> ```
>>>>
>>>> We are missing a `Reflection.isClass` ... useful or not, we've got two
>>>> kind of "invokables" and nobody can distinguish from them.
>>>>
>>>> Regards
>>>>
>>>>
>>>>
>>>>
>>>> On Fri, Oct 23, 2015 at 10:56 AM, Salvador de la Puente González <
>>>> salva at unoyunodiez.com> wrote:
>>>>
>>>>> Hi Andrea.
>>>>>
>>>>> On Thu, Oct 22, 2015 at 10:34 PM, Andrea Giammarchi <
>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>
>>>>>> which one is true?
>>>>>>
>>>>>> > I think there is no ambiguity at all ... decorating a function
>>>>>> should be like decorating a class
>>>>>>
>>>>>> 'cause I think those are very different things.
>>>>>>
>>>>>
>>>>> As far as I know, classes in ES6, apart from preventing you from
>>>>> calling without `new` (and minor subclassing details), are identical to
>>>>> functions.
>>>>>
>>>>>
>>>>>> You gonna wrap for sure the first one, you most likely ever even
>>>>>> bother replacing the class, rather enriching its prototype or its public
>>>>>> statics.
>>>>>>
>>>>>
>>>>> Well, is not as sure you want to wrap a function at all. Suppose:
>>>>>
>>>>> ```
>>>>> // operaations.js
>>>>> @priority(2)
>>>>> function taskA() { doSomething(); }
>>>>>
>>>>> @priority(1)
>>>>> function taskB() { doSomething(); }
>>>>>
>>>>> @priority(5)
>>>>> function taskC() { doSomething(); }
>>>>>
>>>>> taskManager.register(taskA, taskB, taskC);
>>>>> taskManager.run(); // run taking into account priority symbol of the
>>>>> functions
>>>>>
>>>>> // taskManager.js
>>>>> var priority = new Symbol();
>>>>>
>>>>> function priority(p) {
>>>>> return function(target) { target[priority] = p; }
>>>>> }
>>>>> ```
>>>>>
>>>>> On the contrary, you would want to replace a class completely:
>>>>>
>>>>> ```
>>>>> @singleton
>>>>> class system {
>>>>> get version() { return '1.0.0'; }
>>>>> get drives() { return ...; }
>>>>> }
>>>>>
>>>>> console.log(system.version);
>>>>>
>>>>> function singleton(target) {
>>>>> return target();
>>>>> }
>>>>> ```
>>>>>
>>>>> I'm not saying is not important to distinguish between classes and
>>>>> functions, I'm just saying, it is not as important and not critical for the
>>>>> decorator syntax. It suffices for a framework to make their classes to
>>>>> inherit from a custom base object with a symbol `isClass` set to true to
>>>>> allow their own decorators to distinguish between classes and functions but
>>>>> these are specific-implementation details. What is true is the the syntax
>>>>> works for regular functions and class based functions.
>>>>>
>>>>>
>>>>>>
>>>>>> Maybe it's me overlooking at this, but the fact we cannot distinguish
>>>>>> between classes and functions doesn't feel right to me.
>>>>>>
>>>>>
>>>>> No, sorry, maybe it's me that I can not see a harmful side effect
>>>>> here. Can you point me some example where not distinguishing between
>>>>> functions and classes would be fatal, please? Maybe this way, I (and
>>>>> others) understand your concerns.
>>>>>
>>>>>
>>>>>>
>>>>>> Regards
>>>>>>
>>>>>> P.S. babel has some target (browsers mostly, and nodejs) but it
>>>>>> shouldn't be the reason to choose a pattern instead of another, or at least
>>>>>> not the only one
>>>>>>
>>>>>
>>>>> Of course, but it is a clear indicator of semantics. It's very
>>>>> valuable for a language to allow its own declarative semantics to be
>>>>> expressed in a programmatic fashion as it denotes a very consistent and
>>>>> versatile data & execution models.
>>>>>
>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Thu, Oct 22, 2015 at 9:26 PM, Salvador de la Puente González <
>>>>>> salva at unoyunodiez.com> wrote:
>>>>>>
>>>>>>> Hi people.
>>>>>>>
>>>>>>> After reading the conversation, I think there is no ambiguity at all
>>>>>>> or, may be, it must be there: decorating a function should be like
>>>>>>> decorating a class, you can not distinguish between them and that's all.
>>>>>>> Just look at the code generated in Babel:
>>>>>>>
>>>>>>> https://babeljs.io/repl/#?experimental=true&evaluate=true&loose=false&spec=false&code=%40decorator%0Aclass%20A%20{}
>>>>>>> <https://babeljs.io/repl/#?experimental=true&evaluate=true&loose=false&spec=false&code=%40decorator%0Aclass%20A%20%7B%7D>
>>>>>>>
>>>>>>> You'll see:
>>>>>>>
>>>>>>> ```
>>>>>>> A = decorator(A) || A;
>>>>>>> ```
>>>>>>>
>>>>>>> And this is the traditional notion of decorator we see in Python and
>>>>>>> other languages. A simple way to check for a generic decorator would be:
>>>>>>>
>>>>>>> ```
>>>>>>> function decorator(target, name='', descriptor=null) {
>>>>>>> if (descriptor) console.log('Decorating a member');
>>>>>>> else console.log('Decorating either a function or class');
>>>>>>> }
>>>>>>> ```
>>>>>>>
>>>>>>> And it's very consistent if you think the only difference a ES6
>>>>>>> class introduces is that you are not allowed to call the class as a
>>>>>>> function.
>>>>>>>
>>>>>>> So, the generated code for:
>>>>>>>
>>>>>>> ```
>>>>>>> @decorator
>>>>>>> function A() { }
>>>>>>> ```
>>>>>>>
>>>>>>> Should be:
>>>>>>>
>>>>>>> ```
>>>>>>> function A() {}
>>>>>>> A = decorator(A) || A;
>>>>>>> ```
>>>>>>>
>>>>>>> And that's all, if you always add the overwrite after the
>>>>>>> definition, hoisting is irrelevant but if it worries you, simply avoid
>>>>>>> hoisting when decorating as Axel suggested.
>>>>>>>
>>>>>>>
>>>>>>> PS: Well thought, it must be possible for an hypothetical reflection
>>>>>>> function to determine if a function is a class or not as classes are marked
>>>>>>> to throw when they are not invoked with new.
>>>>>>>
>>>>>>> On Thu, Oct 22, 2015 at 9:52 PM, Andrea Giammarchi <
>>>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>>>
>>>>>>>> Ron, there's **no way** you can distinguish a class from a generic
>>>>>>>> function in current specifications.
>>>>>>>>
>>>>>>>> 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?
>>>>>>>>
>>>>>>>> Regards
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On Thu, Oct 22, 2015 at 7:32 PM, Ron Buckton <
>>>>>>>> Ron.Buckton at microsoft.com> wrote:
>>>>>>>>
>>>>>>>>> Andrea,
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Is your concern about disambiguating the usage of a decorator at
>>>>>>>>> the call site or within the body of the decorator? In the current proposal,
>>>>>>>>> you can decorate a class member, or the class itself.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> When decorating a class member, three arguments are passed to the
>>>>>>>>> decorator: The target, the property key (string or symbol), and the
>>>>>>>>> descriptor. When decorating the class, one argument is passed to the
>>>>>>>>> decorator: The constructor function. Generally this means that you can
>>>>>>>>> disambiguate the usage of the decorator based simply on `arguments.length`,
>>>>>>>>> or testing for `undefined` for the property key or descriptor.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Would it be better to have a more consistent way to disambiguate
>>>>>>>>> the usage of a decorator from within the decorator? This could be addressed
>>>>>>>>> with something like a Reflect.getDecoratorUsage API or a
>>>>>>>>> `function.decoration` meta-property or the like. Consider something like:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> ```js
>>>>>>>>>
>>>>>>>>> function memoize(target, key, descriptor) {
>>>>>>>>>
>>>>>>>>> switch (Reflect.getDecoratorUsage(arguments)) {
>>>>>>>>>
>>>>>>>>> case "class":
>>>>>>>>>
>>>>>>>>> // `target` is the class constructor. `key` and `descriptor`
>>>>>>>>> are undefined.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> case "function":
>>>>>>>>>
>>>>>>>>> // `target` is the function. `key` and `descriptor` are
>>>>>>>>> undefined.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> case "method":
>>>>>>>>>
>>>>>>>>> // `target` is the object containing the method (e.g.
>>>>>>>>> constructor
>>>>>>>>>
>>>>>>>>> // for a static method, prototype for a prototype method, or
>>>>>>>>>
>>>>>>>>> // instance for an object literal method).
>>>>>>>>>
>>>>>>>>> // `key` is the string or symbol property name for the
>>>>>>>>> method.
>>>>>>>>>
>>>>>>>>> // `descriptor` is the property descriptor for the method.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> case "accessor":
>>>>>>>>>
>>>>>>>>> // `target` is the object containing the accessor (e.g.
>>>>>>>>> constructor
>>>>>>>>>
>>>>>>>>> // for a static accessor, prototype for a prototype
>>>>>>>>> accessor, or
>>>>>>>>>
>>>>>>>>> // instance for an object literal accessor).
>>>>>>>>>
>>>>>>>>> // `key` is the string or symbol property name for the
>>>>>>>>> accessor.
>>>>>>>>>
>>>>>>>>> // `descriptor` is the property descriptor for the accessor.
>>>>>>>>>
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> ```
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Ron
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> *From:* es-discuss [mailto:es-discuss-bounces at mozilla.org] *On
>>>>>>>>> Behalf Of *Andrea Giammarchi
>>>>>>>>> *Sent:* Thursday, October 22, 2015 10:47 AM
>>>>>>>>> *To:* Yongxu Ren <renyongxu at gmail.com>
>>>>>>>>> *Cc:* es-discuss mailing list <es-discuss at mozilla.org>
>>>>>>>>> *Subject:* Re: Decorators for functions
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Removing ambiguity is my point since the very first post: current
>>>>>>>>> proposal is about a target, a property name, and a descriptor for such
>>>>>>>>> property ... having functions/variables decorators have no target (in
>>>>>>>>> strict mode undefined can't be a target, right?) and not necessarily a
>>>>>>>>> descriptor, or if any, always a data one with fields that makes no sense
>>>>>>>>> (like enumerable within a private scope ... what does that even mean)
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> I'm all in for a distinct, separate, syntax to decorate
>>>>>>>>> "callables" or other variables as long as the current proposal will make
>>>>>>>>> for ES7 and won't be bothered by this different requirement.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Regards
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Thu, Oct 22, 2015 at 6:29 PM, Yongxu Ren <renyongxu at gmail.com>
>>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>> I don't think
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> > ```@@ or @() or @::meomize```
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> would really help much, you can tell what the decorator does by
>>>>>>>>> simply looking at its name. And looks like you can not use @ and @@ for the
>>>>>>>>> same decorator function without adding extra condition checking inside the
>>>>>>>>> function.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> There are two patterns that we have discussed here, they are
>>>>>>>>> actually quite distinct. I still think we should support decorator on
>>>>>>>>> variables, but maybe we should have 2 distinct syntax for the normal
>>>>>>>>> decorators and "ambient decorators"(from Jonathan's post):
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> 1. decorator that alter the code behavior, the currently
>>>>>>>>> proposed decorator. Such as ```@memoize```
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> 2. decorator that absolutely does not alter the code behavior,
>>>>>>>>> only used for optimization, checking or debugging. Instead of @, a distinct
>>>>>>>>> syntax will be much clearer ex.```@annotatition@``` (Maybe it
>>>>>>>>> should be called annotation instead?):
>>>>>>>>>
>>>>>>>>> ```
>>>>>>>>>
>>>>>>>>> @deprecated@
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> @number,number=>string@/*type checking*/
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> @debug("this message will only print in development mode")@
>>>>>>>>>
>>>>>>>>> ```
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> it sounds like terrible idea to have a decorator in code that you
>>>>>>>>> can not figure out if it will alter the code behavior by looking at it. I
>>>>>>>>> do like to see all the new ideas been added into javascript, but it is also
>>>>>>>>> necessary to eliminate the ambiguity whenever possible.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Thu, Oct 22, 2015 at 11:20 AM, Jonathan Bond-Caron <
>>>>>>>>> jbondc at gdesolutions.com> wrote:
>>>>>>>>>
>>>>>>>>> On Thu Oct 22 07:44 AM, Andreas Rossberg wrote:
>>>>>>>>> > > determined at creation time, allowing for massive engine
>>>>>>>>> optimization,
>>>>>>>>> >
>>>>>>>>>
>>>>>>>>> Ya I'm not sure from which hat "massive engine optimization" comes
>>>>>>>>> from?
>>>>>>>>>
>>>>>>>>> What's meant is likely using decorators as annotations (compile
>>>>>>>>> time optimizations hints):
>>>>>>>>> http://www.google.com/patents/US7013458
>>>>>>>>> <https://na01.safelinks.protection.outlook.com/?url=http%3a%2f%2fwww.google.com%2fpatents%2fUS7013458&data=01%7c01%7cron.buckton%40microsoft.com%7c4f28552d1837468197db08d2db08dcea%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=atTz2em0YIlXUvUVgiWsZ5xKNjJsIOzm3wLejdDl33E%3d>
>>>>>>>>>
>>>>>>>>> Or 'ambient decorators':
>>>>>>>>>
>>>>>>>>> https://github.com/jonathandturner/brainstorming/blob/master/README.md#c6-ambient-decorators
>>>>>>>>> <https://na01.safelinks.protection.outlook.com/?url=https%3a%2f%2fgithub.com%2fjonathandturner%2fbrainstorming%2fblob%2fmaster%2fREADME.md%23c6-ambient-decorators&data=01%7c01%7cron.buckton%40microsoft.com%7c4f28552d1837468197db08d2db08dcea%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=1aXPAnWuPpVgE3wCYZqcEnTaksCKqzwuq0bGLkkG8Uo%3d>
>>>>>>>>>
>>>>>>>>> There's 2 patterns (maybe more?):
>>>>>>>>> (a) Tagging a 'tree transformation' on a node.
>>>>>>>>> (b) Metadata at compile time on a node.
>>>>>>>>>
>>>>>>>>> The thing about (b) is it can easily live outside of the code
>>>>>>>>> (like in typescript where you have an optional header/declaration file)
>>>>>>>>>
>>>>>>>>> With (a), it seems more conservative to see how it gets used with
>>>>>>>>> classes before bolting on to functions (opinion: end result in java is not
>>>>>>>>> something to be proud of).
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> _______________________________________________
>>>>>>>>> es-discuss mailing list
>>>>>>>>> es-discuss at mozilla.org
>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>>> <https://na01.safelinks.protection.outlook.com/?url=https%3a%2f%2fmail.mozilla.org%2flistinfo%2fes-discuss&data=01%7c01%7cron.buckton%40microsoft.com%7c4f28552d1837468197db08d2db08dcea%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=YHeobU0gimD8xIX0FwR3GAdjKwWiwOGNGUWVi%2bHZARg%3d>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> _______________________________________________
>>>>>>>>> es-discuss mailing list
>>>>>>>>> es-discuss at mozilla.org
>>>>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>>>> <https://na01.safelinks.protection.outlook.com/?url=https%3a%2f%2fmail.mozilla.org%2flistinfo%2fes-discuss&data=01%7c01%7cron.buckton%40microsoft.com%7c4f28552d1837468197db08d2db08dcea%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=YHeobU0gimD8xIX0FwR3GAdjKwWiwOGNGUWVi%2bHZARg%3d>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> 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/20151023/aae2a8c9/attachment-0001.html>
More information about the es-discuss
mailing list