Yes. But there was also a non-snapshot cycle.
Normally a cellloop / streamloop is constructing a forward reference to the actual output
. But in your case your feeding the new_output
stream back into output
which is defined in terms of output
.
Conceptually you have:
output = output.filter(...).filter(...)...
For the expression a.snapshot(b,...)
the snapshot protects you for a cycle through b
, because it is just calling sample()
on b
internally during transactions. But does not protect you for a cycle through a
.
So here is the devil in the original code:
let new_output = output.snapshot(&output_cell_loop.cell(),
Followed by
output_cell_loop.loop_(&new_output.hold(input.stream()))
That's where the cycle occurred. "CYCLE HERE".snapshot("NOT HERE",...).
Using defer can be kind of magic, you can change new into old.
Conceptually:
new_output = output.filter(...)
output_stream_loop.loop(Operational::defer(new_output));
Defer is like an old function (the stream before current transaction) "old(new_output) is output" --> "defer(new_output) is output".