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

The difference between lastSetValue and resolve #417

Open
justinbmeyer opened this issue Jan 1, 2019 · 3 comments
Open

The difference between lastSetValue and resolve #417

justinbmeyer opened this issue Jan 1, 2019 · 3 comments

Comments

@justinbmeyer
Copy link
Contributor

justinbmeyer commented Jan 1, 2019

I think the following might be a useful addition to our documentation:

The difference between lastSetValue and resolve

Summary: getters maintain both a lastSetValue and a getterValue. These are used for different parts of write and read functionality.

Getters like the following often confuse people:

VM = DefineMap.extend({
  todoId: "number",
  todo: {
    get(lastSetValue, resolve) {
      console.log("re-calculating", lastSetValue);
      if(lastSetValue){
        return lastSetValue;
      }
      Todo.get({id: this.todoId}).then(resolve);
    }
  }
});

vm = new VM({id: 5});

It's important to understand that a property like todo actually houses two distinct values:

  • lastSetValue - TheVALUE that was last set like vm.todo = VALUE
  • getterValue - The value that was last returned by the get function or passed to resolve(). This is the result of reading the property like: vm.todo.

It's important to understand that calling resolve() with a value will not set lastSetValue. Instead, calling resolve() only changes the getterValue.

Lets see how this plays out with an example. The following sets todoId and binds to todo. When todoId changes, a different todo instance can be read:

vm.on("todo", function(){});
// logs: re-calculating undefined

// ONCE THE PROMISE RESOLVES
vm.todo //-> Todo{id:5}

vm.todoId = 6
// logs: re-calculating undefined
// ONCE THE PROMISE RESOLVES AGAIN
vm.todo //-> Todo{id:6}

Now, once todo is set, given the get above, vm.todo's getterValue will match lastSetValue even as todoId changes:

vm.todo = "HELLO THERE";
// logs: re-calculating "HELLO THERE"
vm.todo //-> "HELLO THERE"

vm.todoId = 7;
// logs: re-calculating "HELLO THERE"
vm.todo //-> "HELLO THERE"

vm.todo's __getterValue__ will match __lastSetValue__ even as todoId` changes, unless lastSetValue is set to false:

vm.todo = false;
// logs: re-calculating false
// ONCE THE PROMISE RESOLVES AGAIN
vm.todo //-> Todo{id:6}
@frank-dspeed
Copy link

@justinbmeyer why does resolve not update lastSetVal? i think still this is the expected behavior?

@justinbmeyer
Copy link
Contributor Author

justinbmeyer commented Jan 8, 2019

@frank-dspeed

why does resolve not update lastSetVal?

This would create a cycle in the graph of dependencies. It would change the get from a "map" to a "scan/reduce" (in observables speak). map is more simple. Effectively get is mapping the lastSetValue and other values read (ex: this.otherProp) to the resolved getterValue.

If resolve updated the lastSetValue, I would call the argument lastGetterValue. This would be similar to scan/reduce. This is useful for a variety of patterns, but so is map.

@justinbmeyer
Copy link
Contributor Author

An additional thing to document is that type, Type, Default, and default only operate on lastSetValue.

For example, the following will always return "22":

type: "number",
get() {
  return "22"
}

type: "number" is ignored because the getter returns "22".

However, lastSetValue will use type:

MyType = DefineMap.extend({
  num: {
    type: "number",
    get(lastSetValue) {
      return lastSetValue * 2
    }
  }
});

var inst = new MyType({});
inst.num = "4";
inst.num //-> 8

As Default and default are setting the lastSetValue, they will also go through type or Type.

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

No branches or pull requests

3 participants