Rx Framework Part I - System.Reactive or the .NET Reactive Extensions (Rx) – Concepts and First Look

By Anoop Madhusudanan

Vote on HN

Recently, a lot of interest is bubbling up in the .NET community about reactive programming. This weekend I played around with this, and created a couple of POCs to get a feel. And I'm loving everything. Reactive extensions (Rx) is really cool, as it introduces lot of new possibilities. The .NET Rx or .NET Reactive extensions (System.Reactive.dll) recently appeared in the latest Silverlight tool kit drop. 

.NET Rx introduces two interfaces, IObservable and IObserver that "provides an alternative to using input and output adapters as the producer and consumer of event sources and sinks" and this will soon become the de-facto for writing asynchronous code in a declarative manner. Also, .NET Rx gives greater freedom to compose new events – you can create specific events out of general events. Let us see these aspects in a bit more detail.

Push and Pull Sequences

Here is a quick recap on Reactive programming - Consider a small example, result = var1 + var2. In a normal scenario, we expect the value of result to be independent of the variables, var1 and var2. Later the values of var1 and var2 might change, but the value of result may remain the same as it was at the time of the initial assignment.

But in a reactive scenario, the value of result is dependant on one or more of the variables we used to compute it’s value. i.e the value of, result would change or evolve over a period of time, based on the changes that might happen to var1 or/and var2.

Event based programming and asynchronous call backs are existing ways of doing Reactive programming in .NET. Consider how you handle a simple MouseMove operation in .NET using an event handler. Let us take a step back, and examine this a bit closer - The mouse cursor’s location value is changing over a period of time, and an event notifies you about that – or the source is pushing the value to you.

image

You may see the data we receive from these events as pieces of data that your event handler (the target) receive from a source over a period of time – a sequence. Also, you may instantly notice that the same is happening when you iterate over a collection, probably using a for loop. In that case too, you are receiving values from a source over a period of time, you are pulling the data. In both cases, the target is receiving the pieces of data from a source over a period of time, the difference is that the program is either pulling the data (a pull sequence) or the source or environment is pushing the data to the program (a push sequence).

What’s cool about .NET Rx?

.NET Rx team (this is not an official name) found that any push sequence can be viewed as a pull sequence as well – or they are Dual in nature. So this also means, there is a Duality between Iterator pattern IEnumerable/IEnumerator (pull) and Observable pattern (push) IObservable/IObserver.

So what is cool about about this duality? Anything you do with Pull sequences (read declarative style coding) is applicable to push sequences as well. Here are few aspects.

  • You can create Observables from existing events, enumerables etc  and then use them as first class citizens in .NET – i.e, you may create an observable from an event, and expose the same as a property.
  • As IObservable is the mathematical dual of IEnumerable, .NET Rx facilitates LINQ over push sequences like Events, much like LINQ over IEnumerables
  • It gives greater freedom to compose new events – you can create specific events out of general events.
  • .NET Rx introduces two interfaces, IObservable<T> and IObserver<T> that "provides an alternative to using input and output adapters as the producer and consumer of event sources and sinks"

If you want to dive a bit more deep in to this, watch this video where Eric Meijer explaining this duality. .NET Rx provides various extension methods for creating observables from Events, Enumerables etc.

Turning Events to Observables

The FromEvent method in System.Linq.Observable class will create an Observable, from  an event. This example shows how to create a observer for the Mouse left button down event, for a given control

  var mouseLeftDown=Observable.FromEvent<MouseButtonEventArgs>
          (mycontrol,"MouseLeftButtonDown");

The above example uses the following FromEvent extension method overload, in the Observable class

        public static IObservable<Event<TEventArgs>> 
	 	FromEvent<TEventArgs>(object target, string eventName) 
			where TEventArgs : EventArgs;

Now, as the event is an observable, we can subscribe to the same

mouseLeftDown.Subscribe
 (arg => Console.WriteLine(arg.EventArgs.ButtonState.ToString()));
Also, another overload for FromEvent exits in Observable class to convert an event to an Observable.
public static IObservable<Event<TEventArgs>> FromEvent<TDelegate,
                    TEventArgs>(Func<EventHandler<TEventArgs>, 
                             TDelegate> conversion, 
                             Action<TDelegate> addHandler, 
                             Action<TDelegate> removeHandler) 
			    where TEventArgs : EventArgs;

You may use this overload for explicitly specifying the event argument type and event handler type, and to enable compile time verification for the event name. Like,
 var mouseLeftDown= Observable.FromEvent<MouseButtonEventHandler, MouseButtonEventArgs>
                (   h => new MouseButtonEventHandler(h), 
                    h => el.MouseLeftButtonDown += h, 
                    h=> el.MouseLeftButtonDown -= h
                 );
Please notice that the type of mouseLeftDown is IObservable<Event<MouseButtonEventArgs>>. And as we discussed above, it is very much possible to use the mouseLeftDown variable they way you need. For example, you may pass mouseLeftDown to this method, where we again abstract out another Observable  just for the points, and subscribe to the same – and note that we use LINQ to do the same.
  
public void SubscribePoints
          (IObservable<Event<MouseButtonEventArgs>> mouseEvents)
{
	var points = from ev in mouseEvents
				 select ev.EventArgs.GetPosition(this);
	points.Subscribe(p => this.Title = "Location ="
                                     	+ p.X + "," + p.Y);
}
 

Further Reads

Shout it
© 2012. All Rights Reserved. Amazedsaint.com