soney / constraintjs

Constraint library for JavaScript

Home Page:cjs.from.so/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Do not recompute if parent actually didn't change

QuentinRoy opened this issue · comments

I was thinking about a nice alternative to check_on_nullify.

check_on_nullify avoids invalidating the dependant constraints when the value of a constraint didn't changed. This may be very important when the processing of a constraint is quite resource consuming and thus should be avoided as much as possible.
However it requires the constraint to be re-evaluated, possibly heavy too, on each nullification while it may not actually be used.
It also mean that it is the responsibility of the parent constraint to know that the dependant constraints are resource consuming and should not be invalidated for nothing.

Here is a simple example:

var num = cjs(0);

var sign = cjs(function () {
    // heavy stuff
    console.log('compute sign');
    return num.get() ? num.get() / Math.abs(num.get()) : 0;
});

var signStr = cjs(function () {
    // heavy stuff
    console.log('compute string');
    return {
        '-1': 'negative',
        '1': 'positive',
        '0': 'null'
    }[sign.get()];
});

num = cjs(-5);
signStr.get();
// compute sign     -> OK: -1
// compute string   -> OK: 'negative'

num.set(-8);
signStr.get();
// compute sign     -> OK: still -1
// compute string   -> Whoops ! Recomputed for nothing!

I was thinking of a compromise.
There could be one more state to a constraint:
1- valid
2- invalid
3- maybe
A constraint could keep a list of its 'invalidators': the constraints responsible for its invalidation.
When a constraint is invalidated but not checked it puts its children into the 'maybe' state instead of invalidating them definitively.
When an invalidated constraint is computed, it checks if it really changed. If it did, it puts its children in the state of definitely invalid. However if it it didn't, it removes itself from the invalidators of its children. If the children has no invalidators anymore, it switches back to valid and do the same to its children and etc.
When a 'maybe' constraint is requested, instead of computing itself, it first checks its 'invalidators'. If during the process it switches to the invalid state, it computes itself. If not, it returns the cached value instead.