**Problem:** Prior to this commit, existing implementations of computed values
are eager. An example is the `withComputedProperties` in odoo's web addon, see:
[^1]. It has an issue such that it can lead to triggering of the compute
function even if the target is still in invalid state -- e.g. removing an item
in an array. This can be solved by batching the recomputation with `batched`.
But once the compute is batched, the computed value can't be used by other
computed values, because it won't recompute until the next tick -- it's not part
of the same synchronous context.
**Proposed solution:** This commit introduces a implementation of computed value
that is pull-based -- it only recomputes when it's needed. The main logic is the
following:
- A computed value is declared with a single-parameter function wrapped with
`computed`.
- The compute function has a cache that stores the result of the computation.
- The cached value is invalidated when one of the dependencies of the compute
function changes.
- During invalidation, the cache is only marked as invalid and the
recomputation is not made.
- A dependent computation such as an effect may indirectly depend in the
dependencies of a computed value[^2]. This is an important detail because
without this, the 'laziness' of the computed value won't trigger the dependent
effect.
- This indirect dependency tracking is achieved by using the introduced notion
of multi-reactive target where a target can have multiple callbacks linked
to it.
- During recomputation of the computed value, both the target's reactive and
the invalidation callback are subscribed to the dependencies of the computed
value. But when the value is cached, only the target's reactive callback is
subscribed.
With this implementation, we achieve a lazy computed value that plays well with
the existing reactive system.
[^1]: https://github.com/odoo/odoo/blob/15d7cf12b98bf0223371b8cca91ef6f79c60ee31/addons/web/static/src/core/utils/reactive.js#L58
[^2]: It's possible that in the dependency graph, an effect is affected by
invalidation. This effect will be triggered which will potentially ask for the
value of the computed value which will trigger the recomputation.