, Richard.Hein wrote


Rx is more general than async/await and therefore has more applications.  Rx doesn't force you to decide if something is async or sync in advance.  The composition is the same regardless.  Rx applies to single or multi-values, and therefore has more power than async/await as it does not deal with mult-values. 

Rx shares the same pattern across many languages.  Async/await does not.  You can use Rx from any .NET language.  You can use Rx in JavaScript and the semantics and everything you learn about Rx from .NET applies to it except the specialized schedulers which vary depending on the implementation.   Learning Rx means you will be able to leverage it in any language (eventually) and also deal with asynchrony in any language - even C/C++ are getting Rx.  F# and Rx work very well together and show how simple Rx could be with language support. 

The complexity of Rx scales very well, because you can guarantee composability and you cannot do that with APM/TPM - you simply cannot because it's not obeying the fundamental rules of composition. Rx is built on mathematical rules of composition which can be expressed in many languages and there's no escaping having to understand these laws of composition for a programmer today.  You must understand these at some point to deal with complexity. 

That's not 100% true though is it? Side-effects can cross boundaries and wreak havoc. In queries involving well-tamed primitives it shouldn't be an issue though. IO is actually a very useful are to apply Rx - as you also imply below.

The limitations of C# is the problem with Rx, not Rx, in terms of complexity, as managing continuations seems to be a problem for large Rx compositions, as the number of arguments grows.  The code is inside out, but this is a simple matter of experience to grok, and everyone is capable.  There is also so many ways to write a complex composition in Rx that one can write horribly unreadable code in Rx which once refactored becomes a beautiful pearl.  There are code samples that show how Rx on the server can communicate with the client in just an absolutely simple pattern of LINQ queries, everywhere.

But what can I say, without code to back it all up?  Later, after work, I'll try to post a few examples of crappy Rx code versus beautiful Rx code and then perhaps we can really see where the complexity lies, and why Rx has this real/perceived level of difficultly that is a barrier to entry.

That pretty much states my point (perhaps you are not replying to me). I don't find Rx complicated to use - it eliminates a lot of complexity - but still do find the syntactic expression of Rx semantics not as nice as it could be.

As a purist (albeit a pragmatic one) I care about simplicity and cosmetics at every level but work with the popular tools as they are currently defined (and they have indeed improved a lot in recent times).

F# provides a means improve syntactic expression of Rx semantics but it doesn't feel like we've arrived at the "final destination" in terms of elegance yet - it's "just" ahead of the curve.

The pattern I show is just one more layer of unification; where additional semantics is added to model progress and status updates, where single and multi-valued asynchronous methods with cancellation were already modelled with Rx semantics.

It would also be useful if one could constrain an IObservable to a single-valued collection, either by type or (perhaps) by Code Contracts.