Decorators for functions
Salvador de la Puente González
salva at unoyunodiez.com
Fri Oct 23 13:25:28 UTC 2015
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/b7daf93c/attachment-0001.html>
More information about the es-discuss
mailing list