Slides license: Creative Commons Attribution Non-Commercial Share Alike See...

Preview:

Citation preview

Rx: your prescription to cure asynchronous programming blues

Slides license: Creative Commons Attribution Non-Commercial Share AlikeSee http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode

Mission statement

Rx is a library for composing asynchronous and event-based

programs using observable collections.

( 𝑓 ◦𝑔)(𝑥 )= 𝑓 (𝑔(𝑥 ))

Queries? LINQ?

Too hard today…

Download at MSDN DevLabs• .NET 2.0, .NET 4.0, Silverlight• JavaScript, more…?

interface IEnumerable<out T>{ IEnumerator<T> GetEnumerator();}

interface IEnumerator<out T> : IDisposable{ bool MoveNext(); T Current { get; } void Reset();}

Essential InterfacesEnumerables – a pull-based world

You could get stuck

C# 4.0 covariance

Essential InterfacesEnumerables – a pull-based world

You could get stuck

C# 4.0 covariance

(Waiting to move next)

moving on

Mathematical dualityBecause the Dutch are (said to be) cheap

Electricity: inductor and capacitor

Logic: De Morgan’s Law

Programming?

¬ ( 𝐴∧𝐵 )≡¬𝐴∨¬𝐵 ¬ ( 𝐴∨𝐵 )≡¬𝐴∧¬𝐵

Source:

http://s

martcanucks.c

s

What’s the dual of IEnumerable?The recipe to dualizationhttp://en.wikipedia.org/wiki/

Dual_(category_theory)

Reversing arrows…Input becomes output and

vice versaMaking a U-turn

in synchrony

interface IEnumerable<T>{ IEnumerator<T> GetEnumerator();}

interface IEnumerator<T> : IDisposable{ bool MoveNext(); T Current { get; } void Reset();}

What’s the dual of IEnumerable?Step 1 – Simpler and more explicit

GetEnumerator(void);

MoveNext(void); throws Exception;GetCurrent(void); C# didn’t borrow

Java checked exceptions

interface IEnumerable<T>{ }

interface IEnumerator<T> :{ bool MoveNext(void) throws Exception; T GetCurrent(void);}

What’s the dual of IEnumerable?Step 1 – Simpler and more explicit

IDisposable

( & )IEnumerator<T> GetEnumerator(void);We really got an

enumerator and a disposable

interface{ (IDisposable & );}

interface IEnumerator<T>{ bool MoveNext(void) throws Exception; T GetCurrent(void);}

What’s the dual of IEnumerable?Step 2 – Swap input and output

voidIEnumerator<T>

IEnumerableDual<T>IEnumerable<T>

) GetEnumerator(Set

Will only dualize the synchrony

aspect

interface IEnumerableDual<T>{ IDisposable SetEnumerator(IEnumerator<T> x);}

interface IEnumerator<T>{ bool MoveNext(void) throws Exception; T GetCurrent(void);}

What’s the dual of IEnumerable?Step 2 – Swap input and output

This is an output too

interface IEnumerableDual<T>{ IDisposable SetEnumerator(IEnumerator<T> x);}

interface IEnumerator<T>{ (bool | Exception) MoveNext(void); T GetCurrent(void);}

What’s the dual of IEnumerable?Step 2 – Swap input and output

Discrete domain with true and

false

interface IEnumerableDual<T>{ IDisposable SetEnumerator(IEnumerator<T> x);}

interface IEnumerator<T>{ (true | false | Exception) MoveNext(void); T GetCurrent(void);}

What’s the dual of IEnumerable?Step 2 – Swap input and output

If you got true, you really got a T

T

interface IEnumerableDual<T>{ IDisposable SetEnumerator(IEnumerator<T> x);}

interface IEnumerator<T>{ (T | false | Exception) MoveNext(void);}

What’s the dual of IEnumerable?Step 2 – Swap input and output

If you got false, you really got

void

void

interface IEnumerableDual<T>{ IDisposable SetEnumerator(}

interface{ );}

What’s the dual of IEnumerable?Step 2 – Swap input and output

(T | void | Exception)

MoveNext(void

But C# doesn’t have discriminated unions…

Let’s splat this into three methods instead!

Got

IEnumeratorDual<T>IEnumerator<T>

IEnumeratorDual>);IEnumerator<T> x);

interface IEnumerableDual<T>{ IDisposable SetEnumerator(IEnumeratorDual<T>);}

interface IEnumeratorDual<T>{ void GotT(T value); void GotException(Exception ex); void GotNothing(void);}

What’s the dual of IEnumerable?Step 2 – Swap input and output

interface IObservable<T>{ IDisposable SetObserver(IObserver<T> observer);}

interface IObserver<T>{ void GotT(T value); void GotException(Exception ex); void GotNothing();}

What’s the dual of IEnumerable?Step 3 – Consult the Gang of Four…

Sou

rce:

http

://am

azo

n.co

m

interface IObservable<out T>{ IDisposable SetObserver(IObserver<T> observer);}

interface IObserver<in T>{ void GotT(T value); void GotException(Exception ex); void GotNothing();}

What’s the dual of IEnumerable?Step 4 – Variance annotations

Used to detach the observer…

Do you really know C# 4.0?

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

interface IObserver<in T>{ void OnNext(T value); void OnError(Exception ex); void OnCompleted();}

What’s the dual of IEnumerable?Step 5 – Color the bikeshed (*)

(*) Visit http://en.wikipedia.org/wiki/Color_of_the_bikeshed

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

interface IObserver<in T>{ void OnNext(T value); void OnError(Exception ex); void OnCompleted();}

Essential InterfacesObservables – a push-based world

You could get flooded

C# 4.0 contravariance

Essential InterfacesSummary – push versus pull

Environment

MoveN

ex

tGot next?

Application

On

Next

Have next!

IEnumerable<T>

IEnumerator<T>

IObservable<T>

IObserver<T>

Inte

racti

ve R

eactiv

e

Essential Interfaces

demo

Getting Your ObservablesPrimitive constructors

Observable.Empty<int>()

Observable.Return(42)

Observable.Throw<int>(ex)

OnCompleted

OnNext

OnError

Observable.Never<int>()

new int[0]

new[] { 42 }

Throwing iterator

Iterator that got stuckNotion of

time

Getting Your ObservablesObserver (and enumerator) grammar

OnNext* [ OnError | OnCompleted ]

Observable.Range(0, 3)

OnNext(0)

OnNext(1)

OnNext(2)

Enumerable.Range(0, 3)

yield 0 yield 1 yield 2

o = Observable.Generate( 0, i => i < 10, i => i + 1, i => i * i);

o.Subscribe(x => { Console.WriteLine(x);});

Getting Your ObservablesGenerator functions

e = new IEnumerable<int> { for (int i = 0; i < 10; i++) yield return i * i;};

foreach (var x in e) { Console.WriteLine(x);}

Hypothetical anonymous iterator

syntax in C#

Synchronous

Asynchronous

A variant with time notion exists

(GenerateWithTime)

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"); });

Getting Your ObservablesCreate – our most generic creation operator

C# doesn’t have anonymous interface implementation, so we provide various extension methods

that take lambdas.

C# 4.0 named parameter syntax

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…

Getting Your ObservablesCreate – our most generic creation operator

F10

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…

Getting Your ObservablesCreate – our most generic creation operator

F10

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…

Getting Your ObservablesCreate – our most generic creation operator

F5

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…

Getting Your ObservablesCreate – our most generic creation operator

Breakpoint got hit

Getting Your Observables

demo

form1.MouseMove += (sender, args) => {

if (args.Location.X == args.Location.Y) // I’d like to raise another event};

form1.MouseMove -= /* what goes here? */

Bridging Rx with the WorldWhy .NET events aren’t first-class…

Hidden data sourceHow to pass

around?

Lack of composition

Resource maintenance?

IObservable<Point> mouseMoves = Observable.FromEvent(frm, "MouseMove");var filtered = mouseMoves .Where(pos => pos.X == pos.Y);

var subscription = filtered.Subscribe(…);subscription.Dispose();

Bridging Rx with the World…but observables sequences are!

Source of Point values

Objects can be passed

Can define operators

Resource maintenance!

FileStream fs = File.OpenRead("data.txt");byte[] bs = new byte[1024];fs.BeginRead(bs, 0, bs.Length, new AsyncCallback(iar => { int bytesRead = fs.EndRead(iar); // Do something with bs[0..bytesRead-1] }), null);

Bridging Rx with the WorldAsynchronous methods are a pain…

Hidden data source

Really a method pair

Lack of composition

Exceptions?

Synchronous

completion?

Cancel?

State?

Bridging Rx with the World…but observables are cuter!

FileStream fs = 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 usethe async method pattern is fine tooother sources like SSIS, PowerShell, WMI, etc.

but we…unify those worldsintroduce compositionalityprovide generic operators

hence we…build bridges!

Bridging Rx with the WorldTerminology: hot versus cold observables

Cold observables

Hot observables

var xs = Observable.Return(42);

xs.Subscribe(Console.WriteLine); // Prints 42xs.Subscribe(Console.WriteLine); // Prints 42 again

Triggered by subscription

var mme = Observable.FromEvent<MouseEventArgs> (from, "MouseMove");

mme.Subscribe(Console.WriteLine);

Mouse events going before subscription

Bridging Rx with the World

demo

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 ISchedulervar xs = Observable.Return(42, Scheduler.ThreadPool);xs.Subscribe(Console.WriteLine);

Will run on the source’s

scheduler

Parameterization of

operators

Composition and QueryingConcurrency and synchronization

Does duality apply?Convert between both worlds

“Time-centric” reactive operators:

// Introduces concurrency to enumerate and signal…var xs = Enumerable.Range(0, 10).ToObservable();

// Removes concurrency by observing and yielding…var ys = Observable.Range(0, 10).ToEnumerable();

source1source2source1.Amb(source2)

Race!

Composition and QueryingConcurrency and synchronization

• IScheduler• WPF dispatcher• WinForms control• SynchronizationCont

ext

How to synchronize?

Compositionality to the rescue!

var xs = Observable.Return(42, Scheduler.ThreadPool);xs.Subscribe(x => lbl.Text = "Answer = " + x);

xs.ObserveOn(frm).Subscribe(x => lbl.Text = "Answer = " + x);

Composition and QueryingStandard Query Operators

Observables are sources of dataData is sent to you (push based)Extra (optional) notion of time

Hence we can query over them// Producing an IObservable<Point> using Selectvar mme = from mm in Observable.FromEvent<MouseEventArgs>( form, “MouseMove”) select mm.EventArgs.Location;

// Filtering for the first bisector using Wherevar res = from mm in mme where mm.X == mm.Y select mm;

Composition and QueryingPutting the pieces together

ReactTextChanged Dictionary

web service

Asynchronous request

ReactionReactiveReactor

IObservable<string>

IObservable<DictionaryWord[]>

Data binding

on UI thread

$$$

// IObservable<string> from TextChanged eventsvar changed = Observable.FromEvent<EventArgs>(txt, "TextChanged");var input = (from text in changed select ((TextBox)text.Sender).Text); .DistinctUntilChanged() .Throttle(TimeSpan.FromSeconds(1));

// Bridge with the dictionary web servicevar svc = new DictServiceSoapClient();var lookup = Observable.FromAsyncPattern<string, DictionaryWord[]> (svc.BeginLookup, svc.EndLookup);

// Compose both sources using SelectManyvar res = from term in input from words in lookup(term) select words;

Composition and QueryingSelectMany – composition at its best

input.SelectMany(term => lookup(term))

Composition and Querying

demo

input

ReactReacti

ve

Service call 1

Service call 2

UI data binding

Reactive

ReactionReactiveReactor

|R|Re|Rea|Reac|React|React|Reacti|Reactiv|Reactive|

ReactiveReactionReactiveReactor

Composition and QueryingAsynchronous programming is hard…

Source: http://scrapetv.com

input

ReactReacti

ve

Service call 1

Service call 2

UI data binding

Reactive

ReactionReactiveReactor

|R|Re|Rea|Reac|React|React|Reacti|Reactiv|Reactive|

Reactive

Composition and QueryingFixing out of order arrival issues

Cancel call 1

TakeU

ntil

// IObservable<string> from TextChanged eventsvar changed = Observable.FromEvent<EventArgs>(txt, "TextChanged");var input = (from text in changed select ((TextBox)text.Sender).Text); .DistinctUntilChanged() .Throttle(TimeSpan.FromSeconds(1));

// Bridge with the dictionary web servicevar svc = new DictServiceSoapClient();var lookup = Observable.FromAsyncPattern<string, DictionaryWord[]> (svc.BeginLookup, svc.EndLookup);

// Compose both sources using SelectManyvar res = from term in input from words in lookup(term).TakeUntil(input) select words;

Composition and QueryingApplying the TakeUntil fix

// Alternative approach for composition using:// IObservable<T> Switch<T>(IObservable<IObservable<T>> sources)var res = (from term in input select lookup(term)) .Switch();

Very local fix

Hops from source to source

Fixing asynchronous issues

demo

Rx for JavaScript (RxJS)

Parity with Rx for .NETSet of operatorsTaming asynchronous JS

JavaScript-specific bindings

jQueryExtJSDojoPrototypeYUI3MooToolsBing APIs

Rx for JavaScript (RxJS)

$("#input").ToObservable("keyUp") .Throttle(250) .Select(function(ev) { return query($(ev.target).text()); }) .Switch() .Select(function(result) { return formatAsHtml(result); }) .Subscribe( function(results) { $("#results").html(results); }, function(error) { $("#results").html("Error: " + error); });

Rx for JavaScript (RxJS)

demo

IEnumerable<T>

E.g. LINQ to Objects

IObservable<T>

E.g. LINQ to Events

IQueryable<T>

E.g. LINQ to SQL

Fix

ed

(MS

IL)

Tran

sla

tab

le(E

xp

ressio

n

trees)

ToQueryable

ToObservable

ToEnumerable

AsQ

uery

able

AsE

nu

mera

ble A

sQb

serv

able

AsO

bse

rvable

Pull(interactive)

Push(reactive)

Concu

rren

cy

(ISch

edul

er)

LINQ to *.*

What?

Wher

e?

How

?

Worker pools Message loopsThreads Distributed

Duality

Hom

o-

icon

ic

IQbservable<T>E.g. LINQ to PowerShell

ToQbservable

Mission accomplished

Rx is a library for composing asynchronous and event-based

programs using observable collections.

( 𝑓 ◦𝑔)(𝑥 )= 𝑓 (𝑔(𝑥 ))

Queries! LINQ!

Way simpler with Rx

Download at MSDN DevLabs• .NET 2.0, .NET 4.0, Silverlight• JavaScript, more…?

Related ContentHands-on Labs

Two flavors:Curing the asynchronous blues with the Reactive Extensions (Rx) for .NETCuring the asynchronous blues with the Reactive Extensions (Rx) for JavaScript

Both can be found via the Rx forums

Rx team web presenceRx team blog – http://blogs.msdn.com/rxteamDevLabs – http://msdn.microsoft.com/en-us/devlabs/ee794896.aspxMSDN forums – http://social.msdn.microsoft.com/Forums/en-US/rxChannel9 – http://channel9.msdn.com/Tags/Rx

Recommended