Publishers.CombineLatest may lose values if all upstreams complete while its Subscriber is doing work

I believe I have discovered a nasty issue in the implementation of Publishers.CombineLatest; This reproduces as of iOS 14 beta 4.

This simple gist demonstrates the problem: CombineLatest.swift · GitHub

What happens is that B emits a value and also completes while A's thread is still busy doing work. This final value from B is lost/discarded and CombineLatest directly completes once A's thread finishes its work.
This gist showcases this race by dramatically widening its window.

I understand that CombineLatest guarantees "eventual consistency", in the sense that some buffered values may get discarded in favor of recent ones, but this is not it -- this is pure data loss as I expect CombineLatest to emit a final value with the respective final values of A and B before itself completing.

This gist boils down a very common pattern that many apps implement -- combining completing Publishers (e.g. network requests) together into a computation that may be expensive. The fact that, depending on scheduling, a Subscriber is not guaranteed to receive the final values of all upstream Publishers makes the CombineLatest operator deeply flawed.

4 Likes