Posted By: Charles | Jul 9th @ 11:36 AM | 88,454 Views | 52 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:
14
0

I was also unhappy about the covariance / contravariance discussion, so I'd like to work something up for ch9 for the near future.

 

I did peek at my old physics notes, and here's the gist from physics. Consider a parametric curve, meaning a function p(t) from a real-valued parameter, call it t, to abstract geometric points p in some space M. In calculus on manifolds, we learn that such points have various coordinate systems -- functions from abstract points p to n-vectors of real numbers (x1(p), x2(p), ..., xn(p)), such that we have differentiable functions from each coordinate system to all the others around every point. That means we can always identify abstract points p with n-vectors of real numbers, (x1(p), x2(p), ..., xn(p)) -- the coordinates of the point, in various ways -- say another set is (y1(p), y2(p), ..., yn(p)), so that the derivatives dxi/dyj and dyj/dxi exist (where i and j vary from 1 to n, inclusive).

 

Now consider a function f(p) from the points p on the manifold to something else (usually some other real vectors but it doesn't matter). What happens with df(g(t))/dt when we change coordinate systems? By the chain rule, df/dt = sum(i=1..n, (df/dxi)*(dxi/dt)). But

 

1) df/dxi = sum(k=1..n, (df/dyk)*(dyk/dxi)) -- a.k.a. covariant co-vector

2) dxi/dt = sum(l=1..n, (dxi/dyl)*(dyl/dt)) -- a.k.a. contravariant vector

 

Quantities that vary in the same way as df/dxi are called co-vectors and are covariant. Here's a mnemonic. Abbreviate df/dxi as f,xi and automatically sum over repeated indices. Rewrite equation 1 as

 

f,xi = f,yk * dyk/dxi.  See the y's "upstairs" in the dyk/dxi on the right-hand-side?  UPstairs means COvariant. Now look at equation 2 -- abbreviate dxi/dt as x.i :

 

x.i = y.l * dxi/dyl. See the y's "downstairs" in the dxi/dyl on the right-hand-side? DOWNstairs means CONTRAvariant. Such things are called vectors.

 

Ok, now how we turn these relationships amongst Coordinate Transformations into relationships amongst Types and Subtypes would be the questions I would ask to draw an analogy between co/contra variance in physics and co/contra variance in programming languages.

 

Ideas anyone? Can we relate types and subtypes to differentiable coordinate transformations? Is the "type" of an object similar to the "coordinates of a point?" Can the derivatives of the coordinate transformations (dxi/dyk) somehow be related to type coercions?

For what it's worth, a solution to the deferred disposal problem can be found here: Using IDisposables with LINQ. The filestream example would look like this:

IEnumerable<string> lines =
    from fs in new Stream("...").Use()
    from l in fs.ReadLines()
    where l.Length > 256
    select l;
foreach(var l in lines)
{
    // fs will be disposed with the enumerator
}

The same approach can be used with a delegate to defer creation as well as disposal: () => new Stream("..."). A use keyword, a la F#, would be even better.

exoteric
exoteric
I : Next<I>

I was quite happy with the coverage - it was already unusual to mix physics and programming this way - very stimulating although beyond me. One of the best parts was the formulation of co- and contravariance rules via sequent notation, dualization and showing a statement sequence as a series of continuations, if I got that right. Definitely a video that expands horizons. And this stuff about ambient monads. I'm not sure that was really covered anywhere, was it?

I'm wondering if given the excitement about the dual nature, we might be losing part of the intention of IObservable.

 

First of all, I'm thinking there might be a bit of a mismatch in the duality anyway.  Primarily, IEnumerator and IEnumerable have a many-to-one relationship, whereas IObserver and IObservable havea many-to-many relationship, right?  The deal is that IEnumerator has to have intimate knowledge about the structure of its IEnumerable that the app doesn't necessarily have; they're tightly bound.  Whereas IObserver and IObservable are completely unaware of each others' internals. 

 

I think the dual of IEnumerable would be something more like ILoadable, where you call ILoadable.GetLoader(), which then allows you to load values into an "array" or whatever, using Loader.MoveNext(bool) and Loader.SetValue(T).  I certainly think the intention of IObservable is more valuable than any ILoadable concept (though ILoadable might be an interesting way to explore inserts and updates), so I wonder if the focus on duality is perhaps the wrong way to go about it.

 

For example, I'm not sure I get the point of the OnError method.  First of all, isn't there a duality mismatch here anyway—given that IObserver.OnNext(T) could also throw an exception, then to preserve absolute duality going the opposite direction, shouldn't we require that OnError also be a part of IEnumerator?  But beyond that, it just doesn't seem to fit.  Why would the Observable need to tell all Observers that there was some exception downstream?  Just like an iterator doesn't need to know that there's an exception occurring in the app that uses it.  So I think the focus on preserving duality really mucks up the intention of IObservable in this case.

 

Also, I think if duality was that important to the concept of IObservable and IEnumerable, then the dual of (for example) IList would be even more powerful.  But wouldn't the dual of (for example) IList.Set(int, T) be IListDual.Get(out int, out T)?  Is that useful in some fashion?  I don't see anything, though I'd love to hear from anyone with an idea how it could be powerful.

Covariant/contravariant! 

 

Help! Someone call Eric Lippert Smiley

Apple[] as
Fruit[] fs = as
Fruit f = fs[0]
fs[1] = new Banana

 

In C#, the last line will throw ArrayTypeMismatchException. : Angel

Microsoft Communities