Skip to content

Commit 06f2450

Browse files
committed
3.2 Reworked chapter
1 parent 88bc048 commit 06f2450

File tree

1 file changed

+21
-22
lines changed

1 file changed

+21
-22
lines changed

Part 3 - Taming the sequence/2. Leaving the monad.md

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# Leaving the monad
22

3-
A monad is an abstract concept from functional programming that is unfamiliar to most programmers. It is beyond the scope of this guide to teach monads in general. To quote www.introtorx.com
3+
A monad is an abstract concept from functional programming that is unfamiliar to most programmers. It is beyond the scope of this guide to about teach monads in general. In www.introtorx.com we find a short definition:
44
> Monads are a kind of abstract data type constructor that encapsulate program logic instead of data in the domain model.
55
6-
It is interesting to understand that Rx, and more specifically the observable, is a monad. Rx code declares what needs to be done but the actual processing happens not when Rx statements are executed, but when values are emitted. Readers may find it interesting to read more about monads in general. For this guide, when refering to the monad the reader only needs to think about the observable.
6+
Monads are of interest to us, because Rx, and more specifically the observable, is a monad. Rx code declares what needs to be done but the actual processing happens not when Rx statements are executed, but rather when values are emitted. Readers may find it interesting to read more about monads in general. For this guide, when refering to monads the reader only needs to think about the observable.
77

88
## Why leave the monad
99

10-
There are two main reasons one may want to leave the monad. The first reason is that a new Rx developer will still be more comfortable in the more traditional paradigms. Doing part of the computation in a familiar style may make code easier to understand. Another reason is to interact with components and libraries that weren't designed with Rx in mind. When refactoring existing code into Rx, it may be useful to have Rx behave in a blocking way.
10+
There are two main reasons one may want to leave the monad. The first reason is that a new Rx developer will still be more comfortable in more traditional paradigms. Doing parts of the computation in a different paradigm may enable you to get some parts working, while you're still figuring out how to do things in Rx. Another reason to leave the monad is to interact with components and libraries that weren't designed with Rx in mind. When refactoring existing code into Rx, it may be useful to have Rx behave in a blocking way.
1111

1212
## BlockingObservable
1313

@@ -21,7 +21,7 @@ or the static factory of `BlockingObservable`
2121
public static <T> BlockingObservable<T> from(Observable<? extends T> o)
2222
```
2323

24-
`BlockingObservable` does not extend the `Observable` and it can't be used with our usual Rx operators. It has its own implementations of a small set functions that allow you to extract data out of an `Observable` in a blocking manner. Many of those methods are the blocking counterparts to methods that we have already seen.
24+
`BlockingObservable` does not extend the `Observable` and it can't be used with our usual Rx operators. It has its own implementations of a small set functions, which allow you to extract data out of an `Observable` in a blocking manner. Many of those methods are the blocking counterparts to methods that we have already seen.
2525

2626
### forEach
2727

@@ -34,8 +34,7 @@ Observable<Long> values = Observable.interval(100, TimeUnit.MILLISECONDS);
3434

3535
values
3636
.take(5)
37-
.forEach(
38-
v -> System.out.println(v));
37+
.forEach(v -> System.out.println(v));
3938
System.out.println("Subscribed");
4039
```
4140
Output
@@ -48,18 +47,17 @@ Subscribed
4847
4
4948
```
5049

51-
The code here behaves like `subscribe` would. First you register an observer (no overload for `forEach` accepts `Observer` but the semantics are the same). Execution then proceeds to print "Subscribed" and exits our snippet. As values are emitted (the first one with a 100ms delay), they are passed to our observer for processing.
50+
The code here behaves like `subscribe` would. First you register an observer (no overload for `forEach` accepts `Observer`, but the semantics are the same). Execution then proceeds to print "Subscribed" and exits our snippet. As values are emitted (the first one with a 100ms delay), they are passed to our observer for processing.
5251

53-
`BlockingObservable` doesn't have a `subscribe` function, but it has `forEach`. Let see the same example with `BLockingObservable`
52+
`BlockingObservable` doesn't have a `subscribe` function, but it has `forEach`. Lets see the same example with `BLockingObservable`
5453

5554
```java
5655
Observable<Long> values = Observable.interval(100, TimeUnit.MILLISECONDS);
5756

5857
values
5958
.take(5)
6059
.toBlocking()
61-
.forEach(
62-
v -> System.out.println(v));
60+
.forEach(v -> System.out.println(v));
6361
System.out.println("Subscribed");
6462
```
6563
Output
@@ -72,7 +70,7 @@ Output
7270
Subscribed
7371
```
7472

75-
We see here that the call to `forEach` blocked until the observable completed. Another difference is that there can be no handlers for `onError` and `onCompleted`. `onCompleted` is a given if the execution continues and exceptions are thrown into the runtime to be caught:
73+
We see here that the call to `forEach` blocked until the observable completed. Another difference is that there can be no handlers for `onError` and `onCompleted`. `onCompleted` is a given if the execution continues, while exceptions will be thrown into the runtime to be caught:
7674

7775
```java
7876
Observable<Long> values = Observable.error(new Exception("Oops"));
@@ -81,8 +79,7 @@ try {
8179
values
8280
.take(5)
8381
.toBlocking()
84-
.forEach(
85-
v -> System.out.println(v));
82+
.forEach(v -> System.out.println(v));
8683
}
8784
catch (Exception e) {
8885
System.out.println("Caught: " + e.getMessage());
@@ -97,7 +94,7 @@ Subscribed
9794

9895
### first, last, single
9996

100-
`BlockingObservable` has methods for `first`, `last` and `single`, along with implementations for default values `firstOrDefault`, `lastOrDefault` and `singleOrDefault`. Having read about their namesakes in `Observable`, you already know the returned value is defined. Once the again, the difference in the blocking nature of the methods. They don't return an observable that will the value when it is available. Rather, they block until the value is available and return the value itself, without the surrounding observable.
97+
`BlockingObservable` has methods for `first`, `last` and `single`, along with implementations for default values `firstOrDefault`, `lastOrDefault` and `singleOrDefault`. Having read about their [namesakes](/Part%202%20-%20Sequence%20Basics/4.%20Aggregation.md#first) in `Observable`, you already know what the returned value is. Once again, the difference is the blocking nature of the methods. They don't return an observable that will emit the value when it is available. Rather, they block until the value is available and return the value itself, without the surrounding observable.
10198

10299
```java
103100
Observable<Long> values = Observable.interval(100, TimeUnit.MILLISECONDS);
@@ -138,7 +135,7 @@ Caught: java.lang.IllegalArgumentException: Sequence contains too many elements
138135

139136
### To Iterable
140137

141-
You can transform your observables to [iterables](https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html) throught a variety of methods on `BlockingObservable`. Iterables are pull-based, unlike Rx which is push-based. That means that when the consumer is ready to consume a value, one is requested with `next()` method on the iterable's [Iterator](https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html). The call to `next()` will either return a value immediately or block until one is ready.
138+
You can transform your observables to [iterables](https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html) throught a variety of methods on `BlockingObservable`. Iterables are pull-based, unlike Rx, which is push-based. That means that when the consumer is ready to consume a value, one is requested with `next()` on the iterable's [Iterator](https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html). The call to `next()` will either return a value immediately or block until one is ready.
142139

143140
There are several ways to go from `BlockingObservable<T>` to `Iterable<T>` and each has a different behaviour.
144141

@@ -149,7 +146,7 @@ public java.lang.Iterable<T> toIterable()
149146
```
150147
![](https://github.com/ReactiveX/RxJava/wiki/images/rx-operators/B.toIterable.png)
151148

152-
In this implementation, all the emitted values are collected and cached. Because of the caching, no items will be missed. The iterator gets the next value immediately or blocks until the next value becomes available.
149+
In this implementation, all the emitted values are collected and cached. Because of the caching, no items will be missed. The iterator gets the next value as soon as possible, either immediately if it has already occured, or it blocks until the next value becomes available.
153150

154151
```java
155152
Observable<Long> values = Observable.interval(500, TimeUnit.MILLISECONDS);
@@ -212,7 +209,7 @@ In this example the consumer is slower than the producer and always misses the n
212209
public java.lang.Iterable<T> latest()
213210
```
214211

215-
The `latest` method is similar to `next`, with the difference that it will cache one value. The iterator only blocks if no events have been emitted by the observable since the last value consumed. As long as there has been a single event, the iterator will return immediately with a value, or with the termination of the iteration.
212+
The `latest` method is similar to `next`, with the difference that it will cache one value. The iterator only blocks if no events have been emitted by the observable since the last value was consumed. As long as there has been a new event, the iterator will return immediately with a value, or with the termination of the iteration.
216213

217214
```java
218215
Observable<Long> values = Observable.interval(500, TimeUnit.MILLISECONDS);
@@ -238,7 +235,7 @@ Emitted: 3
238235
Emitted: 4
239236
```
240237

241-
When using the `latest` iterator, values will be skipped if they are not pulled before the next event is emitted. If the consumer is faster than the producer, the iterator will block in wait for the next value.
238+
When using the `latest` iterator, values will be skipped if they are not pulled before the next event is emitted. If the consumer is faster than the producer, the iterator will block and wait for the next value.
242239

243240
It is interesting here that 4 was never consumed. That was because an `onCompleted` followed immediately, resulting in the next pull seeing a terminated observable. The implicit `iterator.hasNext()` method reports a terminated observable without checking if the last value has been consumed.
244241

@@ -249,7 +246,7 @@ public java.lang.Iterable<T> mostRecent(T initialValue)
249246
```
250247
![](https://github.com/ReactiveX/RxJava/wiki/images/rx-operators/B.mostRecent.png)
251248

252-
The `mostRecent` iterator never blocks. It caches a single value, therefore values may be skipped is the consumer is slow. Unlike `latest`, the last cached value is always returned, resulting in repetitions if the consumer is faster than the producer. To allow the `mostRecent` iterator to be completely non-blocking, an initial value is needed. That value is returned if the observable has not emitted any values yet.
249+
The `mostRecent` iterator never blocks. It caches a single value, therefore values may be skipped if the consumer is slow. Unlike `latest`, the last cached value is always returned, resulting in repetitions if the consumer is faster than the producer. To allow the `mostRecent` iterator to be completely non-blocking, an initial value is needed. That value is returned if the observable has not emitted any values yet.
253250

254251
```java
255252
Observable<Long> values = Observable.interval(500, TimeUnit.MILLISECONDS);
@@ -281,7 +278,7 @@ Emitted: 4
281278

282279
### Future
283280

284-
A `BlockingObservable<T>` can be presented as a [Future<T>](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html) using the `toFuture` method. This method only creates an instance of `Future` and does not block. Execution blocks as necessary when getting the value. `Future` allows the consumer to decide how to approach an asynchronous operation. `Future` are also capable of reporting errors in the operation.
281+
A `BlockingObservable<T>` can be presented as a [Future<T>](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html) using the `toFuture` method. This method only creates an instance of `Future` and does not block. Execution blocks as necessary when getting the value. `Future` allows the consumer to decide how to approach an asynchronous operation. A `Future` is also capable of reporting errors in the operation.
285282

286283
```java
287284
Observable<Long> values = Observable.timer(500, TimeUnit.MILLISECONDS);
@@ -304,7 +301,7 @@ Emitted: 0
304301

305302
### Deadlocks
306303

307-
So far we were able to ignore potential deadlocks. Rx's non-blocking nature makes it harder to create unnecessary deadlocks. However, in this chapter we returned to blocking methods, thus bringing deadlocks again to the forefront.
304+
So far we were able to ignore potential deadlocks. Rx's non-blocking nature makes it harder to create unnecessary deadlocks. However, in this chapter we returned to blocking methods, thus bringing deadlocks to the forefront again.
308305

309306
The example below would work as a non-blocking case. But because we used blocking operations, it will never unblock
310307

@@ -317,9 +314,11 @@ subject.onNext(2);
317314
subject.onCompleted();
318315
```
319316

317+
`forEach` returns only after the termination of the sequence. However, the termination event requires `forEach` to return before being pushed. Therefore, `forEach` will never unblock.
318+
320319
### Non-terminating sequences
321320

322-
Some blocking ways to access observables, such as `last()`, require the observable to terminate to unblock. Others, like `first()`, require it to emit at least one event to unblock. Using those methods on `Observable` isn't a big danger, as they only return an non-terminating observable. These same `methods` on `BlockingObservable` can result in a permanent block if the consumer hasn't taken the time to enforce some guarantees, such as timeouts (we will see how this is done in [Timeshifter sequences](/Part 3 - Taming the sequence/5. Time-shifted sequences.md)).
321+
Some blocking ways to access observables, such as `last()`, require the observable to terminate to unblock. Others, like `first()`, require it to emit at least one event to unblock. Using those methods on `Observable` isn't a big danger, as they only return a non-terminating observable. These same `methods` on `BlockingObservable` can result in a permanent block if the consumer hasn't taken the time to enforce some guarantees, such as timeouts (we will see how this is done in [Timeshifter sequences](/Part 3 - Taming the sequence/5. Time-shifted sequences.md)).
323322

324323

325324
#### Continue reading

0 commit comments

Comments
 (0)