540 likes | 635 Views
Explore how to compose asynchronous and event-based programs using observable collections with Rx library. Download available at MSDN DevLabs for .NET 2.0, .NET 4.0, and Silverlight, and in JavaScript. Learn about essential interfaces like IEnumerable and IEnumerator. Discover the concept of duality in programming and how to swap input and output for synchronization. Follow the step-by-step guide to dualize IEnumerable and gain insights into asynchronous programming. The content is licensed under Creative Commons Attribution-Non-Commercial-Share Alike.
E N D
Rx: your prescription to cure asynchronous programming blues Slides license: Creative Commons Attribution Non-Commercial Share Alike See http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode
Mission statement Too hard today… Rx is a library forcomposing asynchronous and event-basedprograms using observable collections. Queries? LINQ? • Download at MSDN DevLabs • .NET 2.0, .NET 4.0, Silverlight • JavaScript, more…?
Essential InterfacesEnumerables – a pull-based world • interfaceIEnumerable<out T> • { • IEnumerator<T> GetEnumerator();} • interface IEnumerator<out T> : IDisposable • { • boolMoveNext(); • T Current { get; } • void Reset(); • } C# 4.0 covariance You could get stuck
Essential InterfacesEnumerables – a pull-based world (Waiting to move next) C# 4.0 covariance moving on You could get stuck
Mathematical dualityBecause the Dutch are (said to be) cheap • Electricity: inductor and capacitor • Logic: De Morgan’s Law • Programming? Source: http://smartcanucks.cs
What’s the dual of IEnumerable?The recipe to dualization http://en.wikipedia.org/wiki/Dual_(category_theory) Reversing arrows…Input becomes output and vice versa Making a U-turnin synchrony
What’s the dual of IEnumerable?Step 1 – Simpler and more explicit • interfaceIEnumerable<T> • { • IEnumerator<T> GetEnumerator();} • interface IEnumerator<T> : IDisposable • { • boolMoveNext(); • T Current { get; } • void Reset(); • } GetEnumerator(void); MoveNext(void); throwsException; GetCurrent(void); C# didn’t borrow Java checked exceptions
What’s the dual of IEnumerable?Step 1 – Simpler and more explicit • interface IEnumerable<T> • { • } • interface IEnumerator<T> : • { • boolMoveNext(void) throwsException; • T GetCurrent(void); • } IEnumerator<T> GetEnumerator(void); ( & ) We really got an enumerator and a disposable IDisposable
What’s the dual of IEnumerable?Step 2 – Swap input and output IEnumerableDual<T> IEnumerable<T> • interface • { • (IDisposable & );} • interface IEnumerator<T> • { • boolMoveNext(void) throwsException; • T GetCurrent(void); • } Set IEnumerator<T> ) GetEnumerator( void Will onlydualize the synchrony aspect
What’s the dual of IEnumerable?Step 2 – Swap input and output • interfaceIEnumerableDual<T> • { • IDisposableSetEnumerator(IEnumerator<T> x);} • interface IEnumerator<T> • { • boolMoveNext(void) throwsException; • T GetCurrent(void); • } This is an output too
What’s the dual of IEnumerable?Step 2 – Swap input and output • interfaceIEnumerableDual<T> • { • IDisposableSetEnumerator(IEnumerator<T> x);} • interface IEnumerator<T> • { • (bool | Exception) MoveNext(void); • T GetCurrent(void); • } Discrete domain with true and false
What’s the dual of IEnumerable?Step 2 – Swap input and output • interfaceIEnumerableDual<T> • { • IDisposableSetEnumerator(IEnumerator<T> x);} • interface IEnumerator<T> • { • (true | false | Exception) MoveNext(void); • T GetCurrent(void); • } T If you got true, you really got a T
What’s the dual of IEnumerable?Step 2 – Swap input and output • interfaceIEnumerableDual<T> • { • IDisposableSetEnumerator(IEnumerator<T> x);} • interface IEnumerator<T> • { • (T | false | Exception) MoveNext(void); • } void If you got false, you really got void
What’s the dual of IEnumerable?Step 2 – Swap input and output • interfaceIEnumerableDual<T> • { • IDisposableSetEnumerator(} • interface • { • ); • } IEnumeratorDual>); IEnumerator<T> x); IEnumerator<T> IEnumeratorDual<T> Got MoveNext( (T | void | Exception) void But C# doesn’t have discriminated unions… Let’s splat this into three methods instead!
What’s the dual of IEnumerable?Step 2 – Swap input and output • interfaceIEnumerableDual<T> • { • IDisposableSetEnumerator(IEnumeratorDual<T>);} • interface IEnumeratorDual<T> • { • voidGotT(T value); • voidGotException(Exception ex); • voidGotNothing(void);}
What’s the dual of IEnumerable?Step 3 – Consult the Gang of Four… • interfaceIObservable<T> • { • IDisposableSetObserver(IObserver<T> observer);} • interface IObserver<T> • { • voidGotT(T value); • voidGotException(Exception ex); • voidGotNothing(); • } Source:http://amazon.com
What’s the dual of IEnumerable?Step 4 – Variance annotations • interfaceIObservable<out T> • { • IDisposableSetObserver(IObserver<T> observer);} • interface IObserver<in T> • { • voidGotT(T value); • voidGotException(Exception ex); • voidGotNothing(); • } Do you really know C# 4.0? Used to detach the observer…
What’s the dual of IEnumerable?Step 5 – Color the bikeshed (*) • interfaceIObservable<out T> • { • IDisposableSubscribe(IObserver<T> observer);} • interface IObserver<in T> • { • voidOnNext(T value); • voidOnError(Exceptionex); • voidOnCompleted(); • } (*) Visit http://en.wikipedia.org/wiki/Color_of_the_bikeshed
Essential InterfacesObservables – a push-based world • interfaceIObservable<out T> • { • IDisposableSubscribe(IObserver<T> observer);} • interface IObserver<inT> • { • voidOnNext(T value); • voidOnError(Exception ex); • voidOnCompleted(); • } C# 4.0 contravariance You could get flooded
Essential InterfacesSummary – push versus pull Application Got next? MoveNext OnNext Have next! Interactive Reactive Environment IObservable<T> IObserver<T> IEnumerable<T> IEnumerator<T>
demo Essential Interfaces
Getting Your ObservablesPrimitive constructors OnCompleted new int[0] Observable.Empty<int>() OnNext new[] { 42 } Observable.Return(42) OnError Throwing iterator Observable.Throw<int>(ex) Observable.Never<int>() Iterator that got stuck Notion of time
Getting Your ObservablesObserver (and enumerator) grammar OnNext* [OnError|OnCompleted] OnNext(1) OnNext(2) OnNext(0) Observable.Range(0, 3) yield 1 yield 2 yield 0 Enumerable.Range(0, 3)
Getting Your ObservablesGenerator functions A variant with time notion exists (GenerateWithTime) Hypothetical anonymous iterator syntax in C# • o = Observable.Generate( • 0, • i => i < 10, • i => i + 1, • i => i * i • ); • o.Subscribe(x => { • Console.WriteLine(x); • }); e = newIEnumerable<int> { for (int i = 0; i < 10; i++) yield return i * i; }; foreach (var x in e) { Console.WriteLine(x); } Synchronous Asynchronous
Getting Your ObservablesCreate – our most generic creation operator • IObservable<int> o = Observable.Create<int>(observer => { • // Assume we introduce concurrency (see later)… • observer.OnNext(42); • observer.OnCompleted(); • }); • IDisposable subscription = o.Subscribe( • onNext: x => { Console.WriteLine("Next: " + x); }, • onError: ex => { Console.WriteLine("Oops: " + ex); }, • onCompleted: () => { Console.WriteLine("Done"); } • ); C# doesn’t have anonymous interface implementation, so we provide various extension methods that take lambdas. C# 4.0 named parameter syntax
Getting Your ObservablesCreate – our most generic creation operator • IObservable<int> o = Observable.Create<int>(observer => { • // Assume we introduce concurrency (see later)… • observer.OnNext(42); • observer.OnCompleted(); • }); • IDisposable subscription = o.Subscribe( • onNext: x => { Console.WriteLine("Next: " + x); }, • onError: ex => { Console.WriteLine("Oops: " + ex); }, • onCompleted: () => { Console.WriteLine("Done"); } • ); • Thread.Sleep(30000); // Main thread is blocked… F10
Getting Your ObservablesCreate – our most generic creation operator • IObservable<int> o = Observable.Create<int>(observer => { • // Assume we introduce concurrency (see later)… • observer.OnNext(42); • observer.OnCompleted(); • }); • IDisposable subscription = o.Subscribe( • onNext: x => { Console.WriteLine("Next: " + x); }, • onError: ex => { Console.WriteLine("Oops: " + ex); }, • onCompleted: () => { Console.WriteLine("Done"); } • ); • Thread.Sleep(30000); // Main thread is blocked… F10
Getting Your ObservablesCreate – our most generic creation operator • IObservable<int> o = Observable.Create<int>(observer => { • // Assume we introduce concurrency (see later)… • observer.OnNext(42); • observer.OnCompleted(); • }); • IDisposable subscription = o.Subscribe( • onNext: x => { Console.WriteLine("Next: " + x); }, • onError: ex => { Console.WriteLine("Oops: " + ex); }, • onCompleted: () => { Console.WriteLine("Done"); } • ); • Thread.Sleep(30000); // Main thread is blocked… F5
Getting Your ObservablesCreate – our most generic creation operator • IObservable<int> o = Observable.Create<int>(observer => { • // Assume we introduce concurrency (see later)… • observer.OnNext(42); • observer.OnCompleted(); • }); • IDisposable subscription = o.Subscribe( • onNext: x => { Console.WriteLine("Next: " + x); }, • onError: ex => { Console.WriteLine("Oops: " + ex); }, • onCompleted: () => { Console.WriteLine("Done"); } • ); • Thread.Sleep(30000); // Main thread is blocked… Breakpoint got hit
demo Getting Your Observables
Bridging Rx with the WorldWhy .NET events aren’t first-class… How to pass around? Hidden data source • form1.MouseMove+= (sender, args) => { • if (args.Location.X==args.Location.Y) • // I’d like to raise another event • }; • form1.MouseMove -=/* what goes here? */ Lack of composition Resource maintenance?
Bridging Rx with the World…but observables sequences are! Objects can be passed Source of Point values • IObservable<Point>mouseMoves= Observable.FromEvent(frm, "MouseMove"); • varfiltered = mouseMoves • .Where(pos => pos.X == pos.Y); • varsubscription = filtered.Subscribe(…); • subscription.Dispose(); Can define operators Resource maintenance!
Bridging Rx with the WorldAsynchronous methods are a pain… Exceptions? Hidden data source • FileStreamfs = File.OpenRead("data.txt"); • byte[] bs = new byte[1024]; • fs.BeginRead(bs, 0, bs.Length,newAsyncCallback(iar=> { • intbytesRead = fs.EndRead(iar); • // Do something with bs[0..bytesRead-1] • }), • null • ); Really a method pair Cancel? Lack of composition Synchronous completion? State?
Bridging Rx with the World…but observables are cuter! • FileStreamfs = File.OpenRead("data.txt"); • Func<byte[], int, int, IObservable<int>> read =Observable.FromAsyncPattern<byte[], int, int,int>(fs.BeginRead, fs.EndRead); • byte[] bs = new byte[1024]; • read(bs, 0, bs.Length).Subscribe(bytesRead => { • // Do something with bs[0..bytesRead-1]}); Tip: a nicer wrapper can easily be made using various operators
Bridging Rx with the WorldThe grand message • We don’t replace existing asynchrony: • .NET events have their use • the async method pattern is fine too • other sources like SSIS, PowerShell, WMI, etc. • but we… • unify those worlds • introduce compositionality • provide generic operators • hence we… • build bridges!
Bridging Rx with the WorldTerminology: hot versus cold observables • Cold observables • Hotobservables varxs = Observable.Return(42); xs.Subscribe(Console.WriteLine); // Prints 42 xs.Subscribe(Console.WriteLine); // Prints 42 again Triggered by subscription varmme = Observable.FromEvent<MouseEventArgs> (from, "MouseMove"); mme.Subscribe(Console.WriteLine); Mouse events going before subscription
demo Bridging Rx with the World
Composition and QueryingConcurrency and synchronization • What does asynchronous mean? • Greek: • a-syn = not with (independent from each other) • chronos = time • Two or more parties work at their own pace • Need to introduce concurrency • Notion of IScheduler Parameterization of operators varxs = Observable.Return(42, Scheduler.ThreadPool); xs.Subscribe(Console.WriteLine); Will run on the source’s scheduler
Composition and QueryingConcurrency and synchronization • Does duality apply? • Convert between both worlds • “Time-centric” reactive operators: // Introduces concurrency to enumerate and signal… varxs = Enumerable.Range(0, 10).ToObservable(); // Removes concurrency by observing and yielding… varys = Observable.Range(0, 10).ToEnumerable(); Race! source1 source2 source1.Amb(source2)
Composition and QueryingConcurrency and synchronization • How to synchronize? • Compositionality to the rescue! varxs = Observable.Return(42, Scheduler.ThreadPool); xs.Subscribe(x => lbl.Text = "Answer = " + x); • IScheduler • WPF dispatcher • WinForms control • SynchronizationContext xs.ObserveOn(frm).Subscribe(x => lbl.Text = "Answer = " + x);
Composition and QueryingStandard Query Operators • Observables are sources of data • Data is sent to you (push based) • Extra (optional) notion of time • Hence we can query over them // Producing an IObservable<Point> using Select varmme = from mm in Observable.FromEvent<MouseEventArgs>( form, “MouseMove”) selectmm.EventArgs.Location; // Filtering for the first bisector using Where var res = from mm in mme where mm.X == mm.Y select mm;
Composition and QueryingPutting the pieces together Asynchronous request IObservable<string> $$$ TextChanged Dictionary web service React Reaction Reactive Reactor IObservable<DictionaryWord[]> Data bindingon UI thread
Composition and QueryingSelectMany – composition at its best • // IObservable<string> from TextChangedevents • varchanged = Observable.FromEvent<EventArgs>(txt, "TextChanged"); • varinput = (fromtext in changed • select ((TextBox)text.Sender).Text); • .DistinctUntilChanged() • .Throttle(TimeSpan.FromSeconds(1)); • // Bridge with the dictionary web service • var svc = newDictServiceSoapClient();var lookup = Observable.FromAsyncPattern<string, DictionaryWord[]>(svc.BeginLookup, svc.EndLookup); • // Compose both sources using SelectMany • varres = fromterm in input • fromwords inlookup(term) • selectwords; input.SelectMany(term => lookup(term))
demo Composition and Querying
Composition and QueryingAsynchronous programming is hard… React Reactive Reactive| Reacti| Re| React| React| Rea| Reac| | Reactiv| R| input Reactive Reaction Reactive Reactor Service call 1 Service call 2 UI data binding Reactive Reaction Reactive Reactor Source:http://scrapetv.com
Composition and QueryingFixing out of order arrival issues React Reactive Reactive| Reacti| Rea| React| Re| React| Reac| | Reactiv| R| input Cancel call 1 Until Reactive Service call 1 Take Service call 2 UI data binding Reactive Reaction Reactive Reactor
Composition and QueryingApplying the TakeUntil fix • // IObservable<string> from TextChangedevents • varchanged = Observable.FromEvent<EventArgs>(txt, "TextChanged"); • varinput = (fromtext in changed • select ((TextBox)text.Sender).Text); • .DistinctUntilChanged() • .Throttle(TimeSpan.FromSeconds(1)); • // Bridge with the dictionary web service • var svc = newDictServiceSoapClient();var lookup = Observable.FromAsyncPattern<string, DictionaryWord[]>(svc.BeginLookup, svc.EndLookup); • // Compose both sources using SelectMany • varres = fromterm in input • fromwords inlookup(term).TakeUntil(input) • selectwords; Very local fix // Alternative approach for composition using: // IObservable<T> Switch<T>(IObservable<IObservable<T>> sources) varres = (fromtermininput select lookup(term)) .Switch(); Hops from source to source
demo Fixing asynchronous issues
Rx for JavaScript (RxJS) • Parity with Rx for .NET • Set of operators • Taming asynchronous JS • JavaScript-specific bindings • jQuery • ExtJS • Dojo • Prototype • YUI3 • MooTools • Bing APIs
Rx for JavaScript (RxJS) • $("#input").ToObservable("keyUp") • .Throttle(250) • .Select(function(ev) { • return query($(ev.target).text()); • }) • .Switch() • .Select(function(result) { • returnformatAsHtml(result); • }) • .Subscribe( • function(results) { • $("#results").html(results); • }, • function(error) { • $("#results").html("Error: " + error); • });