Erik Meijer Wes Dyer Jeffrey van Gogh Bart
Erik Meijer Wes Dyer Jeffrey van Gogh Bart de Smet
What? Fundamentally change the way you think about coordinating and orchestrating asynchronous and event -based programming
Why? Because the essence of Cloud, Web, Mobile is asynchronous computations
How? By showing that asynchronous and event-based computations are just push-based collections
And you have the chance to win some $$$
Environment 1 2 Program 2 Reactive Environment in control 1 Interactive Program in control
A concrete collection of poker chips enumerable observable collection interface implements collection interface
Enumerable collections interface IEnumerable<out T> { IEnumerator<T> Get. Enumerator() } interface IEnumerator<out T>: IDisposable { bool Move. Next() T Current{ get; } // throws Exception }
Enumerable collection of chips 1 Get. Enumerator() Move. Next() Consumer pulls successive elements from The collection Current 3 2 true/false
Observable collection of chips 1 Subscribe 2 On. Next 3 Producer pushes successive elements from The collection On. Completed()
Duality in Math and Engineering !(p||q) == (!p)&&(!q) !(p&&q) == (!p)||(!q)
Duality in Math and Engineering 1/R = 1/R 1+…+1/Rn 1/C = 1/C 1+…+1/Cn R = R 1+…+Rn C = C 1+…+Cn
Duality in Math and Engineering
Dualize Enumerable collections interface IEnumerable<out T> { IEnumerator<T> Get. Enumerator() } interface IObservable<out T> { IDisposable Subscribe(IObserver<T> o) }
Dualize Enumerable collections interface IEnumerator<out T> { bool Move. Next() // throws Exception T Current{ get; } } interface IObserver<in T> { void On. Completed(bool done) T On. Next{ set; } void On. Error(Exception e) }
Observable collections interface IObservable<out T> { IDisposable Subscribe(IObserver<T> o) } interface IObserver<in T> { void On. Done(bool done) T On. Next{ set; } void On. Error(Exception e) }
Observable collections interface IObservable<out T> { IDisposable Subscribe(IObserver<T> o) } interface IObserver<in T> { void On. Completed() void On. Next(T value) void On. Error(Exception e) }
Iterator intimately related Subject Observer
Java Iterable & Iterator Observable/Observer interface Iterable<T> { Iterator<T> iterator() class Observable { void add. Observer(Observer o); void delete. Observers(); int count. Observers(); void notify. Observers(Object arg); void set. Changed(); void clear. Changed(); boolean has. Changed(); } } public interface Observer interface Iterator<T> { { void update(Observable o, Object arg); T next() // throws No. Such. Element. Exception boolean has. Next() void remove() } }
IEnumerable/IEnumerator prototypical interface for interactive collections and interactive programs IObservable/IObserver prototypical interface for observable collections and reactive, asynchronous & event-based programs
Buy enumerable collections get observable collections for free! Both collection interfaces support the LINQ Standard Query Operators
Samples Drag and Drop Dictionary Suggest (AJAX programming using LINQ queries) Clock (MVC programming using LINQ queries) Twitter on Bing maps Animation
Dictionary Suggest in C# Combines event stream from UI with async call across network Html Format(this string[] entries) {…} [Run. At. Origin()] IObservable<string[]> Suggest (this Dictionary dict, string prefix, int count) {…} var input. Values = from i in Input. Get. Key. Up() select i. Value; var q = from s in input. Values from r in Dictionary. Suggest(s, 10) select r. Format(); q. Subscribe(html => { output. Inner. Html = html; });
r ra ⊑ ray r ray ⊒ ra
Preemption operator (Esterelle) var q = from s in input. Values from r in Dictionary. Suggest(s, 10) select r. Format(); var q = input. Values. Throttle(500). Let(_input. Values => from s in _input. Values from r in Dictionary. Suggest(s, 10). Take. Until(_input. Values) select r. Format());
In Java. Script var input = document. get. Element. By. Id("input"); var results = document. get. Element. By. Id("results"); var changed = Rx. Observable. From. Html. Event(input, "keyup"). Select(function(){ return input. value }). Where(function(value){ return value != ""; });
Switch instead of Query Syntax changed. Throttle(250). Select(function(what) { return query(what); }). Switch(). Select(function(results) { return format. As. Html(results); }). Subscribe(function(html) { results. inner. HTML = html; }, function(error){ results. inner. HTML = "> error retrieving results< "; });
Twitter on Bing. Maps
JQuery Binding j. Query. fn. To. Observable = function(event. Type, event. Data) { return Rx. Observable. From. JQuery(this, event. Type, event. Data); } Rx. Observable. From. JQuery. Event(some. JQuery. Object, “mousemove”) some. JQuery. Object. To. Observable(“mousemove”) Array. prototype. to. Observable = function() { return Rx. Observable. From. Array(this); };
Same pattern as dictionary suggest Rx. Observable. Interval(10000). Select(function() { return search. Twitter("#mix 10"); }). Switch(). Select(function(result) { return JSON. parse(result. response. Text); }). Select. Many(function(data) { return data. results. to. Observable(); }). Where(function(data) { return data. geo != null; }). Subscribe( function(data) { var lat = data. geo. coordinates[0]; var lon = data. geo. coordinates[1]; add. Push. Pin(map, data. id, data. created_at, lon, data. profile_image_url, data. from_user, data. text); }, function(error) { alert(error); });
Drag & Drop On Windows Phone 7 d. X d. Y
The code … var W = … control to be dragged …; var mouse. Downs = from md in W. Get. Mouse. Down() select true; var mouse. Ups = from mu in W. Get. Mouse. Up() select false; var mouse. Clicks = mouse. Downs. Merge(mouse. Ups); var mouse. Moves = from mm in W. Get. Mouse. Move() select new{ mm. X, mm. Y }; var mouse. Diffs = from diff in mouse. Moves. Skip(1). Zip(mouse. Moves) select new { d. X = diff. First. X – diff. Second. X , d. Y = diff. First. Y – diff. Second. Y }; var mouse. Drag = from leftdown in mouse. Clicks from delta in mouse. Diffs where leftdown select delta; mouse. Drag. Subscribe(delta => { … move W by delta … });
Side-Effects var mouse. Diffs = from diff in mouse. Moves. Skip(1). Zip(mouse. Moves) select new { d. X = diff. First. X – diff. Second. X , d. Y = diff. First. Y – diff. Second. Y }; var mouse. Diffs = mouse. Moves. Let(_mousemoves => from diff in _mouse. Moves. Skip(1). Zip(_mouse. Moves) select new { d. X = diff. First. X – diff. Second. X , d. Y = diff. First. Y – diff. Second. Y });
MVC IObserver Sy st IObservable em . D at e. T im e Model View
function start. Clock() { var time. Model = get. Time(); var analog. View = get. Analog. Clock(); time. Model. Subscribe(analog. View); }
The Model function get. Time() { return Rx. Observable. Interval(100). Select(function() { var date = new Date(); var result = { hours : date. get. Hours(), minutes : date. get. Minutes(), seconds : date. get. Seconds(), }; return result; }); }
The View function get. Analog. Clock() { var hour = document. get. Element. By. Id("hour"); var minute = document. get. Element. By. Id("minute"); var second = document. get. Element. By. Id("second"); var clock= new Rx. Observer( function(now) { hour. src = "hour" + Math. floor(now. hours*5 % 60 - now. minutes/12) + ". png"; status = hour. src; minute. src = "minute" + now. minutes + ". png"; second. src = "second" + now. seconds + ". png"; }); return clock; }
Animations
<!DOCTYPE html PUBLIC "-//W 3 C//DTD XHTML 1. 0 Transitional//EN" "http: //www. w 3. org/TR/xhtml 1/DTD/xhtml 1 transitional. dtd"> <html xmlns="http: //www. w 3. org/1999/xhtml" > <head> <title>Rx for Java. Script Rocks!</title> <script src="rx. js" type="text/javascript"></script> <script type="text/javascript"> function tester() { var mouse. Move = Rx. Observable. From. Html. Event(document, "mousemove"); var text = "time flies like an arrow"; var container = document. get. Element. By. Id("container"); for (var i = 0; i < text. length; i++) { (function(i) { var s = document. create. Element("span"); s. inner. HTML = text. char. At(i); s. style. position = "absolute"; container. append. Child(s); mouse. Move. Delay(i * 100). Subscribe(function(mouse. Event) { s. style. top = mouse. Event. client. Y + "px"; s. style. left = mouse. Event. client. X + i * 10 + 15 + "px"; })(i); } } </script> </head> <body onload="tester()" style="font-family: Consolas, monospace; overflow: hidden"> <div id="container"></div> </body> </html>
Follow Us On Twitter #Rx. NET #Rx. JS (#Rx is filled with a lot of prescription garbage not related to our library : ))
Download
Questions & Comments emeijer@microsoft. com
- Slides: 44