-
-
Notifications
You must be signed in to change notification settings - Fork 408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Decorators #408
Decorators #408
Conversation
Awesome work! This looks great. To me, the biggest risks are bringing back action namespacing collisions and requiring decorators to be invoked (e.g. Do we have a sense of whether any popular addons rely on subclassed |
@NullVoxPopuli one thing of confusion with language is:
This seems a bit confusing since "directly" here isn't super clear for those who aren't quite familiar with the spec or decorator syntax. I think a bit more explanation of this or moving it to be the first or last example of decorators. The grouping seems odd and a bit of a break and flow adding to some confusion. When I personally read the sentence I had to do a double take because I was like "wait you're saying I can't use Maybe this makes more sense in "drawbacks" or just more language around how |
Maybe better phrasing here would be:
|
? |
@NullVoxPopuli Generally, my experience is that it's better to avoid making claims about whether some functionality will be deprecated or removed, unless it's a deprecation RFC. Otherwise it's too easy for the RFC discussion to turn into a meta-RFC about removing the other behavior, instead of focusing on the benefits of the new behavior. |
Co-Authored-By: pzuraq <me@pzuraq.com>
We reviewed this RFC at the core team meeting today, and given the new language around decorators support and the TC39 stage system, we have consensus that this design is ready to enter Final Comment Period. |
Given that this has been in FCP for a week, we reviewed it again at the core team meeting today. The team is still in favor of moving forward, and there have been no additional comments since being moved into FCP: let's do it! |
Given that last week's TC39 meeting failed to advance decorators to stage 3, a follow-on RFC is probably necessary at this point |
I think a feature flag would still be reasonable :) afaik, the implementation allows the old syntax to work |
There will definitely be a followup RFC addressing this turn of events, along with our plans to mitigate them. Currently we don’t expect this will affect the path moving forward for Octane, as discussed in the RFC, decorators (or something that provides the same functionality) are a pretty hard requirement for us to move forward to native class syntax. This may push back the release of Octane, though we should still be able to preview them by EmberConf. |
I applaud all the thought going into this - and it's because I respect this effort so much, that I feel like I have to give another perspective / even though I don't feel any where near the caliber of folks on this thread.
Without knowing the beast or its belly, I certainly believe and respect all the history here. I did not mind the classic model syntax one bit, but I accept that I don't know enough about it to offer another option. I do wonder, were we bullied into this? Did this appease a portion of the prospective developers only to complicate the situation?
OK. All of these examples are clear / and not very fun ^. But the only option left as it seems / is also not very fun.
I can understand that this was added as a necessity - but I'd like to bring up that it's very clear and nice to use. It's not unlike the
I think this most definitely would be_ the case. Ember has always been ahead of game - but now that the game is afoot, it might be a good time to think about how abstraction might not be out nessesity - but for user benefit. As a user, I feel like Ember has been getting really really close to having an undeniably clear api - and that this is a few steps away from that. It's highly possible that I haven't seen the light yet / but after thinking about this for the last few days / I can't help but think that this is just super ugly. I'm a diehard / but my team is basically gone already.
I think that it's fair for a framework to assume that it's users know how it works. I've stumbled my way with Ember over the last 4 years / and not a JS guru - but I never named a function |
@sheriffderek so is your main concern about the lack of an I think my main concern with following Vue in that way is they don't seem to have a path forward to native class syntax with those types of features. I agree it would be nice to be able to arbitrarily organize and group some categories of things, but at the same time I think betting on native classes to be the future is very good bet. Frameworks will likely start to feel like they're aging when classes really become the standard in JavaScript in general, over the next few years. There may be ways to add that kind of scoping functionality back in the future with decorators, but we should probably wait and see to be sure. |
@pzuraq I guess my main concern is that this syntax along with tracked properties will scare off anyone interested in Ember. Like I said, I don't know enough about decorators - and have only used them a tiny bit to learn about them in a sandbox. Between this and typescript - it feels like things are always pushing the boundary farther then the average person really cares to go. I'm certainly glad it's getting pushed - but like a runway outfit, it usually gets dialed back for public use. My coworker wrote out a component in a few different frameworks syntaxes and put them next to each other. He kinda sighed and said - "I'm a developer. I don't care what's native syntax... I just want to be able to do my job." I always trust the decision process that you guys make - as far as what is 'best' / but just trying to add a voice that isn't so close to the project's core. It seems like decorators could live in the shadows like generator functions. They seem really powerful - but how we use them is really what matters. If it's all just a layer on a layer on a layer - of functions. I'm just making a case for whatever is easiest to read - but I know that's subjective. I'll use this CSS preprocessor mixin as an example. Which one would you rather write 100 times a day?
Also, imagine that you're writing 30 of these rules. hundreds of @import in the file. Do we write @action above every action? I'm loving my Octane experience so far, but when I got to using a service I ran into these decorators / and I'm stumped. Will we be able to opt out? |
I can't speak for @pzuraq , but here are some of my thoughts (also, thanks for sharing your concerns!):
from my point of view, I think it'll encourage people to try out ember, because it's a relatively thin layer on top of existing javascript.
Native syntax has some performance and cross-developer learning benefits.
With ESNext*, over time, this is less and less true, cause things are actually getting implemented in browsers / v8 / node. Super exciting! :D
depends on end-user needs.
this is a bit extreme. :)
in the future, with glimmer components (the future!)
Afaik, temporarily. The way I see it, when the current stuff is eventually deprecated and removed, the ember gzip payload size is going to get a lot smaller. :D |
As @NullVoxPopuli pointed out, classic class syntax will stick around for some time. And as he pointed out, this move really is about removing layers - in the long run, decorators will just be JavaScript. When you switch to a new framework from Ember, they'll use the exact same classes, similar decorators, and lots of the same features - and vice-versa. That's really the core idea here - every framework ends up reinventing the same core things for classes, computed properties, change tracking, etc. They just do it in slightly different ways. Native classes, and decorators, are a standardization at the language level, so in time, all frameworks and libraries will pick them up 😄 Ember is getting the jump on that by adopting now, but we won't drop classic class syntax any time soon. Also, I totally understand the pain of having to learn a new syntax/features, we're working on thorough guides to help out with learning and updating. I also understand the pain around having to annotate every function with export default class MyComponent extends Component {
@action
sayHello() {
console.log('Hello, world!');
}
} <button onclick={{this.sayHello}}>Say Hello!</button> |
@NullVoxPopuli & @pzuraq - Thanks for taking the time to answer. I get the rub here - for sure. I've always thought that getting closer to native JS was a good selling point / and reasoning. I've sold it to other developers that way when they were concerned about the extend - but now it's here! I can also see that as a detractor for some. This is probably a pretty accurate portrayal of how people are thinking about choosing things in real life: https://www.youtube.com/watch?v=OsBrp15zTIE - and in that vein, I could imagine them saying - 'yeah that's great, but we can just write a few decorators.' Developer ergonomics isn't something we talk about in the survey. I'll get some kool-aid and work on some realworld use of decorators and tracked properties - and see if I can come around. Are there any other good examples in the wild besides emberclear? I can learn a lot from that - but the typescript is another layer to understand. |
@sheriffderek did you read the comments on that video? :)
the ember community survey?
what do you mean?
all my octane apps/addons are in TypeScript. :\ @pzuraq do you have any? |
@NullVoxPopuli - RE comments on video: Yes. I read them. I'm not saying that that video has any value besides a window to a less invested 'coders' mindset. I see this attitude at a lot of the JS meetups. RE cool-aid: I'm just saying I'm going to try my best to learn to love these changes. I can write a webapp with only native JS / (or React or whatever) but then no one on my team would know how to use it. That's why we use Ember. We can count on a shared language. We're training a few Jrs and interns now with 3.7 brackets invocation etc. and it's going really well. I know this is a big shift that needs to happen, but If Ember changes the controls instead of the engine - then it's no longer doing what we chose it for. I've seen a lot of Ember organization like this: (this is just an example - copy and pasted from a few things to see the buckets a bit - not a working thing) So, I'm not saying "Well, Vue does x..." - more than I am curious about how creating a hash for something like actions - or computed - mirrors many people's mental model - and could also take away the need for a lot of the registration and this.get('prop') - type things in computed properties. I see uses in Ember where I don't want a props array like Vue, but it's also something that people can use to clearly see what is expected to come in. Just another example. I'm curious what the ideal interface would be - if there was nothing holding you back. Maybe decorators is it. Maybe there can be an experiment add-on that extends the class with a hash and - which simply drops @computed in front of every key in that hash. I don't know how that stuff works. I'm just a user. And as a user - this reminds me a lot of when Angular went from 1.5 to 2-3-4 or whatever it's at - and I went all in on Ember. Maybe I'm just scared. I'll work on an example with all the new syntax. A small component - and try and work into it. |
fwiw, everything is backwards compatible, which is our big advantage over the Angular 1 to 2 transition (at least initially, anyway -- they retroactively added backwards compat). If I convert your example to my ideal modern syntax, it'd look like this: interface IArgs {
info: any;
questions: any[];
}
// NOTE: @glimmer/component doesn't yet take a type arg, like sparkles-component does
export default class SomeComponent extends Component<IArgs> {
@storage game;
@storage settings;
@service('page-interface') page;
@service audio;
@alias('currentStep.stepType') stepType;
// state
@alias('game.currentIndex') currentIndex;
@equal('stepType', 'welcome') isStartPage;
@equal('stepType', 'end') done;
// tracked properties / auto-tracking -- no annotation needed afaik
get totalQuestions() {
return this.questions.filterBy('stepType', 'question').length;
}
get percentComplete() {
return this.totalAnswered / this.totalQuestions) * 100;
}
// private function, I think this is stage 3 of TC39?
#exampleFunction() {
}
setMenu(menuName) {
this.page.setMenu(menuName);
}
closeMenu() {
}
init() {
super.init(...arguments);
// init is mostly optional, depending on what you're doing
}
didInsert(element) {
}
willDestroy() {
}
} <div
...attributes
{{did-insert this.didInsert}}
{{will-destroy this.willDestroy}}
>
<button {{action this.exampleFunction}}>
click me
</button>
</div> though, to be fair, I think this component is doing waaay to much and should be broken up a bit.. :-\ but yeah, all that syntax should work today/soon, depending on ember version / canary, I think. |
@sheriffderek I totally understand the hesitation you're feeling to this change, it is a big shift to the framework and I can see why it might feel like the same type of shift as Angular 1-2. This new syntax is foreign, no matter what, and it will take some time to get used to. I don't want to try to convince you that the syntax is better or not - the reality is, it's mostly an aesthetic difference for end users. The wins in native classes are mostly performance based in the long term, and the Ember Object model is capable of most of the same things as native classes, which is how we're able to continue supporting the object model (funnily enough, the reason this is true is because the Ember Object model was so influential in the design of classes and decorators, so it all comes full circle a bit). We could keep doing this for some time, though I do believe that eventually native classes will start to gain functionality we can't support, like private class fields. The point is, you like it. New users may find it weird, or prefer native classes, but this syntax has served us well, served you well, so I get why it feels like we may be throwing the baby out with the bathwater. I want to point out two things that are different about this change than Angular 1-2:
I hope that helps make you feel better about all these changes. My ask, to you and to the entire community really, is to give the new features and mental model an honest try (when they are released in stable Ember) - convert a few components and classes. Take a look at how they work, and compare your code before and after. We can't debate and design these features in a vacuum, we need to actually try them out in production applications, at scale, to know whether or not they'll be successful. No matter how certain the core team is, it's entirely possible that we were wrong about things, we're only human after all. This is why we always introduce new features and let them be integrated into the community, battle-tested in production apps, and validated at scale, and then move to remove old features. If the new features don't work in practice, we can walk them back. If the old features still provide value, we can continue to support them. This is how we can achieve stability without stagnation 😄 |
We are going to use the computed decorator as a macro and polyfill to the Ember computed described in emberjs/rfcs#408.
This uses `computed` from `@ember-decorators/object`. This allow us to use computed as a macro in classic ember objects using `EmberOjbect.extend({ ... })` as well as a decorator when using classes. In the future, `@ember-decorators/object` would only serve us as a polyfill for older Ember versions as this is becoming the default behavior in Ember per [Decorators RFC](emberjs/rfcs#408)
We are going to use the computed decorator as a macro and polyfill to the Ember computed described in emberjs/rfcs#408.
This uses `computed` from `@ember-decorators/object`. This allow us to use computed as a macro in classic ember objects using `EmberOjbect.extend({ ... })` as well as a decorator when using classes. In the future, `@ember-decorators/object` would only serve us as a polyfill for older Ember versions as this is becoming the default behavior in Ember per [Decorators RFC](emberjs/rfcs#408)
We are going to use the computed decorator as a macro and polyfill to the Ember computed described in emberjs/rfcs#408.
This uses `computed` from `@ember-decorators/object`. This allow us to use computed as a macro in classic ember objects using `EmberOjbect.extend({ ... })` as well as a decorator when using classes. In the future, `@ember-decorators/object` would only serve us as a polyfill for older Ember versions as this is becoming the default behavior in Ember per [Decorators RFC](emberjs/rfcs#408)
Rendered
Big thanks to @pzuraq !!!