A few years back I did a podcast with Erik Meijer about Reactive Extensions for .NET (Rx). Since then thousands of people have enjoyed using Rx in the projects and a number of open source projects like ReactiveUI (also on the podcast) have popped up around it. Even GitHub for Windows uses Reactive Extensions. In fact, GitHub uses Rx a LOT in their Windows product. My friend Paul at GitHub says they liked the model so much they made a Mac version!
“GitHub for Windows uses the Reactive Extensions for almost everything it does, including network requests, UI events, managing child processes (git.exe). Using Rx and ReactiveUI, we've written a fast, nearly 100% asynchronous, responsive application, while still having 100% deterministic, reliable unit tests. The desktop developers at GitHub loved Rx so much, that the Mac team created their own version of Rx and ReactiveUI, called ReactiveCocoa, and are now using it on the Mac to obtain similar benefits.” – Paul Betts, GitHub
Today, Microsoft Open Technologies announced the open sourcing of Reactive Extensions! You can get the code with git up on Codeplex at https://rx.codeplex.com. You can’t stop the open source train! Congrats to the team!
There’s a LOT included, so be stoked. It’s not just Rx.NET, but also the C++ library as well as RxJS for JavaScript! Now everyone gets to play with IObservable<T> and IObserver<T>.
A great way to learn about why Rx is useful is to check out the Rx Koan’s project or to read the IntroToRx online e-book.
Why do I think Rx matters? It’s a way to do asynchronous operations on event streams. Rather than hooking up click events and managing state with event handlers all over, you effectively “query” an infinite stream of events with LINQ. You can declaratively sequence events…no flags, no state machine.
For example, here’s a dragging event created (composed) via Mouse button and Mouse move events:
IObservable<Event<MouseEventArgs>> draggingEvent = from mouseLeftDownEvent in control.GetMouseLeftDown() from mouseMoveEvent in control.GetMouseMove().Until(control.GetMouseLeftUp()) select mouseMoveEvent;
Even better, Rx makes it easier (or possible!) to create event-based tests that are asynchronous, like this example from Jafar Husain:
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 methodTest.Subscribe(() => TestPanel.Children.Remove(rating)); //run the test and clean up at the end.
There’s amazing Time-related operators that let you simulate events over time. Note the Buffer and Subscribe calls.
var myInbox = EndlessBarrageOfEmail().ToObservable();// Instead of making you wait 5 minutes, we will just check every three seconds instead. :)var getMailEveryThreeSeconds = myInbox.Buffer(TimeSpan.FromSeconds(3)); // Was .BufferWithTime(...getMailEveryThreeSeconds.Subscribe(emails =>{ Console.WriteLine("You've got {0} new messages! Here they are!", emails.Count()); foreach (var email in emails) { Console.WriteLine("> {0}", email); } Console.WriteLine();});
You can use await and async, like in this example returning the number 42 after 5 seconds:
static async void button_Click(){ int x = await Observable.Return(42).Delay(TimeSpan.FromSeconds(5)); // x with value 42 is returned after 5 seconds label.Text = x.ToString();}
Here’s some more resources to check out about Rx. Congrats to the team for their contribution to Open Source!
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.
a@href@title, b, blockquote@cite, em, i, li, ol, pre, strike, strong, sub, super, u, ul
Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.