Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zip operator doesn't work properly for more than 2 streams #824

Closed
jachnik opened this issue Oct 4, 2018 · 4 comments · Fixed by #828
Closed

Zip operator doesn't work properly for more than 2 streams #824

jachnik opened this issue Oct 4, 2018 · 4 comments · Fixed by #828

Comments

@jachnik
Copy link

jachnik commented Oct 4, 2018

Bug for versions Versions 4.1.0 and 4.1.1

The code posted below causes the following exception:

Sequence contains no elements

var stream = Observable.Return(1);

var stream2 = stream.Zip(stream, stream, stream, (a, b, c, d) =>
{
       return a + b + c + d;
});
var i = stream2.ToTask().GetAwaiter().GetResult();

Zipping of 2 streams works fine.

As Shlomo on StackOverflow pointed out, if you re-define stream as such:

var stream = Observable.Return(1).Delay(TimeSpan.FromMilliseconds(15));

then the operator works as intended.

@jachnik jachnik changed the title N-wise Zip operator doesn N-wise Zip operator doesn't work properly Oct 4, 2018
@jachnik jachnik changed the title N-wise Zip operator doesn't work properly Zip operator doesn't work properly for more than 2 streams Oct 4, 2018
@quinmars
Copy link
Contributor

quinmars commented Oct 8, 2018

For reference, the mentioned SO question can be found here:

https://stackoverflow.com/questions/52654306/problem-with-zipping-more-than-2-observable-sequences

@quinmars
Copy link
Contributor

quinmars commented Oct 8, 2018

The problem is that the queue of the ZipObserver gets cleared, when the sequence completes, although the queue is still needed:

Commenting out the _values.Clear() line in Dispose() would make the tests of #827 pass, although it's good idea to clear them when all sequences are done. I think the easiest way would be to partially revert #635 and reinsert the nth disposable of the disposables array in the Zip.Run method :

 disposables[3] = Disposable.Create(() =>
                {
                    _observer1.Values.Clear();
                    _observer2.Values.Clear();
                    _observer3.Values.Clear();
                });

see:

https://github.com/dotnet/reactive/pull/635/files#diff-9e17b95d856736d153ecd78c6876ec83L71

@quinmars
Copy link
Contributor

quinmars commented Oct 8, 2018

Hm, #828 looks even more simpler. 😊

@danielcweber
Copy link
Collaborator

danielcweber commented Oct 9, 2018

On an abstract level, we might run into this type of problems anywhere, where an Observer inherits from SafeObserver and overrides Dispose. For immediate sources, when we did everything with SingleAssignmentDisposables, the order of execution was obviously different then. I'll give it a review. Thx @akarnokd for investigating this.

Update: Zip is indeed the only operator that uses a SafeObserver inherited class which overrides Dispose. When #828 gets merged, there are none at all and we might consider removing the virtual modifier on Dispose so we don't run into that issue in the future. @akarnokd Any thoughts ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants