Skip to content
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

Deprecate Computed Overridability and .readOnly() #369

Merged
merged 5 commits into from
Oct 26, 2018

Conversation

pzuraq
Copy link
Contributor

@pzuraq pzuraq commented Aug 31, 2018

their native counterparts.

The main and most notable difference this RFC seeks to deprecate is computed
clobberability. There are some other notable differences, including the caching
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered other terms instead of "clobber"? Maybe

  • replace
  • override

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

override seems like a more explanatory term without context. Maybe also overload. I'll update the language of the RFC

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be easier to just put a dummy term in there for now. Naming is hard, but very important in this case

@pzuraq pzuraq changed the title Deprecate Computed Clobberability and .readOnly() Deprecate Computed Overridability and .readOnly() Aug 31, 2018
@mike-north
Copy link
Contributor

mike-north commented Aug 31, 2018

I really like this proposed change! Yet one more place where we're adjusting defaults to set as many developers and use cases as possible up for success.

decorators

have we considered this ⬇️ option for stuff that chains off of the return of Ember.computed() like .readOnly() or .clobberable()?

@computed.foo.bar
get myProp() { }

Personally, I find something like this to be less readable

@foo
@bar
@computed
get myProp() { }

@rwjblue
Copy link
Member

rwjblue commented Aug 31, 2018

have we considered this ⬇️ option for stuff that chains off of the return of Ember.computed() like .readOnly() or .clobberable()?

@computed.foo.bar
get myProp() { }

Yep, @pzuraq and I discussed this yesterday actually. I think our conclusion was something like what you wrote:

@computed('first', 'last').thing()
get name() {}

@NullVoxPopuli
Copy link
Sponsor Contributor

👍 yay! 😄

@pzuraq
Copy link
Contributor Author

pzuraq commented Aug 31, 2018

To expand on that, we definitely want to add .readOnly() to ember-decorators today to match existing computed semantics. What is more of an open question is whether we should add .overridable() when we remove .readOnly(). On the one hand, as you pointed out it is easier to read, but on the other hand its somewhat orthogonal to decorator composability.

Consider the computed macro @and. It really is providing 2 things:

  1. A caching layer (the same one as @computed)

  2. A getter which looks like:

    get [key] { 
      return this[depKey1] && this[depKey2];
    }

The fact that these two things ended up together is kind of a historical accident, because the easiest way to define and use a macro was through creating a computed property. With decorators though, that changes, we can fairly easily compose functionality like caching, notifying, and macros. In the future, we're going to introduce a new system based around references, @tracked.

Now, unfortunately with the current state of computed macros, there won't be an easy way to use @tracked with macros without incurring the cost of @computed. If we were to separate out these two functions into separate decorator systems though, it could look something like this:

class Foo {
  @computed @and('bar', 'baz') foo;
  
  @tracked @and('bar', 'baz') foo2;
}

The definition of the macro itself is separate from the meta information (caching provided by @computed, notifications provided by @tracked). This also has the benefit that the macro system would no longer be tied to Ember in any way - it could be a generic JS decorator library.

In the case of @overridable, it would provide a self-destructing setter function which would be composable with any macro which provides a getter function. That said, this is more about the future of computed macros (and even further out, @tracked and how we'll adopt that system) so I think adding .overridable() would also make sense, and we could consider redesigning it whenever we do reimplement macros for the @tracked world.

@pzuraq
Copy link
Contributor Author

pzuraq commented Sep 1, 2018

@mike-north I actually just went over the spec again and realized we're more limited than I thought. Decorators can only be chains of properties with one final call at the end:

// valid
@foo
@foo.bar
@foo()
@foo.bar()
@(foo().bar)
@(foo().bar())

// invalid
@foo().bar
@foo().bar()
@foo()()

This is going to affect readOnly and volatile too unfortunately 😕

@mike-north
Copy link
Contributor

This syntax is still valid. Remember we're just capturing dependent keys and flagging the property in some manner to indicate readonly-ness. We only need to capture arguments once

class {
   @computed.volatile.readOnly('firstName', 'lastName')
   get fullName() {
		...
   }
}

There are some very popular projects that have chaining like this, albeit in a conventional function call instead of a function that returns a decorator.

@balinterdi
Copy link

@pzuraq Thank you for putting this together.

While we still can't just use ES classes and decorators in Ember (or can we already?) how would we replace the following if this RFC gets implemented (since it would deprecate computed overridability):

  showErrors: computed('_showErrors', {
    get() {
      return this._showErrors || { email: false, password: false };
    },
    set(key, value) {
      this.set('_showErrors', value);
      return this._showErrors;
    }
  }),

(The transition path shows an example but it uses an ES class.)

Thank you.

@pzuraq
Copy link
Contributor Author

pzuraq commented Sep 1, 2018

Hey Balint, the example you posted would be perfectly valid since the computed property provides a setter. What would not be valid is this:

const Foo = EmberObject.extend({
  showErrors: computed('_showErrors', {
    get() {
      return { email: false, password: false };
    }
  })
});

let foo = Foo.create();

foo.set('showErrors', { email: true, password: true }); // Throws an error because `showErrors` does not have a setter

Does that make sense?

@balinterdi
Copy link

@pzuraq Yes, it does and I then wholeheartedly support this RFC :) Thank you.

@Gaurav0
Copy link
Contributor

Gaurav0 commented Sep 10, 2018

I don't object to the spirit of this RFC, but I need to point out that this is a breaking change and will likely mess up poorly written legacy apps. I strongly advise that we throw a deprecation warning when calling set() on a computed property without a setter, and then make them readonly by default in 4.0.

This unfortunately means we need to continue to clobber during the 3.0 lifecycle.

@pzuraq
Copy link
Contributor Author

pzuraq commented Sep 10, 2018

@Gaurav0 that was the original intent of this RFC, but the deprecation aspect of it was only implied by the title and the summary. I'll add an extra section to the Transition Path section to clarify that the transition would follow the standard deprecation path for breaking changes, showing a warning until v4.0.0

deprecation warnings:

1. When users invoke the default override-setter behavior
2. When users call `.readOnly()` on a computed property
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we deprecate this, users have no way of getting a hard error (not a deprecation warning) when they clobber without getting deprecation warnings by using readOnly.

I recommend only deprecating .readOnly() in the 4.x era. Yeah, like I said, this is a pain.

Copy link
Member

@rwjblue rwjblue left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The core team met today and discussed this, we are in favor of moving this forward into final comment period.

If you haven't read through the RFC just yet, now is a great time to check it out!

a deprecation warning will be thrown if a user attempts to set a
non-`readOnly` property which does not have a setter. User's will still be
able to declare a property is `readOnly` without a deprecation warning.
* Add optional feature to change the deprecation to an assertion after the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We chatted about this today in the core team meeting, and decided to try to leverage svelte here instead of an optional feature. This doesn't change the timeline at all here, just the verbiage.

Can you tweak this from Add optional feature to When the application is configured with svelte, the deprecation will be an assertion?

@rwjblue rwjblue added Final Comment Period T-framework RFCs that impact the ember.js library labels Oct 5, 2018
@rwjblue rwjblue self-assigned this Oct 7, 2018
@rwjblue rwjblue merged commit a5bbf98 into emberjs:master Oct 26, 2018
buschtoens pushed a commit to ClarkSource/ember-css-modules-config that referenced this pull request Apr 3, 2019
Bumps [ember-source](https://github.com/emberjs/ember.js) from 3.8.0 to 3.9.0.
<details>
<summary>Release notes</summary>

*Sourced from [ember-source's releases](https://github.com/emberjs/ember.js/releases).*

> ## v3.9.0-beta.5
> ### CHANGELOG
> 
> - [#17733](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17733) [BUGFIX] Assert on use of reserved component names (`input` and `textarea`)
> 
> ## v3.9.0-beta.4
> ### CHANGELOG
> 
> - [#17710](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17710) [BUGFIX] Allow accessors in mixins
> 
> ## v3.9.0-beta.3
> ### CHANGELOG
> 
> - [#17684](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17684) [BUGFIX] Enable maximum rerendering limit to be customized.
> - [#17691](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17691) [BUGFIX] Ensure tagForProperty works on class constructors
> 
> ## v3.9.0-beta.2
> ### CHANGELOG
> 
> - [#17618](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17618) [BUGFIX] Migrate autorun microtask queue to Promise.then
> - [#17649](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17649) [BUGFIX] Revert decorator refactors
> 
> ## v3.9.0-beta.1
> ### CHANGELOG
> 
> 
> - [#17470](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17470) [DEPRECATION] Implements the Computed Property Modifier deprecation RFCs
>   * Deprecates `.property()` (see [emberjs/rfcs#375](https://github.com/emberjs/rfcs/blob/master/text/0375-deprecate-computed-property-modifier.md)
>   * Deprecates `.volatile()` (see [emberjs/rfcs#370](https://github.com/emberjs/rfcs/blob/master/text/0370-deprecate-computed-volatile.md)
>   * Deprecates computed overridability (see [emberjs/rfcs#369](https://github.com/emberjs/rfcs/blob/master/text/0369-deprecate-computed-clobberability.md) 
> - [#17488](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17488) [DEPRECATION] Deprecate this.$() in curly components (see [emberjs/rfcs#386](https://github.com/emberjs/rfcs/blob/master/text/0386-remove-jquery.md))
> - [#17489](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17489) [DEPRECATION] Deprecate Ember.$() (see [emberjs/rfcs#386](https://github.com/emberjs/rfcs/blob/master/text/0386-remove-jquery.md))
> - [#17540](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17540) [DEPRECATION] Deprecate aliasMethod
> - [#17487](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17487) [BUGFIX] Fix scenario where aliased properties did not update in production mode
</details>
<details>
<summary>Changelog</summary>

*Sourced from [ember-source's changelog](https://github.com/emberjs/ember.js/blob/master/CHANGELOG.md).*

> # Ember Changelog
> 
> ### v3.9.0-beta.5 (March 25, 2019)
> 
> - [#17733](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17733) [BUGFIX] Assert on use of reserved component names (`input` and `textarea`)
> 
> ### v3.9.0-beta.4 (March 11, 2019)
> 
> - [#17710](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17710) [BUGFIX] Allow accessors in mixins
> 
> ### v3.9.0-beta.3 (March 4, 2019)
> 
> - [#17684](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17684) [BUGFIX] Enable maximum rerendering limit to be customized.
> - [#17691](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17691) [BUGFIX] Ensure tagForProperty works on class constructors
> 
> ### v3.9.0-beta.2 (February 26, 2019)
> 
> - [#17618](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17618) [BUGFIX] Migrate autorun microtask queue to Promise.then
> - [#17649](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17649) [BUGFIX] Revert decorator refactors
> 
> ### v3.9.0-beta.1 (February 18, 2019)
> 
> - [#17470](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17470) [DEPRECATION] Implements the Computed Property Modifier deprecation RFCs
>   * Deprecates `.property()` (see [emberjs/rfcs#375](https://github.com/emberjs/rfcs/blob/master/text/0375-deprecate-computed-property-modifier.md)
>   * Deprecates `.volatile()` (see [emberjs/rfcs#370](https://github.com/emberjs/rfcs/blob/master/text/0370-deprecate-computed-volatile.md)
>   * Deprecates computed overridability (see [emberjs/rfcs#369](https://github.com/emberjs/rfcs/blob/master/text/0369-deprecate-computed-clobberability.md) 
> - [#17488](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17488) [DEPRECATION] Deprecate this.$() in curly components (see [emberjs/rfcs#386](https://github.com/emberjs/rfcs/blob/master/text/0386-remove-jquery.md))
> - [#17489](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17489) [DEPRECATION] Deprecate Ember.$() (see [emberjs/rfcs#386](https://github.com/emberjs/rfcs/blob/master/text/0386-remove-jquery.md))
> - [#17540](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17540) [DEPRECATION] Deprecate aliasMethod
> - [#17487](https://github-redirect.dependabot.com/emberjs/ember.js/pull/17487) [BUGFIX] Fix scenario where aliased properties did not update in production mode
</details>
<details>
<summary>Commits</summary>

- [`8df20e9`](emberjs/ember.js@8df20e9) Release v3.9.0
- [`2b9ee17`](emberjs/ember.js@2b9ee17) Add v3.9.0 to CHANGELOG
- [`bfe670c`](emberjs/ember.js@bfe670c) Bump router_js
- [`2f8b8ba`](emberjs/ember.js@2f8b8ba) [DOCS beta] remove component nesting docs
- [`0270001`](emberjs/ember.js@0270001) Release v3.9.0-beta.5
- [`1e2672c`](emberjs/ember.js@1e2672c) Add v3.9.0-beta.5 to CHANGELOG
- [`37d0a11`](emberjs/ember.js@37d0a11) Fix docs test
- [`86999a7`](emberjs/ember.js@86999a7) Post-cherry-pick lint fixup
- [`fff729a`](emberjs/ember.js@fff729a) [DOC RouteInfo] Fix grammar, spelling, and formatting
- [`b179dfd`](emberjs/ember.js@b179dfd) added param "name of the block" for the API document of has-block and has-blo...
- Additional commits viewable in [compare view](emberjs/ember.js@v3.8.0...v3.9.0)
</details>
<br />

[![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=ember-source&package-manager=npm_and_yarn&previous-version=3.8.0&new-version=3.9.0)](https://dependabot.com/compatibility-score.html?dependency-name=ember-source&package-manager=npm_and_yarn&previous-version=3.8.0&new-version=3.9.0)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
If all status checks pass Dependabot will automatically merge this pull request during working hours.

[//]: # (dependabot-automerge-end)

---

**Note:** This repo was added to Dependabot recently, so you'll receive a maximum of 5 PRs for your first few update runs. Once an update run creates fewer than 5 PRs we'll remove that limit.

You can always request more updates by clicking `Bump now` in your [Dependabot dashboard](https://app.dependabot.com).

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
- `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme

Additionally, you can set the following in the `.dependabot/config.yml` file in this repo:
- Update frequency (including time of day and day of week)
- Automerge options (never/patch/minor, and dev/runtime dependencies)
- Pull request limits (per update run and/or open at any time)
- Out-of-range updates (receive only lockfile updates, if desired)
- Security updates (receive only security updates, if desired)

Finally, you can contact us by mentioning @dependabot.

</details>

[//]: # (dependabot-no-ci-start)

---
⚠️ **Dependabot won't automerge this PR as it didn't detect CI on it** ⚠️ 

You have automerging enabled for this repo but Dependabot didn't detect any CI statuses or checks. You can disable automerging on this repo by editing the `.dependabot/config.yml` file in this repo.

[//]: # (dependabot-no-ci-end)
@webark
Copy link

webark commented Jun 25, 2019

@pzuraq did the overridable computed macro ever get into an addon somewhere?

@pzuraq
Copy link
Contributor Author

pzuraq commented Jun 25, 2019

It did not, but it should be relatively easy to write to interop with something like macro-decorators. I don't think it'd be easy to write to interop with @computed, unfortunately, due to the mandatory setter.

@pzuraq pzuraq deleted the deprecate-computed-clobberability branch June 25, 2019 22:46
@alexlafroscia
Copy link
Contributor

alexlafroscia commented Sep 24, 2019

I ended up building an overridable macro as an addon here:

https://github.com/alexlafroscia/ember-overridable-computed

It doesn't support being used as a decorator yet, but I'll do that eventually!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Final Comment Period T-framework RFCs that impact the ember.js library
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants