Posted By: Charles | Jul 9th @ 11:36 AM | 85,493 Views | 51 Comments
Erik Meijer and team (developer Wes Dyer, in particular) have created a profound and beautiful .NET library that will take managed event based programming to new levels. Of course, many of you wish that you could write LINQ expressions over events. Well, now you can thanks to Erik's and Wes Dyer's latest creation, Rx - .NET Reactive Framework. Erik, being a fundamentalist functional theoritician, can't create new programming abstractions without employing some form of monadic magic. 

Enter astrophysicist and monadic composition wizard Brian Beckman. The last time Brian was on C9 he taught us about the State Monad. At the end of that discussion he mentioned he wanted to teach us about the Continuation Monad next. So, who better to conduct this episode of Expert to Expert than Dr. Beckman? Yep. You guessed it! Rx employs the Continuation Monad in its composition. Erik is in the hot seat this time and it's always a real pleasure to converse with Erik and Brian in the same room at the same whiteboard.

Now, what is Rx?

The .NET Reactive Framework (Rx) is the mathematical dual of LINQ to Objects. It consists of a pair of interfaces IObserver/IObservable that represent push-based, or observable, collections, plus a library of extension methods that implement the LINQ Standard Query Operators and other useful stream transformation functions.

interface IObservable<out T> 
{      
    IDisposable Subscribe(IObserver o);
}

interface IObserver<in T> 
{     
    void OnCompleted();     
    void OnNext(T v);      
    void OnError(Exception e); 


Observable collections capture the essence of the well-known subject/observer design pattern, and are tremendously useful for dealing with event-based and asynchronous programming, i.e. AJAX-style applications. For example, here is the prototypical Dictionary Suggest written using LINQ query comprehensions over observable collections:

IObservable<Html> q = from fragment in textBox

               from definitions in Dictionary.Lookup(fragment, 10).Until(textBox)

               select definitions.FormatAsHtml();

 

q.Subscribe(suggestions => { div.InnerHtml = suggestions; })



Please subscribe to this Channel 9 interview to be notified when we have clearance to distribute Rx over the counter (lame puns intended Smiley.

Tune in. This should prove to be an instant classic besides being a very important episode of E2E. Rx is deep, man. Deep.

Enjoy!
Rating:
12
0

Oh my! Oh my! Smiley Too cool: Erik, Wes and Brian. More please. I've been wondering what Wes has been up to since his blog went dark.

aL_
aL_
Rx ftw

whoa eric brian and wes. talk about crssing the streams Smiley cant wait to watch this one

(also hoping against hope for some natal somewhere in there Wink )

aL_
aL_
Rx ftw

watching it now Smiley i saw erics talk about rx on lang.net (i think it was) and his coin example sounded hilarious Smiley to bad they didnt shoot him talking then because it seemd to be alot of visuals besides the slides. did he actually have a bunch of coins and threw them at people? Smiley

totally off topic:

if you hold shift while right clicking on a taskbar button in win7, you get the classic context menu with the move/maximize/minimize options. great if your media player is on your other monitor (the TV in my case) Smiley

Great video! Really fascinating. I can't wait to see the code - just push it to me Smiley

A question: The scope of the  IDisposable object returned by Subscribe() was unclear to me. Erik implies you can put it in a using statement, like a normal IDisposable. But the lexical scope of the IDisposable returned seems much different than the lifetime ("runtime scope"?) of the IObserver you pass in. For example, the using statemetn with IDisposable for files is pretty obvious:

  using(fs = new Stream("somefile.txt"))   
  {     
    // ... do work on fs ...   
  } // fs is closed and disposed. 

But in the IObserver case, I don't think the using statement's scope is appropriate for indicating you don't care about events anymore. Using the autocomplete example above:

using(q.Subscribe(suggestions => ... ))
{
// ???
}

What happens in the body of the using statement? All the work seems to occur in the lambda passed to Subscribe. If I understood correctly, as soon as we leave the scope of the using statement, my lambda stops receiving events. Hmm, I bet the object implementing IDisposable has the secret sauce for the reactive framework. Maybe it has a method for testing for conditions and will "yield" until the condition is met? For example if I had another observer which looked for ENTER or TAB on the textbox and indicated that a selection was made, maybe it would let me write this code:

class KeyObserver :  IObserver<...>
{
publi c bool SelectionMade()
}

KeyObserver key = ...;

using(cntrl = q.Subscribe(suggestions => ... ))
{
if(! key.SelectionMade())
sleep;
}
// selection has been made and we stop listening to suggest events

Hopefully that makes some sense. It looks like the beginnings of a way to do reasonable event based programming. Apologies for answering my own question but glad to hear if I'm on track ...

Two other notes:

  • Check out the AsyncEnumerator library from Jeffrey Richter. He leveraged enumerators and iterators to do something similar, but I think his solution still has an "inversion of control" problem where you need to write the code to drive the enumerator. A recent article can be found at http://msdn.microsoft.com/en-us/magazine/cc721613.aspx
  • Erik mentioned a paper by Phillip Wadler called "The essence of monads" or similar. I think he meant "The essence of functional programming" (http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.38.9516).

 

Great stuff, get me this code! Smiley

Justin

Excellent observation. If you ever get a chance to see my "fundamentalist functional programming" talk, you will see that combining side-effect, closures + using- and try-catch-blocks is my favorite source of fun "what does this code do?" puzzles.

For instance, your own example of using "using" for files is not really that "obvious". What if inside the block you capture fs in a closure, or in general stick it in the heap somewhere? I have seen examples like this

  IEnumerable<string> lines;
  using(fs = new Stream("..."))
  {
    lines = from l in fs.ReadLines() where l.Length > 256 select l;
  }

  foreach(var l in lines)
  {
    // oops, fs has been disposed before the query has been executed
  }

Brian asked the question "can you put it in a using statement", to which the only correct answer is "yes". Had he asked "is that a smart thing to do?" I would have said that the using statement can be very powerful, but as always with great power comes potential danger.

Be sure to check out Eric's talk at Lang.NET Symposium 2009 (which he alluded to in this video) and Anders Hejlberg's covariance/contravariance in C# 4.0 talk.

Using disposable resources like FileStreams in the deferred execution model of LINQ queries (and closures in general) can be frustrating.  Beware of leaks as well as premature disposals.

staceyw
staceyw
Before C# there was darkness...

Love it guys.

While watching I was thinking about the analogy between IObservable<T> and the CCR's Port<T> and how it sounds like a port abstraction.  Port<T> allows you to monitor a port with various typed-listeners and you can listen for stop, exception, and value results (and also return result back to the port) and also do things like Choice over various ports.  How does IObservable compare/contrast to the port model? 

How does fifoness play into this?  I know with Port, sometimes you have to manually assure fifoness because of the inherent concurrency.

btw - "Please subscribe to this Channel 9 interview..".  You guys jest, but that could be a killer feature.  Being able to post arbitrary Observer code in a c9 reply that could do work for you (i.e. send a tweet, send a mail, etc) based on some code in your observer.  Like a little bot script.  That could be the next big thing in blogs and forums.  High geekness factor.

Microsoft Communities