1

Feel free to correct my history, but as far as I understand it, Rx and the Reactive Manifesto trace their roots back to C# and its Reactive Extensions, which is uses push (callback-based) messaging, so that Publishers call Subscriber methods with values, rather than returning values to a subscribing scope like an iterator. This is a bit surprising, seeing as C# has very mature and strong iterator mechanics like LINQ, not to mention it birthed await-async, which is distinctly pull.

I'm designing a Reactive Library in Hacklang, and while for the question of which style is more fundamental, the message-driven camp might have it — you could say that CPS is message-driven, or that the scheduler is really a message relay, and I could see your point — I don't really see the benefit.

Hack tightly embraces the async-await model. One consequence is that pushing messages asynchronously is actually exceptionally difficult. Almost all asynchronous objects are designed to be awaited and produce a value dependency, so it is hard for any code to set and forget a callback that it doesn't depend on.

However, it has actually been a joy to program with iterators, not a hindrance. At its core is the AsyncGenerator, which comes from yielding [read: lazy] async functions. They are iterated by a foreach-like construct (await as), so that means the "subscriber" or calling scope can break out whenever it wants, ask for elements whenever it wants, try-catch, throw, return its own pending values, become an iterator — anything the language allows synchronous code to do. This level of subscriber freedom, especially requesting elements at will sounds like the direction Reactive Streams is going, which is indicative to the problems it solves. With iterators, though, it's baked-in from the start.

Returning to C#, with its already impressive suite of iterator mechanics, why did it opt for callbacks for Reactive Extensions? Did their decision set the stage for the push to dominate? Is there a distinct performant, familiar, expressive, etc. reason for the prevalence of push messaging in Reactive?


Edit: Ah, InteractiveX was the name of the concept I was looking for: replacing IObservable with IEnumerable. It is indeed more obscure — the ReactiveX organization only publishes a JS implementation — and if I understand Bart de Smet's presentation about Ix back in 2011, some operators aren't implemented "interactively" even, but rather are achieved by converting to IQueryable, building the expression tree, and back to IEnumerable to iterate.

Maybe due to equivalence, just one of ReactiveX vs. InteractiveX was good enough? Maybe it is unnatural to work with? Bart de Smet mentions the ISubject <-> IBuffer dual, which I found enlightening. There isn't much documentation outside of his talk which doesn't discuss much about the motivations, so I'm still taking shots in the dark a bit.

  • What you are talking about is generally call pull vs. push model for messaging. In your pull scenario, what happens when consumer is processing a message and source produces new one? Is it dropped? Buffered? Where is the buffer? Is this baked into the library, or is it something programmer needs to think about? How are multiple clients for single source handled? No clients for source that is producing messages? Does source need to know it has any clients? – Euphoric Apr 16 '17 at 16:16
  • @Euphoric All of those questions have multiple answers in ReactiveX as well depending on what the source is, and so that's not really related to my question. I intend to treat it similarly. For full disclosure though, in my impl: a) it's buffered, d) the producer holds the buffer cloned among subscribers, e) sure they have to think about it in high-memory cases, but I think the handling can be more elegant, f) every source is hot, g) no clients = no next, so with lazy, nothing happens, h) not usually, but it could by listening on clone and next calls. – concat Apr 16 '17 at 17:49
  • @Euphoric if pull is considered a form of message passing though, I may need to refine my question to ask why the push model is so prevalent instead. I just always assumed messages meant callbacks from how common it was... – concat Apr 16 '17 at 17:56
  • Your answer is confusing. On one side, you are saying every source is hot. On the other you are saying source is buffered. And that source doesn't need to know it's clients. I don't think those can work together. If source is hot and no client is "waiting" on next, how do you know if to buffer? And how is the buffering handled in case user-coded client calls user-coded source? – Euphoric Apr 16 '17 at 18:33
  • 1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.