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

[BUGFIX beta] Observers after Dependent Key Change #11550

Conversation

mmpestorich
Copy link
Contributor

Currently when a property is overriden in an extended class and its
dependent keys change, observers watching that property will still fire for
changes made to the old set of dependent keys.

For example (http://emberjs.jsbin.com/nujofu/1/edit?html,js,output):

var count = 0;

var MyClass = Ember.Object.extend({
    prop1: 'foo',
    content: Ember.computed.alias('prop1'),
    incrementCount: Ember.observer('content', function () { count++; })
});

var obj = MyClass.extend({
    prop2: Ember.computed.alias('prop1'),
    content: Ember.computed.alias('prop2') // redefine content with diff depKey
}).create();

Ember.run(function() {
    obj.set('prop1', 'bar');
});

count === 1; // Should be 1; but in fact is 2

The problem is that iterDeps will loop over deps that no longer exist and invoke prop will/did change methods.

@mmpestorich mmpestorich force-pushed the v2.0.0-beta.1+canary+redefine-property-observer-fix branch from 3aab493 to 55d3109 Compare June 25, 2015 00:22
@rwjblue
Copy link
Member

rwjblue commented Jun 25, 2015

In general, the test case that is passing seems good to me, but I think this will need @stefanpenner and/or @krisselden to review in detail....

@@ -61,8 +61,8 @@ export function addDependentKeys(desc, obj, keyName, meta) {
depKey = depKeys[idx];
// Lookup keys meta for depKey
keys = keysForDep(depsMeta, depKey);
// Increment the number of times depKey depends on keyName.
keys[keyName] = (keys[keyName] || 0) + 1;
Copy link
Member

Choose a reason for hiding this comment

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

these counts exist for a reason, i don't believe we can binary enable and disable these without risking unsubscription for other listeners

@stefanpenner
Copy link
Member

something feels fishy

@mmpestorich
Copy link
Contributor Author

Initially that's what I thought but I couldn't find a single test that illustrated that. After tracing the code I can't see how that count could ever exceed 1. meta.deps is incremented and decremented when properties are setup and torn down at the time they're defined and no where else that I could find. keyName is the name of that property being defined and depKey is the name of a property that keyName depends on (the comment deleted above is wrong; depKey here doesn't depend on keyName... rather its the other way around). So how can you have a property that depends on the same key more than once? ... of course I could be missing something but that's what I took away from it earlier

@stefanpenner
Copy link
Member

i'll take some soon to do a thorough investigation. Little low on time right now.

@mmpestorich mmpestorich force-pushed the v2.0.0-beta.1+canary+redefine-property-observer-fix branch from 55d3109 to 2eb5730 Compare June 25, 2015 19:35
@mmpestorich
Copy link
Contributor Author

I made a couple more small changes and added another test so that redefining a property with dependent keys on the same object (versus a subclass) will properly fire property change events as well. Also because meta.deps is an inherited hierarchy of dependent keys for given key names it's not always safe to delete the keyName for a given depKey in removeDependentKey. I set it to false instead and use a guard in iterDeps to ensure disabled depKeys don't trigger change behavior (I still believe that it is safe to handle them in a binary fashion).

@rwjblue
Copy link
Member

rwjblue commented Jun 30, 2015

@stefanpenner - I'm gonna go ahead and assign this one to you since you mentioned you would like to dig into it a bit further before merging.

@stefanpenner
Copy link
Member

I'm gonna go ahead and assign this one to you since you mentioned you would like to dig into it a bit further before merging

👍

@krisselden
Copy link
Contributor

@stefanpenner if these test fail without this change, that would be very serious, it used to be that defineProperty() caused teardown if there was existing keys. I'm concerned that isn't the case anymore.

The counts seem to be handling the case of a dependent key being listed twice which seems weird. I'm not sure if that is important, but I would like to get these tests passing ASAP.

@krisselden
Copy link
Contributor

@mmpestorich it is simpler fix to just have iterDeps check the ref count, at some point during the various refactorings, iterDeps actually lost the guard that checked this. Most likely because of the reuse of a variable name that made it look like a redundant check.

@@ -179,6 +179,9 @@ function iterDeps(method, obj, deps, depKey, seen, meta) {
keys = keysOf(deps);
for (i=0; i<keys.length; i++) {
key = keys[i];

if (!deps[key]) { continue; }
Copy link
Contributor

Choose a reason for hiding this comment

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

this check is enough to pass the tests without the above no?

@mmpestorich
Copy link
Contributor Author

@krisselden Yes, that guard is enough to pass the tests... I'd be happy to remove the other if that will get this merged quicker, just let me know... (though I would still like to know the reason that the code allows for the same dependent key multiple times... doesn't make sense to me).

@rwjblue
Copy link
Member

rwjblue commented Aug 2, 2015

@mmpestorich - I'd happily merge the test + guard here.

I would still like to know the reason that the code allows for the same dependent key multiple times... doesn't make sense to me

Take a look at http://numberofpeoplewhounderstandembermetal.com. It doesn't make sense to me either, but lets fix your failure scenario first...

Currently when a property is overriden in an extended class and its
dependent keys change, observers watching that property will still fire
for changes made to the old set of dependent keys.

```js
var count = 0;

var MyClass = Ember.Object.extend({
    prop1: 'foo',
    content: Ember.computed.alias('prop1'),
    incrementCount: Ember.observer('content', function () { count++; })
});

var obj = MyClass.extend({
    prop2: Ember.computed.alias('prop1'),
    content: Ember.computed.alias('prop2') // redefine content with diff depKey
}).create();

Ember.run(function() {
    obj.set('prop1', 'bar');
});

// assert(count === 1); // Fails, should be 1 but in fact is 2
```
@mmpestorich mmpestorich force-pushed the v2.0.0-beta.1+canary+redefine-property-observer-fix branch from 2eb5730 to 75a7ba3 Compare August 6, 2015 20:36
@mmpestorich
Copy link
Contributor Author

@rwjblue updated to include just the guard + tests

rwjblue added a commit that referenced this pull request Aug 9, 2015
…-property-observer-fix

[BUGFIX beta] Observers after Dependent Key Change
@rwjblue rwjblue merged commit c0ce9f7 into emberjs:master Aug 9, 2015
@rwjblue
Copy link
Member

rwjblue commented Aug 9, 2015

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants