Rework damage propagation and handling #1
Loading…
Reference in New Issue
No description provided.
Delete Branch "redamage"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
We say that the graph is damaged when it changes in the middle of evaluation. In certain cases though this is acceptable, if the change is not observable.
Imagine the following combinator:
It takes an integer variable and an expression and increments the variable each time the expression is evaluated, returning its value unchanged. In general, this combinator is not well-behaved: it changes the graph during its evaluation. The result depends on the evaluation order of
expr
andcounter
.To detect these ambiguities, the current implementation maintains a
damaged : bool
field inLwd
nodes, to detect if a node has changed in the current update cycle.However this was an conservative approximation: if any effect was detected during evaluation, the graph was considered ambiguous. The new implementation accepts graph if there is a strict ordering between read and write effects.
join
now allows the outer computation to have effects that impacts the inner one.map2
is now evaluated left-to-right (inmap2 f t1 t2
,t1
is evaluated beforet2
). Assumingt2
is not used elsewhere in the graph (there are no aliases outside), thent1
is allowed to perform effects that can invalidatet2
.Make reasoned use of this property. Relying on the ordering of effects is a bad practice in general, and not really in the spirit of
Lwd
; yet, it enables efficient implementation of a few specialized operations.Example: sharing constraints and cutting-off evaluation
Imagine we want to make a list of widgets that are constrained to all have the same width.
This definition will produce the right
Ui
but has a performance bug. When a single element of the table changes, the width is updated and the final layout is entirely recomputed.An
O(1)
change (a single item) turns into ano(n)
recomputation (layout of each item).What we would like is a cutoff operator: if after recomputation the width value is the same, we can skip the relaying-out the table. However a performant cutoff operator is tricky to implement and can have surprising runtime characteristics.
The evaluation and damage-resilience of
join
let us implement a good one:Which can be used as follow:
Here is a possible implementaition:
And the corresponding
list_same_width
:When using
cutoff
, one can observe that there are two continuations:continuation
argument,bind
ing on the returned value.Only computations in
continuation
will be filtered, computations in the return continuation will be recomputed as usual.The new implementation
Damages are safe if they touch a part of the graph that has not been observed yet, as defined by the left-to-right evaluation order of
map2
,app
andpair
and outer-inner evaluation ofjoin
andbind
.If a part of the graph that has always been observed is damaged:
sample root
returns normally,is_damaged root
returnstrue
,sample
will reevaluate the damaged part of the graph.