Note reloaded into my rebuilt blog: I know the test code should be a unit test now! This was written over 13 years ago!
Supporting Re-entrant Event Publication: Why It is Significant
But this is something of an aside. Because in starting to look at the reasons
to explicitly support this, I found that the RX type
(in assembly "System.Reactive", namespace
has exactly the same behaviour as
Personally I feel that this behaviour will lead to inconsistent and unexpected ordering of events as seen by subscribers, depending on the order in which the observers subscribed and the details of the internals of the observable (what kind of collection is used to store the list of subscribers). This opens up the potential of races to subscribe with different timing leading to seeing out of order events.
One final note here, where I started drafting my implementation of
IObservable<T> I was not aware of
When I became aware of this type, I almost decided to give up on my own implementation.
With this discovery I am not rather glad I didn't.
The Test Code
In this the three subscribers (imaginatively named
sub2) all increment a count of subscriber calls, and all
print the same details to the console: which subscriber, the event value, the
total number of subscriber calls and the number of calls to the second subscriber
Additionally the second subscriber will raise an event itself, recursively publishing an event if the current value is 1≤i≤2 with value -1×i. Thus there is no more than a single level of recursion.
Sub 0 (1): sub1 called 0 times (total subscriber calls 1) Sub 1 (1): sub1 called 1 times (total subscriber calls: 2) Sub 0 (-1): sub1 called 1 times (total subscriber calls 3) Sub 1 (-1): sub1 called 2 times (total subscriber calls: 4) Sub 2 (-1): sub1 called 2 times (total subscriber calls: 5) Sub 2 (1): sub1 called 2 times (total subscriber calls: 6) END: sub1 called 2 times, all subscribers 6 times
As expected there are six calls to subscribers, with each subscriber seeing two events. But there is an oddity in the order in which the subscribers see events.
Not all subscribers receive the first event raised first,
sub2 receives event -1 before event 1: in
reverse order. But
sub0 sees them in order.
The only difference between the two subscribers is the
order in which they were subscribed relative to
Hence the comment above about a race-condition, and dependence
on the implementation of
Subject<T>. If a different
container were used the order in which subscribers are called could be
changed without any client code changing.
Clearly the ordering between subscribers is subject to the scheduler in use, but a single subscriber seeing events in a different order certainly could be a problem. This is exacerbated by the dependence on when the subscription is performed. A concurrent system could have the relative order of subscription subject to external factors (e.g. how many cores, how slow an assembly is to load, …).
This post is now long enough, so my solution to this will wait for part 4.