Yes. I agree with the fact that the intuitively best argument order of the decorator would be dependent on its context (as a class decorator or property decorator). I understand the difficulty of this design decision. Since it is pretty challenging (if not impossible) to determine how the community will use this decorator, I doubt if that criterium should be taken into account for your design decision here. Perhaps the choice should be mainly based on other criteria, like usage consistency, expected future usage (regarding TypeScript and JavaScript evolution), internal scalability in Aurelia, etc. Anyway, to me, as a TypeScript-oriented developer, I would prefer property decoration over class decoration, and thus - together with the consistency argument - the current order (newValue
, oldValue
, instance
) does seem to be the most logical choice to me. Unless it is already known that this choice would complicate any important future design choices in Aurelia.
I also agree with the static
issues. It was just a question. Using singletons would be a design choice as well, and a very valid one in the Aurelia architecture. IMHO, it would probably be better to avoid using static
stuff as much as possible.
For the source expression issues (if they would be important for me as an Aurelia consumer), instead of this:
class App {
counter1 = 0;
counter2 = 0;
@watch(abc => abc.counter1)
@watch(abc => abc.counter2)
log(newValue) {
// which expression triggered me???
}
}
… I could just as easily do something like this:
class App {
counter1 = 0;
counter2 = 0;
@watch(abc => abc.counter1)
logCounter1(newValue) {
// log counter 1
this.log(newValue, 'counter1');
}
@watch(abc => abc.counter2)
logCounter2(newValue) {
// log counter 2
this.log(newValue, 'counter2');
}
log(newValue, expressionName) {
// Great, I now know who triggered me.
}
}
… or with a class decorator:
@watch(abc => abc.counter1, (newValue, oldValue, app) => app.log(newValue, 'counter1'))
@watch(abc => abc.counter2, (newValue, oldValue, app) => app.log(newValue, 'counter2'))
class App {
counter1 = 0;
counter2 = 0;
log(newValue, expressionName) {
// Great, I now know who triggered me.
}
}
… if it is necessary. Perhaps it would be more straightforward to handle specific logic in the logCounter1
and logCounter2
methods themselves.