Frontmatter
| id | 242 |
| title | core.Base: state management using a modified getter |
| state | Closed |
| labels | enhancement |
| assignees | tobiu |
| createdAt | Feb 24, 2020, 6:18 PM |
| updatedAt | Mar 16, 2020, 12:49 PM |
| githubUrl | https://github.com/neomjs/neo/issues/242 |
| author | tobiu |
| commentsCount | 6 |
| parentIssue | null |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Mar 16, 2020, 12:49 PM |
core.Base: state management using a modified getter

The problem is in the queueing concept: https://github.com/neomjs/neo/blob/fe9804d8cd65da0da8a60e21514dda28331227b5/src/Neo.mjs#L583
Setting all the values, and then, in a separate run through, calling afterSet on each one?
That still doesn't help configs which depend upon other configs being fully set and postprocessed.
If the postprocessing of config a reads config z, and needs that z's afterSet has done its stuff, then that's a problem. The configs are still iterated in order. It will get the unprocessed value of z. Only having initGetters will fix this.
afterSet should be called right there after me[_key] = value
Also line 574 should be
if (me[beforeSet] && typeof me[beforeSet] === 'function') {
value = me[beforeSet](value, oldValue);
// If they don't return a value, that means no change
if (value === undefined) {
return;
}
}
Also, the object that you create in autoGenerateGetSet. It is the same for each key name. The property definition object for property foo in one class will be exactly the same as for another class. These can be cached statically and reused.

Hi Nige,
thanks for your input! I am not 100% sure about this part:
if (me[beforeSet] && typeof me[beforeSet] === 'function') {
value = me[beforeSet](value, oldValue);
// If they don't return a value, that means no change
if (value === undefined) {
return;
}
}
not having a return value inside a beforeGetXXX method is not supposed to happen.
in case it would, this could mean:
- keep the old value
- use the unprocessed new value
in theory you could even use return undefined; (not saying it is smart), which would then keep the old value.
those were my reasons not to do it so far. thoughts?
agree on
afterSet should be called right there after me[_key] = value
in case it does work out with the getters adjustment (well, this ticket is intended as a replacement for the queue).
If the postprocessing of config a reads config z, and needs that z's afterSet has done its stuff, then that's a problem. The configs are still iterated in order. It will get the unprocessed value of z. Only having initGetters will fix this.
see my examples above: i am still not 100% sure if this can resolve circular dependencies for beforeSet methods in a way that we always get the same results not related to the order. will create more tests once i have time.

The idea is eg
changeStartDate(newDate, oldDate) {
if (typeof newDate === 'string') {
newDate = DateHelper.parse('YYYY-MM-DD');
}
// Only return a value if it's a *valid* value (!isNaN) and is actually changed.
// undefined return value means the change is vetoed - the calling code returns early.
if (!isNaN(newDate) && (!oldDate || oldDate.valueOf() !== newDate.valueOf())) {
return newDate;
}
}

The value !== oldValue test here: https://github.com/neomjs/neo/blob/dev/src/Neo.mjs#L581
That won't work for more complex cases. For example dates. Two Date objects for the same date are unequal.

Hi Nige,
thx again for your input! I will create a new ticket for this one:
// todo: we could compare objects & arrays for equality
if (Neo.isObject(value) || Array.isArray(value) || value !== oldValue) {
I am trying to keep tickets granular to avoid sub-items getting lost.

guess we can close this one now (implemented).
pondering ticket.
instead of using the afterSetQueue, add a tmp. class prop to store the new config values object.
then modify the autoGen getters to check for this object first and in case it does exist use it.
instance.set() would then create this object, assign the values and delete it.
goal: make all new values available inside the beforeGetXXX methods as well, although circular references there feel a bit ambiguous for the new value.
a=1, b=2
beforeSetA(val) {return val + this.b;} beforeSetB(val) {return val + this.a;}these 3 ways will create different outputs:
inst.set({a:2, b:3}); // a=5, b=5