It’s the most wonderful time of the year: a new version of the Silverlight Toolkit has been released alongside Silverlight 3. This release of the Toolkit has a lot of goodies including a new TreeMap control, a Rating control (written by yours truly), and a useful collection of extensions methods for TreeView. That said this post is not really about the Toolkit. Buried deep in the bin folder of the Silverlight Toolkit Unit Tests is a hidden gem: The Rx Framework (System.Reactive.dll). If you glanced quickly you’d miss it altogether but it’s one of the most exciting additions to the .NET framework since Linq.
Stating the Obvious: Asynchronous Programming is Hard
Developers tend to avoid asynchronous programming if possible because it makes our programs non-deterministic and obscure our code’s intent in a sea of callbacks. However the truth is that asynchronous programming has become an essential part of application development. Client apps have always needed to use asynchronous methods to keep the user interface responsive. As a matter of fact Silverlight developers don’t have any choice in the matter because Silverlight doesn’t include any blocking IO calls. Connected apps also need to take advantage of asynchronous programming to improve scalability. Mashups, apps cobbled together from web services, often need to retrieve data from multiple sources in a particular order.
Clearly we need to write asynchronous code to create modern, connected applications, but how to do it in such a way that our code remains clear and maintainable?
Introducing the Rx Framework
The IEnumerable Interface
We’re all familiar with the IEnumerable interface. Almost every collection implements it and we use it every time we write a foreach. Most of us are also pretty comfortable using Linq to query IEnumerables. Linq is a series of extension methods used to manipulate sequences. Here’s a simple example:
int[] numbers = new int[]{20,31,5,16,22}; IEnumerable<int> numbersSmallerThan20 = numbers.Where(number => number < 20);
The resulting numbersSmallerThan20 sequence looks like this when visualized:
5, 16, break
In addition to finite sequences it can sometimes be useful to create sequences that never end. Take this method that returns an infinite sequence of integers:
IEnumerable<int> NaturalNumbers() { int number = 0; while(true) { yield return number; number++; } }
When visualized this sequence looks like this:
0,1,2,3,4,5,6…
Enumerable’s are sequences of data that we pull from a data source. We don’t always pull data though. Often it is pushed onto us and we must react appropriately. This is called “Reactive Programming.”
Reactive Programming
Reactive programs are ubiquitous. We use reactive programming every time we register a handler with an event or a specify a call back for an asynchronous operation. In this example I register a handler for the mouse move event of a button. The handler prints out the location of the mouse when it is called.
button.MouseMove += (o, mouseEventArgs) => Debug.Writeline(“You moved the mouse to {0}”, mouseEventArgs.GetPosition(button));
“You moved the mouse to 20,3”
“You moved the mouse to 33,12”
“You moved the mouse to 44,18”
Another form of reactive programming is running an asynchronous method and passing it a callback method to invoke when it’s finished. This is how we keep our programs responsive during long-running operations. Here’s an example:
DownloadFile(“http://www.jeffwilcox.com”, (byteArray) => Debug.WriteLine(“This file is {0} bytes long.”, byteArray.Length);
“This file is 12323 bytes long.”
We’re all used to doing reactive programming by specifying methods that are called at unpredictable times, but what if there was a different way to think about reactive programming? What if we thought of each piece of data passed to a reactively-called method as an item in a sequence?
Events and Callbacks are Sequences of Data!
The data passed to event handlers and callbacks can be thought of as sequences of data that are “pushed” at you rather than “pulled.” Every time an event is fired we get “pushed” a new piece of data: the EventArgs. Similarly when a callback is invoked it is typically “pushed” the result of the asynchronous method. You can think of an event as a sequence of EventArgs that never ends just like the NaturalNumbers sequence. If you were to visualize the mouse move event as a sequence it would look like this:
new MouseEventArgs(new Point(20,3)), new MouseEventArgs(new Point(33,12)), new MouseEventArgs(new Point(44,18))…
Similarly the asynchronous DownloadFile method can be viewed as a “push” sequence of data with only one entry:
new byte[]{23,211,33,23…}, break
The Rx team has discovered that pull sequences and push sequences are “dual.” That is to say, any operation you can perform on “pull” sequences can also be performed on “push” sequences. This is quite a revelation. To put things in perspective it’s been 13 years since Design Patterns was published and we’ve only now realized that the Observable pattern and the Iterator pattern are actually the same pattern.
Although reactive “push” sequences are fundamentally the same as “pull” sequences the IEnumerable interface can’t be used for reactive sequences because it blocks. We need a new interface with non-blocking methods that correspond exactly to the blocking methods on IEnumerable. We need…
The IObservable/IObserver Interface
Despite the fact that they may look somewhat different on the surface the IObservable/IObserver pair of interfaces are the non-blocking equivalents of IEnumerable/IEnumerator.
To help you understand how they are equivalent let’s take a look at a simple example of traversing a pull sequence. You enumerate an IEnumerable by requesting an IEnumerator. As you call MoveNext the IEnumerator “pulls” data from the IEnumerable, usually by invoking its methods.
IEnumerator<int> numberEnumerator = new int[]{1,2,3}; while(numberEnumerator.MoveNext()) { Debug.WriteLine(“{0}”, numberEnumerator.Current); } Debug.WriteLine(“all done.”);
This prints:
1 2 3 all done.
To traverse an IObservable you go through the same actions as an IEnumerable but in reverse. You create an IObserver, give it to an IObservable, and the IObservable “pushes” data into the IObserver by invoking its methods. When an IObservable invokes the “OnNext” method on an Observer it is equivalent to an IEnumerable method using the yield keyword to give information to an IEnumerable. Similarly when an IObservable invokes the “OnCompleted” method on an Observer it is equivalent to an IEnumerable using the break keyword to indicate that there is no more data.
Let’s define a NumbersObserver which converts a “pull” sequence of numbers into a “push” sequence as well as an observer that listens to our NumbersObserver and prints its contents.
internal class AnonymousDisposable : IDisposable { internal Action Action {get; internal set;} void IDisposable.Dispose() { this.Action(); } } class NumbersObservable : IObservable<int> { public NumbersObservable(IEnumerable<int> numbers) { this._numbers = numbers; } private IEnumerable<int> _numbers; public IDisposable Subscribe(IObserver<int> observer) { foreach(int number in _numbers) { observer.OnNext(number); } observer.OnCompleted(); return new AnonymousDisposable { Action = () => { ; // do nothing because we’ve already called OnCompleted() } }; } } class DebugObserver : IObserver<int> { public void OnNext(int value) { Debug.WriteLine(“{0}”, value); } public void OnCompleted() { Debug.WriteLine(“all done.”); } public void OnError(Exception ex) { Debug.WriteLine(“Whoops exception, I’d better throw.”) throw ex; } }
Now let’s use these classes to create a “push” version of our “pull” example:
new NumbersObservable(new[]{2,3,4}).Register(new DebugObserver());
This prints…
1 2 3 all done.
“Whoa, whoa! Isn’t this pretty complicated?”
Don’t worry. This example above is just to demonstrate the interplay between the interfaces. Most of the time you won’t have to implement your own Observable or Observer. Rx includes lots of methods for constructing observables and observers. Using Rx extension methods I can rewrite the code above like so:
new[]{1,2,3}.ToObservable().Subscribe(number => Debug.WriteLine(“{0}”, number));
“What’s with the IDisposable object?”
The IDisposable object is returned by an Observable when you register an observer with it. When you invoke the Dispose method on the registration object the observer will stop listening to the observable for data. This is the active equivalent of passively not calling MoveNext() anymore in the middle of a sequence. Rather than invoke the Dispose method directly you will most often have it invoked for you by Rx. In the following example the TakeWhile method will invoke Dispose under the hood to detach from an observable as soon as a number larger than 10 is returned.
var numbersSmallerThanTen = Enumerable.Range(0,100).ToObservable().TakeWhile(x => x <= 10);
Here’s an example of invoking Dispose explicitly to detach from an event which has been converted to an Observable:
// Use an Rx method to convert an event to an Observable IObservable<Event<MouseEventArgs>> mouseMoveEventObservable = Observable.FromEvent<MouseEventArgs>(myControl, “MouseMove”); // register a handler with the event using an overload that accepts a lambda instead of an Observer IDisposable registration = mouseMoveEventObservable.Subscribe(mouseMoveEvent => Debug.Write(“The mouse was moved.”)); // stop listening to the event registration.Dispose();
“What about the OnError method? I don’t see an equivalent for that in IEnumerable or IEnumerator either.”
When errors occur in asynchronous operations the exception must be passed to the callback method so that the callback method can handle it. That’s why this method exists in IObservable but seems to have no equivalent in IEnumerable. In IEnumerable it is implicit because you can use try/catch.
Linq to IObservable
Now that we understand that an IObservable is just a “push” version of IEnumerable it just be obvious that all of the familiar Linq methods apply to it. In fact it is equally appropriate to use query syntax on “pull” sequences and “push” sequences. Both are queries in the strictest sense and the fact that a sequence is push or pull is orthogonal. Let’s analyze a typical Linq query:
IEnumerable<Point> points = from x in Enumerable.Range(0, 2) from y in Enumerable.Range(0, 2) select new Point(x,y);
A verbal description of this query might be:
“For each x in the sequence [0 to 1] get each y in the sequence [0 to 1] and create a new point for each pair of values.”
The result of course is:
0,0 0,1 1,0 1,1
Now let’s contrast this with an Rx query that creates a dragging event for a Silverlight/WPF control:
IObservable<Event<MouseEventArgs>> draggingEvent = from mouseLeftDownEvent in control.GetMouseLeftDown() from mouseMoveEvent in control.GetMouseMove().Until(control.GetMouseLeftUp()) select mouseMoveEvent;
A verbal description of this query might be:
“For each mouse left down event, get each mouse move event and return it until the next mouse left up event occurs.”
As you can see, using “from” allows us to declaratively sequence events. The alternative would be to create a state machine, setting a flag when the mouse button is pressed and then behaving differently when the mouse is moved and that flag is set. With Rx the code for the drag event is self-contained and involves no variable mutation.
With Linq to IEnumerable we transform and combine sequences of data to create a sequence containing exactly the data we need. Then we traverse that sequence and do something with the data. With Linq to IObservable we can transform and combine events and async callbacks to create the precise event we’re interested in. Then we register a handler and do something with the data.
Silverlight Toolkit Unit Test Code Written with Rx
The Silverlight Toolkit team is using Rx to write reliable, event-based asynchronous tests. This is essential as the elements in a control’s visual tree are created asynchronously, forcing us to wait for an event in order to confirm they were created appropriately. Let’s take a look at a test for Rating that uses Rx.
This test ensures that the Actual Value of a RatingItem is %100 when its parent Rating is %100. This is tricky because when you change the value of rating it animates to the new value using an internal storyboard. I have to wait for ActualValue to be animated to the Value property before I examine the RatingItem.
The test creates a Rating control, places it on screen, and waits for LayoutUpdated to ensure that the rating items are generated. Then it asynchronously sets the value of rating to 1.0. As the ActualValue of the Rating changes, the various RatingItems will have their ActualValue’s set accordingly depending on their index. The test needs to wait until the Rating’s ActualValue reaches Value before checking to make sure the ActualValue of the last rating item is 1.0.
Rating rating = new Rating(); IObservable<Unit> test = // Unit is an object that represents null. ObservableExtensions .DoAsync(() => TestPanel.Children.Add(rating)) .WaitFor(TestPanel.GetLayoutUpdated()) // Extension method GetLayoutUpdated converts the event to observable .DoAsync(() => rating.Value = 1.0) // Calls the Ignite EnqueueCallback method .WaitFor( // waits for an observable to raise before going on // listen to all the actual value change events and filters them until ActualValue reaches Value rating .GetActualValueChanged() // extension method that converts ActualValueChanged event to IObservable .SkipWhile(actualValueChangedEvent => actualValueChangedEvent.EventArgs.NewValue != rating.Value)) // check to make sure the actual value of the rating item is set appropriately now that the animation has completed .Assert(() => rating.GetRatingItems().Last().ActualValue == 1.0) // crawls the expression tree and makes a call to the appropriate Assert method Test.Subscribe(() => TestPanel.Children.Remove(rating)); //run the test and clean up at the end.
The code above uses a variety of extension methods we built to manipulate observable objects. You can use these libraries in your own unit tests by downloading the Silverlight Toolkit sources.
Always Useing IObservable for New Asynchronous APIs
The IObservable/IObserver interfaces are in .NET framework 4.0. I want to stress that IObservable is the new asynchronous programming pattern in .NET. It supplants the Begin/EndInvoke pattern as well as the event-based asynchronous pattern. Simple run of thumb: if the method is asynchronous, return an IObservable. *
*A correction here. It is still perfectly acceptable to use Begin/End Invoke or the event-based asynchronous pattern. Large portions of the framework use these patterns and will continue to do so for the sake of consistency.
Exposing IObservable is like putting lighting in a bottle. Developers can open it up and get access to a galaxy of Linq methods they can use to combine and sequence them with other IObservables. My hope is that eventually API’s exposing IObservable will be just as common as those exposing IEnumerable.
Erik Meijer Strikes Again
Rx is the brainchild of Erik Meijer, the father of Linq and recent recipient of the Outstanding Technical Leadership award at Microsoft. Erik is the reason I chose to work for Microsoft. With the introduction of Rx and his work on Linq and Haskell he has profoundly changed the way I approach software development twice in four years – an incredible feat. Thanks to Meijer, Microsoft does a better job than anyone of taking bleeding-edge functional programming research and productizing it. The Rx team also includes my favorite blogger, Wes Dyer whose blog posts opened my eyes to what an incredibly versatile language C# is.
After using it for the last few months it’s now impossible to imagine doing Silverlight development without Rx. As of today the only place you can get it is in the Silverlight Toolkit sources. Take a look. If you are comfortable with Linq programming you’ll find it to be extremely powerful.
46 comments:
Note that the IObserver interface must have 3 separate methods (OnNext, OnCompleted, OnError) to handle what IEnumerable describes with a single method. The "Jeckel/Hyde" duality of IEnumerable and IObserver would be more obvious in a language supporting pattern matching (F#/*ML, Scala, etc).
So that's very similar to BindingLinq/Obtrics, but limited to new items appearing at the end?
(except for the events use case, which seems to bу extremely interesting)
One thing that I do not really understand is what happens to items that asynchronously appear after creating the observable, but before calling Subscribe.
I'm _really_ interested in playing with this library, but when I reference the System.Reactive.dll, my project fails to compile. I'm using Visual Studio 2008 targeting the .NET 3.5 Framework.
It looks like the shipped version of System.Reactive.dll targets later versions of the core libraries (mscorlib, System, and System.Core: 2.0.5.0).
Do you have any recommendations for trying out the Rx Framework from a VS2k8 .NET 3.5 project?
Sweet! I've been waiting for something like this for a long time! Didn't even know it was there...
I will definitely be playing with this!
>>>
It looks like the shipped version of System.Reactive.dll targets later versions of the core libraries (mscorlib, System, and System.Core: 2.0.5.0).
>>>
It's not a later version of the .NET, it's Silverlight version. They deliberately have different version numbers.
This is obviously confusing to some people. Silverlight IS the regular .NET, except when it isn't :)
Though the binary format of DLLs is identical to regular .NET DLLs, the libraries are different (mostly there's less code and on a couple of places there's actually more). It's a subset, with a little of different security model sprinkled around. To prevent possible confusion, Microsoft decided to assing slightly different version numbers to these DLLs since they (without hacking) can't be directly referenced by a regular .NET project - which is what you've encountered.
Resolution: create a new Silverlight project and then reference the library, you'll see that it'll work.
Very nice :) Thx.
--
Jacek
I watched a video with Erik Meijer a couple of month ago where he explained the observable pattern compared to the iterator/IEnumerable pattern. I must say it's absolutely stunning.
Sounds pretty interesting.
I was wondering if this could help whilst processing objects AND wanting to show screen updates to the user.
I am in the middle of having to use Invoke methods, callbacks, and separate threads to provide a more responsive user experience, see my blog for more info.
Is this something that can be used and is it thread safe?
Awesome!
Thank you Jafar for the explanantion.
David Roh
Nice article!
Only the comment "...only now realized that the Observable pattern and the Iterator pattern are actually the same pattern." is questionable.
In this article they maybe are, but still there is a difference in responsibilities (here expressed in the "pull" or "push").
Furthermore, the Observable pattern does not need to be applied to iteration.
Brian Maso:
I'm intrigued by this statement: "The "Jeckel/Hyde" duality of IEnumerable and IObserver would be more obvious in a language supporting pattern matching."
Care to elaborate as to why? It's not clear to me how pattern matching would make the duality more obvious.
ashmind:
"One thing that I do not really understand is what happens to items that asynchronously appear after creating the observable, but before calling Subscribe."
This was a point of confusion for me for a while as well. The answer is that there really isn't a hard and fast rule. The IObservable can cache data so as to give every observer the same data regardless of when they join the party. On the other hand (as is the case with Observables generated from events) each Observer will get only data that arrives after it is connected to the Observable.
jacobcarpenter:
There IS a WPF version, and today I'm going to ask for explicit permission to post it. Hang in there.
The Luddite Developer:
Rx makes hopping threads effortless. IObservable has a Post method which accepts a thread's synchronization context. A nice pattern is to respond to an event, hop to another thread, do computations, then hop back to the UI thread right before updating UI elements. I'll be blogging more about Rx in the near future and I'll include some more in-depth examples like this.
This looks and feels like something exceptionally powerful that I am eager to use in my applications. It is also nice to hear that Microsoft it looking to make this the standard for async programming with .NET 4.0.
Now I have a reason to look into the latest framework.
Thanks!
This looks very interesting. How similar will this become to functional reactive programming?
Let's say I want to define a Linq expression against an arbitrary set of objects, and bind a property to this expression. Now when any of the values involved in that expression changes, the whole expression is recomputed (intelligently according to dependency analysis, like a spreadsheet). Is this possible with Rx?
Binding to events like you have shown is interesting -- I think the next level is binding to properties (where you have some knowledge of change notification) and updates are handles automatically. This would help tremendously with the amount of subscribing we do today to INotifyPropertyChanged events, and then managing all the update sequences manually.
good stuff
@pete Look at Obtrics/BindingLinq, that's exactly what you are looking for.
This looks very interesting. I bet it's also quite useful in a distributed messaging based application.
It would have helped if you mentioned the .GetLeftMouseDown (etc) methods in your examples were extension methods. I was initially thinking it would only be useful if someone wrapped the events up in such a way.
It took me a few minutes to figure that one out - now it makes sense.
Where can I get details, such as API docs?
I've very interested in using this framework in a project I'm going to be starting soon. Is there any chance you could share the timeline for when a .NET 4.0 compatible (non-SL) version will be released?
@ashmind -- can you share a link for the FRP library you mentioned? I can't find a reference to Obtrics or BindingLinq online.
@jafar -- to sum up my feedback, isn't the logical conclusion of this that instead of binding to events, you bind to the properties of which those events are change notifications. For example, instead of binding to a stream of MouseMove events, do something like:
myRect.Location = bind(Mouse.Location);
Databinding, but with the ability to handle complex expressions and to update dependent values in the correct order (and efficiently).
A C# version of an the good old unix pipeline. Pull from stdin(enumerable) push to stdout/stderr(observable) yet each command runs as separate process (thread) consuming and processing input as available.
@pete, sorry, I was in a hurry. the names are Obtics:
http://www.codeplex.com/Obtics
and Bindable Linq:
http://www.codeplex.com/bindablelinq
This is some great new functionality, although some libraries are doing parts of this already (in addition to the ones mentioned above, there's also CLinq(http://clinq.codeplex.com/)). When can we expect the WPF version to be released?
The open source libraries mentioned provide exactly the functionality I would have expected a functional reactive library to provide.
Jafar, is Reactive Linq expected to go to this far? There is a great example on the bindable linq page:
"As well as propogating change, Bindable LINQ can analyse your queries at runtime and detect any dependencies your query has. If these dependencies provide events to subscribe to, Bindable LINQ will automatically monitor them for change." (http://www.codeplex.com/bindablelinq)
I am not criticizing the start you guys have made in working against event streams, but just binding to an expression (LINQ query) and having update/recalculation handled automatically is the real beauty of FRP. I hope the Reactive library supports this eventually. (Right now it looks like a slightly nicer event handling mechanism... with true FRP the change notification events are transparent.)
...I meant to mention flapjax (javascript) as a great example that includes event stream handling a la System.Reactive and also the type of expression binding in BindableLinq that encompasses more spreadsheet-like behavior.
http://en.wikipedia.org/wiki/Flapjax
http://www.flapjax-lang.org/
Isn't it just observer pattern done by hand rather than using what's already implemented in .NET using Events?
I see no real difference. In both cases we have the push/pull thing though this one just takes some general code and puts it in named classes, which is nice, but i wouldn't make a framework out of it...
"When an IObservable invokes the “OnUpdate” method on an Observer it is equivalent to an IEnumerable method using the yield keyword to give information to an IEnumerable."
"OnUpdate" should read "OnNext"?
You can use Mono.Cecil or even Reflexil (Reflector plugin) to prepare the System.Reactive assembly for use.
http://evain.net/blog/articles/2009/07/30/rebasing-system-reactive-to-the-net-clr
(recomment from Part 1 post)
This is really "plain cool".
I've tried your code for the mouse button events (Down, Up and Click) but don't seem to work.
Observable.FromEvent work with MouseEnter, MouseLeave and MouseWheel but fail to Subscribe with MouseLeftButtonDown and MouseLeftButtonUp.
Any ideas what might be happening?
BTW, using SL3.
@Sébastien LEBRETON
thanks - I used Reflexil and it works like a champ!
Tom
jacobcarpenter: I'm afraid I didn't get permission to post the WPF version of reactive yet. There are good reasons to delay it. In the meantime people have provided workarounds in the comments.
The Luddite Developer: IObservable is an excellent choice.
pete: Technically this IS functional reactive programming...it just doesn't go as far as FlapJax or Binding Linq for example. IObservable could be seen as a building block for such a framework. At the moment I'm not aware of any plans to move in this direction.
Ryan O: The current plan (subject to change) is to release of beta of Rx when VS2010 beta 2 is released. AT that point IObservable and IObserver will be in the BCL and Rx will only contain the extension methods.
richardh: Yes. :-) Shortly before release the interface names changed. I'll fix that soon.
This looks interesting, although I guess I haven't understand it completely well.
One thing that feels me a little nervous is IObserver. If I had imagined all events and all async APIs are done with IObservable, that means I have to write a class for every event. That'd mean I have to write more lines of code, which I don't like. Also it might make harder to write a code that listens to multiple events as you can't write two observers in a class.
I'm wondering it should be
IDisposable Subscribe(
Action-T- next,
Action completed,
Action-Exception- error)
or create a class of these three and:
IDisposable Subscribe(
ObserverArgs-T- o)
Maybe it's because I hadn't written much using IObservable, but you'd imagine that consumers are more than producers. Making every consumer to an interface and thus a class feels me nervous.
Very nice article , going to play around with this for a bit.
I agree with Pete 100%, and have been beating the same drum about observing raw property changes for years. We're going to eventually need some sort of implicit INotifyPropertyChanged that we can enable from a subscriber during runtime so we can listen for arbitrary changes of any aspect of accessible state. There's too much ceremony around exposing and publishing "change" events. XChanged, YChanged, ZChanged... at what point will we just say, "okay, let's just allow the programmer to detect and react to any property change?
Dan Vanderboom: Believe me. There are people thinking deeply about ways of improving reactive programming (including INPC) right now. I predict that things will get better in the near to mid term.
Jafar: That's what I like to hear. Only, I hope it's generic and not tied to WPF or DependencyProperties. The whole ObservableCollection class was defined in too specific an assembly. I'm guessing we need low-level (CLR) support to get this right.
After started playing with this, I just created a simple text template (T4) to generate Event To Observable wrapper methods for a given type - so that we won't end up handcoding those GetMouseDown(), GetMouseUp() etc events
http://amazedsaint.blogspot.com/2009/11/linq-to-events-generating-wrapper.html
Post a Comment