-
-
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
ES5 Getters #281
ES5 Getters #281
Conversation
If this is only for computed properties, I believe it adds another confusion since we need to use |
@rmmmp you won't have to use |
Since this is an RFC for the underlying Ember.Object this should also remove the need for |
A smattering of addons, some of which are popular, use I assume they would either have to change the way they work, or |
@rtablada if you mean let obj = Object.extend({
foo: inject.service()
}).create(); ...then yes, in this case you should be able to do I'll let the Ember Data folks chime in for the other part of your question. I think most of their public API would not require |
Just as a general note regarding @kategengler's #281 (comment): In the distant (?) future, we'd have Proxies. |
|
||
`this.get()` and `Ember.get()` will still work. This RFC does not propose | ||
removing or deprecating them in the near term. They support other use cases | ||
that ES5 getters does not, such as "safe" path chaining (`get('foo.bar.baz')`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the curious: Babel 7 will support optional chaining.
The way to think about this is: In today's world, every object that inherits from After this change, you would still be able to use In practice, what this means is that the handful of libraries that want to use For now, it would be reasonable for users to use |
Several additional points:
|
Is there a separate RFC that will be introduced which will replace: I dont like being a negative noodle, but it seems to me that as long as set() exists.. get() should also exist for consistency sake. That being said. I AM super excited to one day be able to set/get things with classic JS "dot style" |
@grapho does the "How We Teach This", "Drawbacks" and "Alternatives" section not answer your question? Besides the empirical evidence that other frameworks have the same API, you can also construct a principled explanation/mental model for this: reading data is always side-effect free, but mutations are by definition effectful. Therefore, it is a feature not a bug to explicitly call out these mutations, both for human understanding (something something "mutations are the root of all evil" ¯_(ツ)_/¯) and for Ember (so it knows to re-render your code). |
Another way to put this is that if the addon is using |
@chancancode good points! |
A quick search turned up a few examples:
Then there are many other JS APIs that use getters (as in Java-style
The point is, when interacting with third-party libraries (which an addon is) in JavaScript, sometimes you work with "plain properties", sometimes you are going through something like So, as long as those special objects (those that need to use As @buschtoens said, in the very long term, the community (not just the Ember community, but the wider JS community) will transition to use the native proxies and expose a more uniform API. Until then, in the rare cases where you need to implement proxies in user-land (which, like ES5 getters, are not shimmable), those objects would have to go through something like |
The RFC does not make clear how we will know when we will be able to use this. Is it available now? After all, we can access some properties now without |
@Gaurav0 I'm pretty sure this means for all computed properties specifically, which cannot be accessed without |
@Gaurav0 currently the mental model I would teach is "always use .get". after the feature lands, you will not need it in general, unless the library/addon tell you otherwise. As for timing, as always, it will be available when (and if) the RFC is merged, the feature is Go'ed by the core team and when it makes it all the way to the release channel. Might be available earlier on canary behind a flag for experimentation. |
I would love to see this implemented... ❤️ |
@sandstrom I think you pretty much answered your question yourself. 😛 IE's the only browser of interest that is dragging behind. Since it will never get Proxy support, we'd basically have to wait until Ember.js drops IE support completely. |
Can Ember utilize proxy-polyfill or does the polyfill not support enough of it to be worthwhile? I'm thinking ember-cli could include this based on targets. [Edit] Perhaps this is the limiting factor.?.
|
Since all of our [target browsers](https://github.com/emberjs/rfcs/pull/252) | ||
support ES5 getters now, we can drop the need of this special function, | ||
improving developer egornomics and interoperability between other libraries | ||
and tooling (such as TypeScript). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure it should be said here. But we can improve ergonomics of tooling such as TypeScript today with Ember.get
. And if we will able to pass an Array to Ember.get
like Ember.get(["some", "nested", "key"])
we would even have better ergonomics with TS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have tried in the past, and I am pretty convinced you cannot type an Ember object successfully today, even without considering nesting. You need to convince TypeScript that they are no properties on the object itself (so obj.foo etc are type errors) but when you do obj.get(“foo”)
or get(obj, “foo”)
it should have the right type. I have come close with using some phantom associated type tricks but I think it’s fundamentally impossible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For what it’s worth, you can, and we are... as long as you don’t do nested properties. It took a fairly ridiculous amount of work, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be precise: the types you end up with on the object itself end up having a type of ComputedProperty<TheType>
, which the type system then properly unwraps when using get
.
I am stoked about this RFC. When teaching people coming from other libs/frameworks, |
This RFC was nominated and approved for Final Comment Period (FCP) yesterday, since most comments have already been replied to. The FCP with last for a week. If there are any substantial new arguments that are brought up during this time, the FCP will be restarted (or aborted). If you haven't reviewed the proposal yet, now would be a great time to do so. If I may, here is a summary of the main objections:
Meanwhile, I am working on implementing this feature behind a flag (which can be done independently from progressing this RFC). Once the patch is merged, I'll comment on this thread so you can try the feature on Ember Twiddle, or with the canary build. |
It definitely is not intended (or public API), and |
@mike-north as mentioned in the RFC:
I have started working on that in #15992 |
Sounds great. But one question isn't cleared out for me yet. Perhaps it's obvious but I'm not sure about. How would that effect the need of consuming a computed property which should be observed? Would |
@jelhan It is not explicitly stated in the RFC, but the way I understand it, ES5 getters would basically trigger the exact same code the current You still have to pseudo-consume unconsumed observed properties in the init() {
this._super(...arguments);
this.myProperty;
} |
@buschtoens to clarify, did you mean ES5 getters? I think that's what the RFC is referring to |
@theseyi absoultely. I updated my comment, thank you. |
Hello! I implemented this feature (behind a flag). You can try this on canary now: https://ember-twiddle.com/7aded3d76fcc04867b426bf05f641388?openFiles=controllers.application.js%2C |
Thanks everyone for your participation! Since no major issues were found during the FCP, we will now close and merge this proposal. |
For what it's worth, I think it's important that we consider the developer experience of migrating to this flag an open issue that should be addressed during implementation. The most notable version of the problem is existing code using Ember proxies, and what kind of development mode experience we could use to help people who forget to use .get() on those objects. |
Implementation question related to my above comments on TypeScript—how does this interact with the use of class instance properties? import Service from '@ember/service';
import { computed } from '@ember/object';
class Neato extends Service {
bar = 'a string';
foo = computed('bar', function() {
return this.bar.length;
});
} Will the proposed (and already-initially-implemented) solution handle this correctly? Edit: experimenting with the Twiddle linked above suggests no: since class property instances are equivalent to running import Ember from 'ember';
const { computed } = Ember;
export default class extends Ember.Controller {
constructor() {
super();
this.appName = 'Ember Twiddle';
this.firstName = 'Godfrey';
this.lastName = 'Chan';
this.fullName = computed('firstName', 'lastName', function() {
let { firstName, lastName } = this;
return `${firstName} ${lastName}`;
});
this.preferFirstName = true,
this.preferredName = computed('firstName', function() {
return this.firstName;
});
this.displayName = computed('preferFirstName', 'preferredName', 'firstName', function() {
return this.preferFirstName ? this.firstName : this.preferredName;
});
}
} And when you drop that into the Twiddle, you'll see the the computed properties do not update as they should. 😢 |
Yeah, the issue there is that currently the getters get applied once when the class is first defined (in the I think the path forward for native classes and computed properties is using decorators, they're the only method we really have to modify the prototype of a class at this point (using just |
That is the conclusion I came to as I experimented bit last night. 👍🏼 Come on, TC39, give us that decorator goodness!
|
@chriskrycho since you're using TypeScript, why not just use decorators? |
@wycats It's a good suggestion. Unfortunately, the result of our experiments with the ember-decorators in TS has been that they don’t work because Babel and TS have different implementations; we'd need to completely reimplement the package. As a result, we've essentially just opted to wait on decorators until we get Stage 3 decorators and Babel's and TS's implementations converge. |
@wycats the main issue with decorators as they stand in Typescript is with class fields. Currently, there is no way to get the initializer for a class field in TS, so some of our decorators can't be made to work with it without breaking changes (specifically thinking of I think we can take another stab at TS compatibility once Babel finalizes the Stage 2 transforms, since we'll need to rewrite ember-decorators' internals a fair amount at that point. Ideally though we would wait for Stage 3 to avoid more churn/breaking changes. |
For those looking to test this out in their own apps, here's a regex that works for most cases of find/replace.
|
@mike-north - Hmm, I think it would be much better to use the codemod (which |
Also (as mentioned in the RFC) – it's not generally safe to replace all usages of |
@rwjblue I didn't know that existed, but have had bad luck with TS and jscodeshift |
@rondale-sc and I recently wrote codemod-cli, to make authoring code mods much easier (the goal being to author only the codemod and it’s expected inputs and outputs and let codemod-cli do all the heavy lifting glue code). One of the out of the box features is typescript support. This allowed us to update ember-qunit-codemod to “just work” for typescript files. We should do the same for es5-getter-ember-codemod... |
Rendered