reactive extensions

async meets IEnumerable

reactive extensions - mark sowul - www.solsoftsolutions.com 1

Today I’m going to talk about a library called the “reactive extensions” I don’t want to overpromise but it just might change your life…at least a little bit, for some classes of problems

1 Marquee Sponsor

2

But first, a shout-out to our sponsors… They have made our camp today possible, so if you get a chance, talk to them and see what they have to offer you in your projects…well, hopefully you already have, because this is the last session

2 Platinum Sponsors

Gold Sponsors

Silver Sponsors 3

Some more of our sponsors

3 where we’re going • what are the reactive extensions • how and why to use them • .NET examples – Variety of other languages supported! http://reactivex.io/

reactive extensions - mark sowul - www.solsoftsolutions.com 4

So this is what I plan to talk about today

4 why reactive extensions? 1. IEnumerable + async: like Montagues and Capulets – although IAsyncEnumerable is coming 2. A different way of handling events

This Photo by Unknown Author is licensed reactive extensions - mark sowul - www.solsoftsolutions.comunder CC BY-NC-ND 5

So a little taste of what we’re going to talk about: what are the reactive extensions and why should we care about them? • One reason is that IEnumerable and async await are tragic, star-crossed lovers. As much as you might want them to be together, it currently doesn’t work that way. • Another use case is to provide a new way of handling events which has certain advantages

5 who am i? • Mark Sowul – [email protected] • Consultant – .NET (C#) – MS-SQL • www.solsoftsolutions.com – slides here (check blog / speaking calendar) – sign up for newsletter

reactive extensions - mark sowul - www.solsoftsolutions.com 7

People will probably take pictures of this page so keep it up a bit

7 different types of programming

“Active” Main() { read (what's your name) print "hello, " + name return 0; }

reactive extensions - mark sowul - www.solsoftsolutions.com 8

So here's one style of programming.

What's notable about this type of program is that it's straightforward and sequential. You can trace through the steps that are happening. Even if you add something like a loop, it's still in the same class of code. I’m going to call this “active” programming.

8 different types of programming

“Active” Main() { int targetNumber = random() while(true) { int guess = read (guess the number) if (guess > target) Print "too high!" else if (guess < target) Print "too low!" else { Print "you got it!" break; } } }

reactive extensions - mark sowul - www.solsoftsolutions.com 9

This is still “active” – you can still step through this, line by line, to get an understanding of what it does This is just a simple number guessing game

9 different types of programming

“Active” “Reactive” Main() Main() { { Timer t = new Timer(1 minute) read (what's your name) t.Tick += print "hello, " + name { return 0; print "It is now: " + DateTime.Now } } print "Press enter to exit" readline } reactive extensions - mark sowul - www.solsoftsolutions.com 10

The contrast I want to draw is with something like this.

In this case, the steps are sort of out of your control, and non-deterministic. You can't just step through it one line at a time in the debugger.

Think too, of how you would write tests for and/or mock this sort of code. And how you would have to change it in order to write to a file for example, instead of printing to the console.

10 different types of programming

“Active” “Reactive” • straightforward • no direct sequence • sequential • can’t step through • can trace through the steps • how to test and mock? • harder to debug

reactive extensions - mark sowul - www.solsoftsolutions.com 11

11 another “reactive” example

• Imaginary temperature New Temperature Max Temperature sensor 65° 65° 68° 68° – Emits new value when 66° changed 72° 72° • Want to track max 70° temperature 71° 75° 75° • Only spit out new max value 70° when it changes 68° • How would you implement?

reactive extensions - mark sowul - www.solsoftsolutions.com 12

Fine, but what if, instead of a timer where you're just spitting out a value every so often, you wanted to analyze a sequence of values? Say you have a temperature sensor and you want to get the max temperature, and you wanted to display it to the screen or write it to a file when it changes. It would be a bit tricky to do by just exposing an event.

Probably you'd have some class that encapsulates it, and is calculating the max, and maybe now passes through a "value changed" event that triggers the consumers of that class to update themselves (write to file or show on screen)

12 events / asynchronous sequences

Array of 1, 2, 3 Asynchronous sequence

1 2 3

• 2 • 5 • 1 1 2 3 seconds seconds second elapse elapse elapses

reactive extensions - mark sowul - www.solsoftsolutions.com 13

An asynchronous sequence is the same as a synchronous sequence (e.g. an array), except that the elements are also separated by time Conversely, you can think of a synchronous sequence as an asynchronous sequence simply with 0 time in between

13 events / asynchronous sequences • Can think of events ↔ asynchronous sequence of void [void] [void] [void]

• Time • Time • Time elapses elapses elapses

reactive extensions - mark sowul - www.solsoftsolutions.com 14

In Reactive, there is such a “void” type, called “Unit”

And conversely, think of events that contain data as equivalent to an asynchronous sequence of values For example a MouseMovedEvent

Hold on this point – the isomorphism between arrays <-> asynchronous sequences <- > events

14 end of act I

reactive extensions - mark sowul - www.solsoftsolutions.com 15

Questions so far? Let’s look at some other, less artificial examples

15 IObservable • IObservable: core of reactive extensions • Like IEnumerable, but push instead of pull var enumerable = Enumerable.Range(0, 100) .Where(n => n % 2 == 0) .Select(n => n * n); var observable = Observable.Range(0, 100) .Where(n => n % 2 == 0) .Select(n => n * n);

reactive extensions - mark sowul - www.solsoftsolutions.com 16

All right, time to start discussing actual code

The core of reactive extensions in .NET is called IObservable, which you can think of like IEnumerable, it represents a sequence of values (or just a sequence), but a “push” sequence instead of a “pull” sequence. You’ll see what I mean shortly.

16 Using IObservable (continued) • foreach (var n in enumerable) Console.WriteLine(n); • observable.Subscribe(n => Console.WriteLine(n));

reactive extensions - mark sowul - www.solsoftsolutions.com 17

What I mean by push sequence vs pull sequence is that, in IEnumerable we keep asking for the next value and doing something (it waits for you to request the next value); IObservable provides the next value and runs it through the logic you give. We’ll see much slicker things later but deep down that’s what’s happening.

So in the case of that temperature sensor example, we could wire that up as an observable (we’ll see more later), and now it’s the availability of new values that drives the logic

So to tie this to what I was saying earlier: The “enumerable” version is active – we can step through the program, get to the loop, iterate through the loop, and then continue The “observable” version is reactive – we don’t know when values will end up being written, it’s similar to the timer example; we can’t exactly predict when a new value will be written

17 IObservable vs IEnumerable • Both are generators – Both contain only the logic to generate the sequence – Logic runs only when we iterate (foreach)/subscribe • new independent generator each time – Difference is “pull” vs “push”

reactive extensions - mark sowul - www.solsoftsolutions.com 18

Many people have probably only interacted with IEnumerable because it’s something that arrays and lists implement, but it’s actually much more exciting than that. How many of you have ever used “yield return”?

18 sidebar: yield return • What happens when this is called?

public static IEnumerable GetNumbersSquared(int max) { for (int i = 1; i <= max; i++) { yield return i*i; } }

reactive extensions - mark sowul - www.solsoftsolutions.com 19

19 IObservable vs IEnumerable • Both are generators – Both contain only the logic to generate the sequence – Logic runs only when we iterate (foreach)/subscribe • new independent generator each time – Difference is “pull” vs “push”

reactive extensions - mark sowul - www.solsoftsolutions.com 20

(Don’t say this)

Note that IObservable can be “eager” (produce values even when no one’s listening) and also “multicast” (send the same values to multiple subscribers) but let’s not run before we can walk

20 subscribing to IObservable • manual subscription – IDisposable Subscribe( Action onNext, Action onError, Action onCompleted); – IObservable sequence = GetData(); var subscription = sequence.Subscribe( nextValue => Console.WriteLine(nextValue); ); – Dispose of the subscription to unsubscribe

reactive extensions - mark sowul - www.solsoftsolutions.com 21

Two main ways to use IObservable. Like I said, I’ll show the other set later. But again, for now: think of it like a List or Array that pushes its values to you

So as I mentioned, the logic is in a “generator”, and that logic will run when a subscription happens. You can abort that logic before the sequence finishes by disposing of the subscription.

21 simple IObservables • Observable.Return(5) – Returns a single value • Observable.Range(1, 5) – Returns 1, 2, 3, 4, 5 – Just like Enumerable.Range • Observable.FromAsync() – Task is equivalent to single-value Observable • Observable.Create(…) – You provide the logic to produce values (like yield return)

reactive extensions - mark sowul - www.solsoftsolutions.com 22

Here are some ways to create IObservables that are reasonably straightforward. We’ve seen Range, later we’ll see Create. Observable.FromAsync is important – there’s another equivalence: an asynchronous sequence that returns a single value, and Task So that’s another way to think about Observable: a multi-valued task

22 fancier IObservables • Observable.Timer – returns one value, after the given time • Observable.Interval( TimeSpan.FromMinutes(1)) – Increments on time intervals – Yields 0; a minute later, yields 1, etc – Infinite sequence • Observable.FromEventPattern – Yield value each time the event fires

reactive extensions - mark sowul - www.solsoftsolutions.com 24

Here are some more ways to create IObservable.

So Observable.Interval would be a good way to replicate my initial example with the periodic timer

FromEventPattern will turn an event into a sequence.

Note that Interval and FromEventPattern are infinite sequences, so disposing of the subscription is the only real way to stop them!

24 events example • Update mouse position in status bar Observable.FromEventPattern ( handler => this.MouseMove += handler, handler => this.MouseMove -= handler ) .Select(eventInfo => eventInfo.EventArgs.Location) .Sample(TimeSpan.FromSeconds(1))

MousePositions.Subscribe(p => statusLabel.Text = p.ToString());

reactive extensions - mark sowul - www.solsoftsolutions.com 25

This is a silly example, but I think it starts to illustrate the power of Reactive Extensions. I’m going to have a form that puts the mouse position in the status bar.

But now I’m going to do something more interesting: I only want to update the position once a second.

I think that Sample line is a real game changer: before that, this all just seems like a roundabout way of doing things you already could do: why go through all this trouble instead of just having the event wired to update the status label?

But think of how you would implement a status bar that shows the mouse position once a second. Probably you’d have a timer that polls for the position once a second or something. But that would lose the “event” behavior, and be looking for changes every second even if there aren’t any.

I think it’s way more straightforward now to think of it (and many other events) this way, as an asynchronous sequence of values, and I think that’s reinforced by the code changes you’d make to add this “sampling behavior”: this is literally all the code needed to make this behavior happen; you don’t have to tear the whole thing apart. One of the benefits of reactive is that time is already a built-in concept.

There’s also “.Throttle”, which will basically hold off on emitting values until time has

25 elapsed – in this case, as long as I would move the mouse, it won’t update, until I stop moving the mouse for a second.

--- (Don’t speak this)

Note that because WinForms predates EventHandler, you actually have to do the following which I omitted for brevity return Observable.FromEventPattern ( handler => this.MouseMove += handler, handler => this.MouseMove -= handler )

25 status bar demo

reactive extensions - mark sowul - www.solsoftsolutions.com 26

26

value proposition Coding Complexity Coding

Problem Complexity

Traditional techniques Reactive extensions

reactive extensions - mark sowul - www.solsoftsolutions.com 27

I mean this is just a made up graph, but this is a visual illustration of how I view the Reactive Extensions: it adds some upfront complexity, but then when the problem becomes more complex or needs a new behavior, the coding doesn’t usually just explode in complexity and/or need to be rewritten. Usually you can just chain in some other operators into the pipeline…again, “usually”

27 temperature sensor example

• Imaginary temperature New Temperature Max Temperature sensor 65° 65° 68° 68° – Emits new value when 66° changed 72° 72° • Want to track max 70° temperature 71° 75° 75° • Only spit out new max value 70° when it changes 68° • How would you implement?

reactive extensions - mark sowul - www.solsoftsolutions.com 28

So let’s go back to the temperature sensor example, which is here for a refresher

28 temperature sensor example

• Here’s how you can produce the rolling maximum:

IObservable readings…

IObservable rollingMax = readings .Scan((accumulated, next) => Math.Max(accumulated, next) ) .DistinctUntilChanged(); await rollingMax .ForEachAsync(newMax => Console.WriteLine(newMax));

reactive extensions - mark sowul - www.solsoftsolutions.com 29

This is how I would think of it

I know this is a lot to unpack: I’m trying to strike a balance between “talking endlessly about the Reactive stuff” and “showing actual code”

“Scan” is a rolling aggregation (as compared to a “one-valued” Aggregation like “Max”) So basically each new value in the sequence, we’re going to compare with the previous Max, and output a new value each time we get a new input. If the new temperature is lower than the max, we will just spit out that same maximum again.

DistinctUntilChanged will not output the value if it’s the same as the previous value, so that will keep us from emitting the new maximum if it’s the same as the previous maximum.

29 temperature sensor example

Readings sequence Scan sequence DistinctUntilChanged 65° 65° 65° 68° 68° 68° 66° 68° 72° 72° 72° 70° 72° 71° 72° 75° 75° 75° 70° 75° 68° 75°

reactive extensions - mark sowul - www.solsoftsolutions.com 30

So here’s what I mean about Scan and DistinctUntilChanged “Readings” is what we’re getting as our source. Scan is doing a rolling maximum. And DistinctUntilChanged throws away any non-changes

30 temperature sensor example

• Here’s how you can produce the rolling maximum:

IObservable readings…

IObservable rollingMax = readings .Scan((accumulated, next) => Math.Max(accumulated, next) ) .DistinctUntilChanged(); await rollingMax .ForEachAsync(newMax => Console.WriteLine(newMax));

reactive extensions - mark sowul - www.solsoftsolutions.com 31

(So Scan and DistinctUntilChanged are just some nice extra operators that exist with IObservable; you could totally write them for IEnumerable too by the way, with yield return or something)

At the end, in this case, we just write to the console. But note how this lets us break down and compose the various parts

1) we can create a dummy sequence of “readings” for testing. That lets us separately exercise the rolling maximum logic 2) we can write to the console, or we can write a file, or we can send over the network, whatever

So, this all looks very similar to what you’d do with IEnumerable. And indeed, if we just had a bunch of values in a list, we could use IEnumerable and would want to break things down for the same reasons.

The important part here is that the values are being pushed to us, and so we would have not been able really to use IEnumerable, we would have some event or timer (just like in the mouse example) and the code for that would be very different.

The reactive extensions basically lets us treat events and polling and things like that, very similar to how we would treat it if we did just have a list.

31 consuming IObservables • various other methods – ForEachAsync – LINQ operators (where, select, etc) • These produce new IObservables, similar to IEnumerable – await (for single-element sequences) • await sequence.FirstOrDefault(), await sequence.Max() – ToEnumerable • Stores up the elements until they are consumed, blocks if next element is not yet produced

reactive extensions - mark sowul - www.solsoftsolutions.com 35

More ways to consume observables. These are some of the slick ways I was mentioning earlier

Remember that since they are “push”-based and asynchronous, it can sometimes be tricky to come out of “observable land” back into synchronous-land

I’ve shown the ForEachAsync, but what everything boils down to is subscription.

35 end of act II

reactive extensions - mark sowul - www.solsoftsolutions.com 36

Questions so far? Let’s look at some other, less artificial examples

36 web service example • parse a sequence of results from web service and write them to disk – scalability/efficiency – testability/flexibility • IEnumerable? – synchronous; how to use with HttpClient.GetAsync()? • Task>? – must buffer all responses; wastes time and memory

reactive extensions - mark sowul - www.solsoftsolutions.com 37

Here’s a simple version of a problem I needed to solve

This seems simpler than it is: 1) connect to a web service 2) retrieve each line 3) parse the line 4) do something with each parsed item

The hard part is with (4) – how do you “do something with the result” without hard- coding it in? Again, think testability/maintainability.

37 Observable.Create • Earlier we saw “subscribe” – OnNext – OnError – OnCompleted • Subscription: encapsulated with IObserver • Publishing involves producing these events – Create your own sequence with Observable.Create

reactive extensions - mark sowul - www.solsoftsolutions.com 38

Observable.Create takes in the target to which you will emit results (OnNext), etc Remember that (by default), every time you subscribe, it creates a new generator: this is basically how IEnumerable works too, you’ll recall

38 Observable.Create example private static IObservable CreateObservableForNumbers() { return Observable.Create((IObserver observer) => { observer.OnNext(1); observer.OnNext(2);

for (int i = 3; i <= 10; i++) { observer.OnNext(i); }

return Disposable.Empty; }); }

reactive extensions - mark sowul - www.solsoftsolutions.com 39

This is just a simple, dumb example, of using our own logic to create an observable to emit 1 through 10

observer.OnNext is simply the equivalent of List.Add or yield return

In this case it will automatically call OnComplete when you’re done and OnError if there’s an exception that occurs

Remember I talked about subscription returning a Disposable: even if you don’t have anything to dispose you have to return one, there’s an empty one built in. The asynchronous case is a bit different.

39 web service with IObservable private static IObservable CreateObservableForLines(string url) { return Observable.Create(async (IObserver observer) => { using (var client = new HttpClient()) { using (var response = await client.GetAsync(url)) { using (var stream = await response.Content.ReadAsStreamAsync()) { using (var streamReader = new StreamReader(stream)) { while (!streamReader.EndOfStream) { string line = await streamReader.ReadLineAsync(); observer.OnNext(line); } }}}}}); } reactive extensions - mark sowul - www.solsoftsolutions.com 40

So how would we use this to create a web service observable? Here’s an asynchronous example.

This looks very long, but it’s mostly just boilerplate. Note that this supports async. There’s another overload that takes in a CancellationToken too. That’s canceled if the subscription is disposed, so you can use the cancellation token to end things early. I omitted that code here to save space.

So now we have an observable that spits out each line of a web service call!

40 web service with IObservable async Task ReadFromWebAsync() { string url = …;

IObservable lineSource = CreateObservableForLines(url);

await lineSource.ForEachAsync(line => Console.WriteLine(line)); } reactive extensions - mark sowul - www.solsoftsolutions.com 41

Now that we have that lines observable, we can do something like this

This is now 1) testable (you can create a dummy set of lines) 2) efficient/scalable (doesn’t need to store up the whole set of results; they can be streamed out) 3) flexible (we can do whatever we want with the results: write them to screen, write them to disk, etc), we can also parse each line (CSV for example), with .Select for example 1) Note that you can call async methods in Select, but it is tricky

41 find as you type example • first, let’s get a “sequence” of search queries • Assume we have a text box to enter queries

IObservable queriesObservable = Observable.FromEventPattern( handler => textBox.TextChanged += handler, handler => textBox.TextChanged -= handler )

.Select(eventInfo => textBox.Text)

.Throttle(TimeSpan.FromSeconds(.5));

reactive extensions - mark sowul - www.solsoftsolutions.com 42

Let’s look at another problem: a find-as-you-type text box

First thing, we will get the queries that the user is typing. And we’ll just get it as an asynchronous sequence.

Throttle, as I believe I mentioned before, basically holds off on emitting values until they stop being produced. So in this case, as long as you’re still typing, we’ll keep getting change events, so until you stop typing for half a second, we won’t emit any of the queries. Once you stop, the most recent one will be spit out.

42 find as you type example • from the sequence of queries, we need to obtain sequences of results • we will encounter IObservable> – this seems scary, but think List> • each time the user types, we will get a new query; each of those queries will have multiple results

reactive extensions - mark sowul - www.solsoftsolutions.com 43

So we have a sequence of search queries. For each of those, we want to search and come back with a set of results. Do we want to get the whole set of results, and only then update the UI? Or do we want to add them as they come in?

Let’s add them as they come in. So that’s another IObservable...so we’re going to have IObservable which is similar to a list of lists

43 results illustration hel- hello- hello world

• hel result 1 • hello result 1 • hello world • hel result 2 • hello result 2 result 1 • hel result 3 • hello result 3 • hello world • hel result 4 result 2

reactive extensions - mark sowul - www.solsoftsolutions.com 44

Here’s an illustration as I type “hello world” Our “queries” observable will have, say three entries (hel, hello, hello world) Each of those will have a set of results

44 find as you type example • Search function (results for one query): IObservable GetSearchResults(string query)… • Wire the queries to it: IObservable> resultSets = queries .Select(query => GetSearchResults(query));

reactive extensions - mark sowul - www.solsoftsolutions.com 45

We might implement GetSearchResults similar to the web query example we saw before

So we have the sequence of queries, and for each of those, we get an IObservable of results, so we have IObservable>

45 results illustration

hel- hello- hello world

•GetSearchResults(hel) •GetSearchResults(hello) •GetSearchResults(hello •hel result 1 •hello result 1 world) •hel result 2 •hello result 2 •hello world result 1 •hel result 3 •hello result 3 •hello world result 2 •hel result 4

reactive extensions - mark sowul - www.solsoftsolutions.com 46

For each entry in the “query” sequence, we select GetSearchResults, which gives us a new sequence for each partial query

46 handling the search results resultSets .ObserveOn(listBoxResults) .Subscribe(newResultSet => { //replace list box values //with new result set });

reactive extensions - mark sowul - www.solsoftsolutions.com 47

I’m going to walk through one way to deal with the results. It has a flaw, so I wouldn’t necessarily write everything down here, but it’s easier to understand this way.

First thing to note is ObserveOn. Basically, there’s a callback each time an element is produced. ObserveOn ensures that the callback will occur on a particular synchronization context, i.e. the UI thread in this case. There’s also an ObserveOnDispatcher, which would be similar for XAML UI.

--- (Don’t speak this) Note that there’s also a “SubscribeOn”, but that’s for setting which thread wires up the pipeline we are creating https://stackoverflow.com/questions/7579237/whats-the-difference-between- subscribeon-and-observeon#7582727 ---

Basically what we’ve done so far at this stage is: 1) we have an observable of each query the user types in 2) Each of those queries produces a result set 3) we ensure that each time we get a new result set, our callback is on the UI thread

47 Now we need to do something with the new results we get

47 find as you type example … //(resultSets.ObserveOn…) .Subscribe(newResultSet => { listBoxResults.Items.Clear(); newResultSet .ObserveOn(listBoxResults) .Subscribe(result => { listBoxResults.Items.Add(result); }); });

reactive extensions - mark sowul - www.solsoftsolutions.com 48

So each time we get a new set of results (because there’s a new query), what we could do is just clear the existing results and subscribe to that new sequence, adding them to the list box when they become available. This subscription also has to be on the UI thread

I know this is daunting so I’ll reiterate: 1) we have a list of search queries, and each time we get a new query, we search for the results, which gives us a new set of query results (“resultSets”) 2) when we get that new result set, we clear the list box (and we’re making sure this is on the UI thread) 1) if our result set were just a list (IObservable>), we could just set the listBoxResults items to be the contents of the list 2) but instead, that new result set is an Observable, so we need to subscribe 1) Each time a new result is available in the result set, we can add it to our list. In a XAML UI we would instead probably add to an ObservableCollection

Any questions here?

48 results illustration

hel- hello- hello world

•GetSearchResults(hel) •GetSearchResults(hello) •GetSearchResults(hello •hel result 1 •hello result 1 world) •hel result 2 •hello result 2 •hello world result 1 •hel result 3 •hello result 3 •hello world result 2 •hel result 4

reactive extensions - mark sowul - www.solsoftsolutions.com 49

So each time we get a new result set (GetSearchResults is called), we clear out the list box, and subscribe to that result set. Then, for each result that comes in, we add it to the list box

49 find as you type demo 1

reactive extensions - mark sowul - www.solsoftsolutions.com 51

Let me demonstrate (demonstrate good and bad behavior)

The more serious problem with the setup I just described is that the results for “hello” might still be coming in, even after we type “hello world”. This does highlight another consideration about the Reactive Extensions…asynchronous stuff is still pretty hard

51 multiple result timeline

query 1 results

a query 2 results

b

j query 3 results

c

w

k

x

l

y

m

reactive extensions - mark sowul - www.solsoftsolutions.com 52

Here you can visualize what’s happening Query 2’s results start coming back (“j, k, l…”) while query 1 is still producing more items (“b, c”)

We can handle this by combining them into one sequence

52 combining multiple results • Flattening IObservable> to IObservable – Concat • all results from sequence 1, then all results from sequence 2 – Merge • interleave results as we get them – Switch • as each new sequence becomes available, the previous one is discarded (and so are any results from it)

reactive extensions - mark sowul - www.solsoftsolutions.com 53

So, there are a couple of operators that can collapse a sequence of sequences into just one sequence. I’ll describe them and then show a diagram.

(Describe)

If we use “Switch”, then when we get a new sequence, we throw away the old one (so once we get “hello world”, the “hello” sequence will be thrown away and stop bothering us)

53 combining multiple result sets

query 1 results Concat Merge Switch

a query 2 results a a a

b b b j

j query 3 results c j w

c j c x

w k w y

k l k

x m x

l w l

y x y

m y m

reactive extensions - mark sowul - www.solsoftsolutions.com 54

Note that we get one flattened sequence in each case.

Also note that with Switch, each time a new result set comes along, we ignore the results from any of the prior ones (we will have unsubscribed too)

..

Note that you can also combine sequences by “zipping” them together, for example if you have a status indicator observable for a web service and a status indicator observable for a database, you can pair them together into an “overall” status http://www.introtorx.com/Content/v1.0.10621.0/12_CombiningSequences.html#Pari ngSequences

54 handling the find results resultSets .Switch() .ObserveOn(listBoxResults) .Subscribe(result => { listBoxResults.Items.Add(result); });

reactive extensions - mark sowul - www.solsoftsolutions.com 55

So let’s use Switch. Now we have combined the results, throwing away an old result stream once a new one comes along.

Of course now we have another problem, how do we clear out the list when the results need to be replaced? Also, what should we do about the buffering? One thing at a time.

This is the kind of thing that can get annoying about reactive, figuring out how best to deal with these less-straightforward situations.

There are (at least) two options I’ll discuss.

55 handling the find results resultSets .ObserveOn(listBoxResults) .Do(resultSet => listBoxResults.Items.Clear()) .Switch() .ObserveOn(listBoxResults) .Subscribe(result => { listBoxResults.Items.Add(result); });

reactive extensions - mark sowul - www.solsoftsolutions.com 56

First, there’s a “Do” ‘operator’ that can be used at a given level to produce a side- effect. This should be used sparingly, because it sort of breaks up the pipeline.

Sure enough, we can’t really extract the “Switch” level to its own thing and test it, because it’s now wired up to the list box. Code that you can’t test in isolation is a huge red flag!

Note that we need both parts to have ObserveOn.

56 handling the find results var query = … query.Subscribe(q => listBox.Clear()) var results = …//(query.Select…) results .Switch() .ObserveOn(listBox) .Subscribe(result => { listBoxResults.Items.Add(result); });

reactive extensions - mark sowul - www.solsoftsolutions.com 60

The other way I mentioned would be to have multiple subscriptions. Have an additional subscription that just clears out the list

1) subscribe to the queries and in that subscription, clear out the list box 2) also do the result set subscription with switch (and buffer) that we just saw 1) The disadvantage is that we have two separate generators now, one for each subscription. If we subscribed twice to the result sets, we’d be searching twice! 2) Another disadvantage is that because we have multiple things going on simultaneously, there’s no guarantee of order. Maybe we get the first result, and then clear out the list. It’s very unlikely, but there’s no guarantee

How can we solve that?

60 multiple subscriptions

Subscription 1 Subscription 2 Subscription 2 Clear list Fill results Fill results

Subscription 1 Switch Generator logic Generator logic Clear list Subscription Switch [Multicast]

Subscription Generator

reactive extensions - mark sowul - www.solsoftsolutions.com 61

So in the first case we would have two independent pipelines What we really want is something like this, where we run one pipeline and send the results out to multiple subscriptions

I’ll show a diagram in a moment

61 clear list

hel- hello- hello world

•GetSearchResults(hel) •GetSearchResults(hello) •GetSearchResults(hello •hel result 1 •hello result 1 world) •hel result 2 •hello result 2 •hello world result 1 •hel result 3 •hello result 3 •hello world result 2 •hel result 4

reactive extensions - mark sowul - www.solsoftsolutions.com 62

As a reminder, here’s the sequence of events. This is what is being multicast out.

The “clear list” only cares about each result set – it doesn’t care about any of the results within each result set.

Each time we get a new result set we clear the list.

62 fill results

query 1 results Switch

a query 2 results a

b j

j query 3 results w

c x

w y

k

x

l

y

m

reactive extensions - mark sowul - www.solsoftsolutions.com 63

The second subscription is the one that combines all the result sets into one All we’re doing is adding each item to the list as we get it We are relying on the other subscription to clear the list in the meantime

63 multiple connections var resultSetsMultiple = resultSets .Publish() .RefCount(); resultSetsMultiple .ObserveOn(listBoxResults) .Subscribe(set => listBoxResults.Items.Clear()); resultSetsMultiple .Select(set => set.Buffer(…) .Switch() .ObserveOn(listBoxResults) .Subscribe(results => { foreach… listBoxResults.Items.Add(result); });

reactive extensions - mark sowul - www.solsoftsolutions.com 64

You can have multiple connections to the same observable. Publish will do that.

Once you have Publish, there are two ways to actually “start” and “stop” the observable (since it’s not just tied to a subscription anymore). RefCount basically keeps it going as long as there’s at least one subscription.

Otherwise you can call Connect to explictly start it (even before anything is subscribed!). That will return a Disposable that you can use to unsubscribe.

So now we have multiple connections to the same resultSet observable. The logic will only be called once but the results will be fired out to each of those subscriptions.

64 find as you type demo 2

reactive extensions - mark sowul - www.solsoftsolutions.com 65

65 end of act III

reactive extensions - mark sowul - www.solsoftsolutions.com 66

So I know I just went through a ton of information, and I fully expect that a decent amount of the more detailed stuff is a bit too complicated if you haven’t encountered this before.

The main takeaway I want to give you is to introduce you to the Reactive Extensions and show you a different way of thinking about these problems. Hopefully the next time you have some nasty problem with events, or timers, asynchronous loops, and so on, you’ll remember to keep Reactive as a tool in your software toolbox.

Any other questions, before I wrap up?

66 a note on void • Outside of Reactive, “void” is always separate – void MyMethod() vs T MyMethod – Action vs Func delegates – Task vs Task – etc. • In Reactive, this is handled by a special “Unit” type – imagine if you could have Task, Func, etc.

reactive extensions - mark sowul - www.solsoftsolutions.com 67

This idea comes from

So if you just wanted a sequence of “this event is fired”, for example, you’d use the “Unit” generic type.

67 further resources • intro to rx – extremely useful (even though it’s based on an old version) – http://www.introtorx.com/ • ReactiveX home – http://reactivex.io/ • msdn hands on lab – https://blogs.msdn.microsoft.com/rxteam/2010/07/15/rx-hands-on- labs-published/ – Note that it’s also based on an old version – Now Reactive is installed via NuGet

reactive extensions - mark sowul - www.solsoftsolutions.com 68

68 following up • feedback! – https://www.surveymonkey.com/r/HYMFLGH • www.solsoftsolutions.com – slides posted soon (check blog) – sign up for newsletter • [email protected]

reactive extensions - mark sowul - www.solsoftsolutions.com 69

People will probably take pictures of this page so keep it up a bit

69