1 / 54

Rx: your prescription to cure asynchronous programming blues

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….

Download Presentation

Rx: your prescription to cure asynchronous programming blues

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 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

  2. 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…?

  3. 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

  4. Essential InterfacesEnumerables – a pull-based world (Waiting to move next) C# 4.0 covariance moving on You could get stuck

  5. Mathematical dualityBecause the Dutch are (said to be) cheap • Electricity: inductor and capacitor • Logic: De Morgan’s Law • Programming? Source: http://smartcanucks.cs

  6. 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

  7. 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

  8. 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

  9. 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

  10. 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

  11. 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

  12. 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

  13. 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

  14. 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!

  15. 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);}

  16. 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

  17. 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…

  18. 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

  19. 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

  20. Essential InterfacesSummary – push versus pull Application Got next? MoveNext OnNext Have next! Interactive Reactive Environment IObservable<T> IObserver<T> IEnumerable<T> IEnumerator<T>

  21. demo Essential Interfaces

  22. 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

  23. 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)

  24. 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

  25. 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

  26. 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

  27. 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

  28. 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

  29. 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

  30. demo Getting Your Observables

  31. 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?

  32. 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!

  33. 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?

  34. 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

  35. 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!

  36. 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

  37. demo Bridging Rx with the World

  38. 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

  39. 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)

  40. 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);

  41. 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;

  42. Composition and QueryingPutting the pieces together Asynchronous request IObservable<string> $$$ TextChanged Dictionary web service React Reaction Reactive Reactor IObservable<DictionaryWord[]> Data bindingon UI thread

  43. 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))

  44. demo Composition and Querying

  45. 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

  46. 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

  47. 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

  48. demo Fixing asynchronous issues

  49. 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

  50. 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); • });

More Related