Channels have this high-level notion as they can simplify a lot when doing data-binding - they have this bi-directional mechanism and operators that let you build a network of synced channels.
But sometimes you get in contact with the inner workings where things can get more tricky. I have a solution for you that still is high-level and elegant, but if you don’t know about it, banging your head is very relatable.
The solution:
ChannelIOvsHoldLatest.vl (36.2 KB)
It uses a validator which makes sure that the spread gets fixed before even pushed.
Why is it not a bug?
A network of channels that are linked to each other via Select (ByPath) where everything shall sync in all directions is realized internally by a protection mechanism that makes sure that events spread through the network freely in all directions, but still you never end up with an endless cascade of events.
Everything happens immediately. Like with observables or events.
So if A triggers and B and C react on value 1 immediately, it’s still B that reacts first - someone has to. If B would be allowed to trigger again and push value 2, A and C would react on that immediately and after that, let’s not forget, C would react on the initial push “immediately” - value 1.
So the protection mechanism not only makes sure that it’s impossible to get an endless chain reaction, but we also avoid situations where the order of events gets nonsensical.
The protection mechanism works like this: Don’t allow push to a channel that currently propagates changes. Well, it accepts those values but doesn’t fire further events. The problem with your patch is that it tries exactly that: pushing to a channel as a reaction to a push to the channel.
The solution that I posted solves two issues:
- You never get a spread that is not allowed - in your case two slices true
- You don’t need to react on a channel in order to fix it and push back. You don’t need to reason about a channel with valid spreads and another channel that allows intermediate values, which need to get synced
Just as a side note, if the validator idea wouldn’t be in place:
A less elegant solution could have been to do certain things on update and not as immediate reaction. Checking the Value of the channel and when wrong pushing a fixed version.
In general, working with channels can trick you into too much event-based thinking. I for myself like to sometimes do stuff on update if possible, reading the current Value and working with that if possible. In a way, Channels are a hybrid of the Reference and the Observable types and both ideas are valid: having a current value always available, being able to change it and being able to react immediately.
My take on it: event-based thinking can be harder than update-based/declarative/data-flow thinking that we all are more used to - thankfully.
BTW: what you saw in the IOBoxes was probably just the dirty version and the fixed spread never made it to the HoldLatest (Reactive), as it never got pushed.