wycats / javascript-decorators

2.4k stars 127 forks source link

Force decorators to be higher-order functions even without parentheses #52

Closed alexbyk closed 8 years ago

alexbyk commented 8 years ago

Right now there are 2 forms of @decorators: (1)decoratorFunction and (2)decoratorFactory, which produces a (1)decoratorFunction. The difference for end users is only parentheses. If there are parentheses, decorator is in the 2nd form, if there are no parentheses, it's in the 1st form

The problem is: while we have 2 possible variants, it's not obvious which one to choose, and that leads to mistakes My proposal is to forbid the (1)decoratorFunction form and consider a decorator as (2)decoratorFactory, even without parentheses If my proposal is accepted, there will be no forgot parentheses bug. Also, because parentheses without arguments will be always optional, the syntax will be much clearer in the most of the cases

@F("color") @G class Foo { }

the same, parentheses without args are optional

@F("color") @G() class Foo { }

desugaring:

var Foo = (function () {
  class Foo {
  }

  Foo = F("color")(Foo = G()(Foo) || Foo) || Foo;
  return Foo;
})();

and G should be written this way:

function G(optional) {
  return function G(Class) {
    Class.prototype.g = optional ? optional : 'hello';
  };
}

P.S. Writing universal decorator, that examines arguments in runtime and behaves either (1) or (2) is impossible. See proofs below. Or, if you don't understand why, here is my step-by-step explanation with examples: https://github.com/alexbyk/decorators-flaw . Also please read it before pointing me to the SomeAwesomeLibrary because in the most of the cases all libraries that provide "universal/smart" decorators syntax have the same bugs no matter how popular they are. So if you library provide @withSomething class Foo {} syntax, it 100% has a potential bug. The same thing about attribute decorators

silkentrance commented 8 years ago

@loganfsmyth can we please get back to the topic at hand? And, yes, I am having a whole lot of fun right now, trying to convince these peops that they are wrong in their initial assessment. So maybe you chime in and we both have a lot of fun...

silkentrance commented 8 years ago

@loganfsmyth meta level != concrete level, so there is a distinction here. abstract such as sarcasm is not understood by people very well.

loganfsmyth commented 8 years ago

@silkentrance Sure. I think I'd said all I've got to say. If your goal is to be a member the JS community, you're not going to get there by rubbing people the wrong way. It does not matter if you are making a joke. Projecting emotion, humor and sarcasm over the internet is difficult. Generally your comments come off poorly. By all means keep doing whatever you want, but I think you'd get better results in your discussions by more carefully choosing how you approach online discourse and by treating other users as the fallible human beings they are, rather than malicious entities.

alexbyk commented 8 years ago

@loganfsmyth I think right now we're both confused.

1) Here is your example in the current impl. I renamed makeDecorator to log. (see console output)

2) Here is you example after my proposal : . It didn't change. It's the same. You don't need 2 sets of parens. right now and will not need them if my proposal is accepted

3) And here is the same example that don't work right now (no output, silent bug), but after my proposal will

loganfsmyth commented 8 years ago

@alexbyk Correct. If you add another layer of functions though

function log(){
    return (target, prop, desc) => {
      console.log(target, prop, desc)
    };
}

class Foo {
    @log
    method(){}
}

becomes

function log(){
    return () => {
        return (target, prop, desc) => {
            console.log(target, prop, desc)
        };
    }
}

class Foo {
    @log()()
    method(){}
}

which I'm saying is confusing, because now by adding one new function, you are required to add two new sets of parens.

alexbyk commented 8 years ago

@silkentrance Have you already written an answer to my exercise I asked you a few comments above? Could you show it? If you can't do it because you are so smart and thinking at meta-level only, that's ok.

alexbyk commented 8 years ago

@loganfsmyth yes. That's right. @log => @log()() really looks confusing if you treat @log like something callable. Let's add it to CONS.

But @log() => @log()() looks ok. And knowing that @log THING is actually @log() THING (we don't treat @log as function), I don't see problems

As I understand, you are against magic invocation without parentheses. It's common in coffescript, perl and some other languages, but not used in JS.

But that's because you are looking at the @log as something callable. If you look on it as a syntax sugar, @log isnt just log and makes no sense without "THING", so @log Class === log()(Class) and @log() Class === log()(Class) too, it will be ok and will look consistent.

But the big +1 to CONS is all decorators will look the same, don't need refactoring and you will be able to be used this way:

class Foo {
 @inj one;
 @inj two;
 @inj('THREE') three;
}

right now it's either impossible, or is buggy to implement @inj decorator that allows this

alexbyk commented 8 years ago

@loganfsmyth Also, I don't think someone ever wants to write makeDecorator with a spagetti of subfunctions that needs to be called as@log()()()()()()() THING because it's not usable and always can be rewritten, so the consistency problem isn't real in this case.

loganfsmyth commented 8 years ago

I feel like splitting this discussion between here and https://github.com/wycats/javascript-decorators/issues/23 is just coming to be confusing. Would you be willing to combine the discussions over there since it is the older issue?

silkentrance commented 8 years ago

@loganfsmyth and quoting "as the fallible human beings they are, rather than malicious entities",

This is where sarcasms comes in. I always consider humans to be fallable, I myself am, but being fallable and just ignorant and driven by some weird ambition are two different types of things, which I wanted to point out.

Regardless, you are right in your perception that #52 and #23 are the same issue, just as I pointed out in the first place. And there might be others...

alexbyk commented 8 years ago

issue moved here https://github.com/wycats/javascript-decorators/issues/23