Decorators for functions
Andrea Giammarchi
andrea.giammarchi at gmail.com
Fri Oct 23 11:52:43 UTC 2015
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/cb9da3b2/attachment-0001.html>
More information about the es-discuss
mailing list