Switching to a new source is published as two changesets rather than one: a set of removals for what the previous source contributed, and then whatever the new source publishes when it is subscribed to.
Cache/Internal/Switch.cs, roughly:
using (var scope = queue.AcquireLock())
{
sourceId = ++activeSourceId;
if (current.Count != 0)
{
scope.EnqueueNext(/* removals for everything the old source contributed */);
current.Clear();
}
}
subscription.Disposable = source.SubscribeSafe(...);
The removals are enqueued, and then the subscription to the new source happens. If subscribing causes an immediate publication of the items already in that source, which it normally will, those arrive as a second changeset.
That breaks the general rule of one frame, one changeset. A subscriber sees the collection empty out and then refill, rather than a single changeset carrying the removals and the additions together. Anything binding to the result gets a visible flicker, and anything counting changesets sees two where it should see one.
The same is true of the implementation currently on main, which does destination.Clear() in a Do on the outer sequence before PopulateInto sees anything from the new source, so this is long standing rather than newly introduced.
Raised from review on #1137, where the observation was that the fix belongs in its own change rather than being folded into a completion fix.
The list Switch has the same shape and would want the same treatment.
Switching to a new source is published as two changesets rather than one: a set of removals for what the previous source contributed, and then whatever the new source publishes when it is subscribed to.
Cache/Internal/Switch.cs, roughly:The removals are enqueued, and then the subscription to the new source happens. If subscribing causes an immediate publication of the items already in that source, which it normally will, those arrive as a second changeset.
That breaks the general rule of one frame, one changeset. A subscriber sees the collection empty out and then refill, rather than a single changeset carrying the removals and the additions together. Anything binding to the result gets a visible flicker, and anything counting changesets sees two where it should see one.
The same is true of the implementation currently on
main, which doesdestination.Clear()in aDoon the outer sequence beforePopulateIntosees anything from the new source, so this is long standing rather than newly introduced.Raised from review on #1137, where the observation was that the fix belongs in its own change rather than being folded into a completion fix.
The list
Switchhas the same shape and would want the same treatment.