Desynchronization downstream of combine
See original GitHub issueI have an issue where I combine two streams, then make a new object. I then branch from that stream into two others, and it’s important that the values in the two streams must originate from the same object. This has to do with the other libraries I’m using, but I also think it’s the expected and intended behavior. Instead, the two streams end up looking at different objects because they’ve received different signals.
A simple illustration of the problem is below. Note that Math.random()
is a stand-in for creating a new object that the signals in streams x and y both must originate from. As an example of why this is important, consider if the object is a new data entity that comes with a randomly-generated UUID; clearly x and y must agree on what that UUID is.
Expected behavior:
- Both x and y fire every time ab fires.
- xy emits the value “true”
Actual behavior:
- ab fires, then only x fires, then ab fires, then only y fires.
- xy emits the value “false” since x and y received different signals.
const a = xs.of('a');
const b = xs.of('b');
const ab = xs
.combine(a, b)
.map(([a, b]) => Math.random())
.debug('ab');
const x = ab.map(o => o).debug('x');
const y = ab.map(o => o).debug('y');
const xy = xs
.combine(x, y)
.map(([x, y]) => x === y)
.debug('xy');
xy.addListener({
next: e => console.log(e)
});
Issue Analytics
- State:
- Created 3 years ago
- Comments:16 (6 by maintainers)
Top GitHub Comments
I can rephrase that statement: “So every module of code you write should understand exactly how every stream that gets passed in is constructed, since that will affect its behavior”. That breaks the entire point of abstraction. Say I wrote a function:
I could reasonably complain if this function sometimes works and sometimes doesn’t, depending on whether
x
was computed from a multiplication operation instead of addition. And you could come back to me and say: well, of course it works that way, if you just understood how our library works! Multiplication changes the bit-parity of the mantissa in the underlying pseudo-binary representation, and addition doesn’t! Haha, see, you’d understand if you weren’t so stupid!And I would say: okay, well, this function has no way to check the bit-parity of the mantissa of the pseudo-binary representation, and besides, that’s way outside of the scope of what
number
is supposed to represent. That’s the definition of a leaky abstraction.So when I write
and ask: why doesn’t this always work? Why can
numbers
emit a value that the stream returned by this function never sees? And you come back and say: well of course it works that way, whennumbers
is downstream of a combine of two streams that are not temporally independent! You’d understand that if you weren’t so stupid!And I say: okay, well, this function has no way to check if the
numbers
stream is downstream of a combine of two streams that are not temporally independent, and besides, that’s outside the abstraction of what I thought aStream
was supposed to be.I understand the technical reasons why it’s occurring in this case. But it is a flaw. It may be a theoretically necessary flaw, one that’s not feasible to fix without causing other problems, and/or one you can work around if you completely change your coding style, but it’s still a flaw. Don’t act like this is some sort of stupid question.
I belive everthying works as expected.
You can add this:
With this you make
ab
stream never complete and keep the latest value for the late subscribery
.