CombineLatest and withLatestFrom are both and-style combination operators. The next one we're going to see is zip, which works in a rather intuitive fashion. It combines the first value from foo with the first value from bar to make the first of the output. Similarly, the second of foo with the second of bar to produce the second of the output observable.
Let's write that down, just as a guideline. The first value of foo plus the first value of bar will be used to produce the first value of the output. Then, similarly, the second of foo with the second of bar will make the second of the output. In general, the Nth of foo with the Nth value emitted by bar will be used to produce the Nth of the output.
This rule is strict with zip. It doesn't combine the second with the third. That doesn't happen. It only does in this order, Nth, Nth, Nth.
That means that when we see zero being emitted here on bar, that's the first one on bar, but foo has not yet, at this point, emitted the first one. It waits until both of them have emitted their first, and then we can combine them together. Zip also takes an argument here, which is the combination function.
All of these and-style combinator operators, they take this argument. Zero plus zero would be zero. Then, the second value from bar plus the second value from foo would give us one plus one, two. Then, two plus two is four, and three plus three is six.
Now, the bar completed. It means that it will be impossible for bar to emit a fifth value here in the future. While foo does emit a fifth value, bar cannot ever do that, so it's safe to conclude that it will complete here. It will complete because simply nothing will happen anyway, since you can't combine the fifth of foo with any fifth of bar. It just doesn't exist.
Now, if we run this code, it does exactly what we draw there, "02, 4, 6," and complete. Also, like the other operators, this is the instance version of zip. You can also use the static version, Rx.Observable.zip. You give the two observables, foo and bar, and it still does the same thing.
The idea behind zip is really like a zipper in clothes where you're matching each of these teeth to their respective parts. In general, I would not recommend using zip as often as you think that you're going to need it. It's actually not that common that you need to explicitly use zip.
In general, I recommend that if you have a problem where you want to combine two observables, you generally need combineLatest or withLatestFrom. As we're going to see later, you can also use flatMap.
The reason why is that sometimes foo may emit here in the middle. Let's say it emits X here. What you want to happen is that three would be combined with three, but just because we have a mismatch here in the amount of elements, X will be combined with three. Then, you start getting inconsistencies.
Often, zip is not that used, but there are some cases where it's used, and I can show you one of them. Let's say you have an observable here that says, "Hello." It emits five values, one for each of these characters. It does all of this synchronously. If we draw that, it does all of this synchronously and then completes.
Then, we have bar here, which can, let's say, emit five of these. It would emit four. Then, what we want to do is since this is happening synchronously, let's say you want to have each of these letters emitted every 400 milliseconds. With zip, you can do this. You can get the X coming from foo and the Y. Just drop down the Y, and you can just use the X.
Basically, what that gives you is then you're combining the first of foo with the first of bar, and you're just returning the first from foo, which gives you "h." Then, the second from foo and bar will give you "e," "l," "l," and "o."
This is generally how you get an observable that runs synchronously, and you just spread it over time by combining it in a zip style with an observable that happens over time and not synchronously.
Let's see how we can do that. We need to just return X from here. Then, once we run this, we see "h-e-l-l-o" happening like we want it to. That's the most important and-style combinators in RX.