During the last weeks I took some time to have a first look at the Reactive Framework. Here I want to share some impressions and information with you.
Rx: What is it about?
The Reactive Framework (Rx) has been developed at the Microsoft Live Labs and is another creation by Erik Meijer, the father of LINQ. Rx will be part of the upcoming .NET Framework 4.0, but is already included as preview DLL (
System.Reactive.dll) in the sources of the current Silverlight 3 Toolkit. It’s used there to get some smoother Unit Tests to work.
The aim of Rx is to simplify/unify complex event-based and asynchronous programming by providing a new programming model for those scenarios. That’s very important in a world which becomes more and more async (Web, AJAX, Silverlight, Azure/Cloud, concurrency, many-core, …) and where present approaches (event-based programming with .NET events, Begin/Invoke) hit the wall. Program logic gets hidden in a sea of callback methods which leads to nasty spaghetti code. Those of you who are creating larger async programs know what I mean 😉
The main concept of Rx is reactive programming and that’s not new at all. It involves a distinction of data processing methods into push and pull scenarios:
- In a pull-scenario your code/program is interactively asking for new data from the environment. In this case the actor is your program while it pulls new data from the environment.
- In a push-scenario your program is reactive. The environment in pushing data into your program which has to react on every new incoming data item (see illustration below). Reactive programs are ubiquitous: every event-handler (e.g. for UI events) is an example for a reaction in a push-scenario.
The guys at Microsoft got a very important insight which builds the fundament of Rx: there’s a dualism between the Iterator and the Observer pattern! This means that both patterns are essentially the same, if you dismiss their practical intentions for a moment.
With the Iterator pattern you get a sequence of data which is iterated in the pull-mode: the Iterator is the actor and asks the iterable object for data.
The Observer pattern can be interpreted equivalently: the environment pushes data into your program (e.g. through events), which has to react. As result with repeatedly fired events you get a sequence of data, which makes the relationship to the Iterator pattern obvious.
With this, an Observer in the push-scenario is equal to an Iterator in the pull-scenario and that’s the key insight, which has led to the development of the Reactive Framework. 14 years had to pass from the publication of the GoF Design Patterns book until now to figure out this intense relationship of the Iterator and the Observer pattern.
LINQ to Events
Rx realizes the Observer pattern with the two interfaces
IObservable which are the pendants for
IEnumerable of the Iterator pattern.
IObservable is a sort of „asynchronous collection“, which represents the occurrence of a certain event at different points in time. Thus it expresses a sequence of data, on which you can run arbitrary actions. In fact
IObservable for push-scenarios is essentially the same as
IEnumerable for pull-scenarios.
The interplay of
IObserver is the following: on an
IObservable you can register (
IObserver (Note the dualism to
IEnumerator here!). The
IObserver has three methods
OnError(). These methods are invoked when the
IObservable gets new data, completes the data sequence or results in an error. Thus your
IObserver implementations take care of the data processing which replaces your custom callback methods.
The real impressing thing with Rx is that with events as data sequences you can use LINQ syntax to process and transform these data sequences (that’s why it’s sometimes called LINQ to Events). To create instances of
IObservable and for providing LINQ methods, Rx comes with the class
Observable. If you want for example take the first 10 click events on a button but skip the first click, you could easily write:
Observable.FromEvent(button1, "Click") .Skip(1) .Take(9) .Subscribe(ev => MyEventAction(ev));
Subscribe() has some overloads. In this example I’ve directly specified an action which is executed when an event (= a piece of data) comes in. Instead you could give it e.g. your custom implementations of
IObserver as well.
LINQ gives you real power in processing, composing and transforming your events as data stream. Even in the simple example above, if you would implement it by event-based programming without Rx, you would need some additional effort. You would have to use temporary variables to skip certain elements, take others and so forth. In general, more complex cases require complete finite state machines which can be circumvented with Rx.
Composing events with LINQ is another typical and impressing example for Rx. Thus, a dragging event on a textblock can be implemented as:
IObservable<Event<MouseEventArgs>> draggingEvent = from mouseLeftDownEvent in Observable.FromEvent(textBlock1, "MouseLeftButtonDown") from mouseMoveEvent in Observable.FromEvent(textBlock1, "MouseMove") .Until(Observable.FromEvent(textBlock1, "MouseLeftButtonUp")) select mouseMoveEvent; draggingEvent.Subscribe(...);
In this example, with the
from keyword the two events
"MouseMove" are chained together. Everytime the left mouse button is pressed on the textbox, the „gate“ opens to react on mouse move events. The „gate“ closes again when the left mouse button is released. So the composed stream includes all events where the left mouse button is pressed and the mouse is moved – the typical dragging event!
There are other possibilities to compose events, which for example consider the order of events differently. Those build the interesting parts of the Reactive Framework and clarify the use cases, where Rx has real advantages over present event-based .NET programming.
Personally I like the new way of thinking of events as data sequence! The dualism of the Iterator and the Observer pattern has nothing artificially constructed, but some sort of purity and mathematical elegance for me. But one big question remains: do we need this in our everyday’s developer life and which advantages come with it?
Erik Meijer himself says about Rx:
Of all the work I’ve done in my career so far, this is the most exciting. […] I know it’s a bold statement, but I really believe that the problem of asynchronous programming events has been solved.
That’s a really strong message and it has some important weight since Erik is the creator of LINQ and has a big expertise in language design. Does Rx hold what he promises?
In my opinion Rx is really beautiful and valuable when you do complex asynchronous operations, where you have to compose and orchestrate events/data from several sources. With Rx you’re able to chain and filter events to easily create the concrete event, to which you want to react. That’s the power of LINQ, which allows transforming the resulting data as well. LINQ gives you the whole flexibility of processing the data stream that you already know from LINQ to Objects (on
Beyond that at the moment I don’t see a real big impact in many current development scenarios. If you have to handle simple events or do simple async computations, you are still fine with the present event-based programming model. Of course with Rx you can write your own observers to prevent a sea of callback methods, but encapsulation of handler logic can be done without that as well. Thus at the end I like the concepts of Rx (Observer, LINQ, …) and I’m curious to see how this whole thing develops after the release of .NET 4.0, but I’m not over-enthusiastic at the moment.
Finally here is a list of links to some interesting websites regarding the Reactive Framework:
- Lang.NET – Live Labs Reactive Framework
- Channel9 – Inside the .NET Reactive Framework (Rx)
- Channel9- Inside .NET Rx and IObservable/IObserver in the BCL (VS 2010)
- Channel9 – Reactive Framework Under the Hood Part1
- Channel9 – Reactive Framework Under the Hood Part2
- unfold – Introducing Rx (Linq to Events)
- unfold – The Joy of Rx: Extension Events
- unfold – The Joy of Rx: The Event-Based Async Pattern vs. IObservable
- unfold – The Joy of Rx: Building an Asynchronous API…
- Paul Batum – Reacting to the Reactive Framework Series