Skip to content

Commit f3c8862

Browse files
fjoshuajrakarnokd
authored andcommitted
Update DESIGN.md (#6033)
I've just read the DESIGN.md and noticed some things that I could do to improve the quality of the DESIGN.md. So as a result of my "proofreading" I mainly: - Added periods at the ending of some sentences. - Did case matching of certain types and terms. e.g. `OnSubscribe` -> `onSubscribe` OR flowable -> `Flowable`. Hope it helps! 😄
1 parent e8156d5 commit f3c8862

File tree

1 file changed

+69
-69
lines changed

1 file changed

+69
-69
lines changed

DESIGN.md

Lines changed: 69 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ Producer is in charge. Consumer has to do whatever it needs to keep up.
3838

3939
Examples:
4040

41-
- `Observable` (RxJS, Rx.Net, RxJava v1.x without backpressure, RxJava v2)
42-
- Callbacks (the producer calls the function at its convenience)
43-
- IRQ, mouse events, IO interrupts
44-
- 2.x `Flowable` (with `request(n)` credit always granted faster or in larger quantity than producer)
45-
- Reactive Streams `Publisher` (with `request(n)` credit always granted faster or in larger quantity than producer)
46-
- Java 9 `Flow.Publisher` (with `request(n)` credit always granted faster than or in larger quantity producer)
41+
- `Observable` (RxJS, Rx.Net, RxJava v1.x without backpressure, RxJava v2).
42+
- Callbacks (the producer calls the function at its convenience).
43+
- IRQ, mouse events, IO interrupts.
44+
- 2.x `Flowable` (with `request(n)` credit always granted faster or in larger quantity than producer).
45+
- Reactive Streams `Publisher` (with `request(n)` credit always granted faster or in larger quantity than producer).
46+
- Java 9 `Flow.Publisher` (with `request(n)` credit always granted faster than or in larger quantity than producer).
4747

4848

4949
##### Synchronous Interactive/Pull
@@ -52,11 +52,11 @@ Consumer is in charge. Producer has to do whatever it needs to keep up.
5252

5353
Examples:
5454

55-
- `Iterable`
56-
- 2.x/1.x `Observable` (without concurrency, producer and consumer on the same thread)
57-
- 2.x `Flowable` (without concurrency, producer and consumer on the same thread)
58-
- Reactive Streams `Publisher` (without concurrency, producer and consumer on the same thread)
59-
- Java 9 `Flow.Publisher` (without concurrency, producer and consumer on the same thread)
55+
- `Iterable`.
56+
- 2.x/1.x `Observable` (without concurrency, producer and consumer on the same thread).
57+
- 2.x `Flowable` (without concurrency, producer and consumer on the same thread).
58+
- Reactive Streams `Publisher` (without concurrency, producer and consumer on the same thread).
59+
- Java 9 `Flow.Publisher` (without concurrency, producer and consumer on the same thread).
6060

6161

6262
##### Async Pull (Async Interactive)
@@ -65,24 +65,24 @@ Consumer requests data when it wishes, and the data is then pushed when the prod
6565

6666
Examples:
6767

68-
- `Future` & `Promise`
69-
- `Single` (lazy `Future`)
70-
- 2.x `Flowable`
71-
- Reactive Streams `Publisher`
72-
- Java 9 `Flow.Publisher`
73-
- 1.x `Observable` (with backpressure)
74-
- `AsyncEnumerable`/`AsyncIterable`
68+
- `Future` & `Promise`.
69+
- `Single` (lazy `Future`).
70+
- 2.x `Flowable`.
71+
- Reactive Streams `Publisher`.
72+
- Java 9 `Flow.Publisher`.
73+
- 1.x `Observable` (with backpressure).
74+
- `AsyncEnumerable`/`AsyncIterable`.
7575

7676
There is an overhead (performance and mental) for achieving this, which is why we also have the 2.x `Observable` without backpressure.
7777

7878

7979
##### Flow Control
8080

81-
Flow control is any mitigation strategies that a consumer applies to reduce the flow of data.
81+
Flow control is any mitigation strategy that a consumer applies to reduce the flow of data.
8282

8383
Examples:
8484

85-
- Controlling the production of data, such as with `Iterator.next` or `Subscription.request(n)`
85+
- Controlling the production of data, such as with `Iterator.next` or `Subscription.request(n)`.
8686
- Preventing the delivery of data, such as buffer, drop, sample/throttle, and debounce.
8787

8888

@@ -112,14 +112,14 @@ Stream that supports async and synchronous push. It does *not* support interacti
112112

113113
Usable for:
114114

115-
- sync or async
116-
- push
117-
- 0, 1, many or infinite items
115+
- Sync or async.
116+
- Push.
117+
- 0, 1, many or infinite items.
118118

119119
Flow control support:
120120

121-
- buffering, sampling, throttling, windowing, dropping, etc
122-
- temporal and count-based strategies
121+
- Buffering, sampling, throttling, windowing, dropping, etc.
122+
- Temporal and count-based strategies.
123123

124124
*Type Signature*
125125

@@ -147,23 +147,23 @@ Stream that supports async and synchronous push and pull. It supports interactiv
147147

148148
Usable for:
149149

150-
- pull sources
151-
- push Observables with backpressure strategy (ie. `Observable.toFlowable(onBackpressureStrategy)`)
152-
- sync or async
153-
- 0, 1, many or infinite items
150+
- Pull sources.
151+
- Push Observables with backpressure strategy (i.e. `Observable.toFlowable(onBackpressureStrategy)`).
152+
- Sync or async.
153+
- 0, 1, many or infinite items.
154154

155155
Flow control support:
156156

157-
- buffering, sampling, throttling, windowing, dropping, etc
158-
- temporal and count-based strategies
159-
- `request(n)` consumer demand signal
160-
- for pull-based sources, this allows batched "async pull"
161-
- for push-based sources, this allows backpressure signals to conditionally apply strategies (i.e. drop, first, buffer, sample, fail, etc)
157+
- Buffering, sampling, throttling, windowing, dropping, etc.
158+
- Temporal and count-based strategies.
159+
- `request(n)` consumer demand signal:
160+
- For pull-based sources, this allows batched "async pull".
161+
- For push-based sources, this allows backpressure signals to conditionally apply strategies (i.e. drop, first, buffer, sample, fail, etc.).
162162

163-
You get a flowable from:
163+
You get a `Flowable` from:
164164

165-
- Converting a Observable with a backpressure strategy
166-
- Create from sync/async OnSubscribe API (which participate in backpressure semantics)
165+
- Converting a Observable with a backpressure strategy.
166+
- Create from sync/async `onSubscribe` API (which participate in backpressure semantics).
167167

168168
*Type Signature*
169169

@@ -191,14 +191,14 @@ Lazy representation of a single response (lazy equivalent of `Future`/`Promise`)
191191

192192
Usable for:
193193

194-
- pull sources
195-
- push sources being windowed or flow controlled (such as `window(1)` or `take(1)`)
196-
- sync or async
197-
- 1 item
194+
- Pull sources.
195+
- Push sources being windowed or flow controlled (such as `window(1)` or `take(1)`).
196+
- Sync or async.
197+
- 1 item.
198198

199199
Flow control:
200200

201-
- Not applicable (don't subscribe if the single response is not wanted)
201+
- Not applicable (don't subscribe if the single response is not wanted).
202202

203203
*Type Signature*
204204

@@ -219,15 +219,15 @@ interface SingleSubscriber<T> {
219219

220220
##### Completable
221221

222-
Lazy representation of a unit of work that can complete or fail
222+
Lazy representation of a unit of work that can complete or fail.
223223

224224
- Semantic equivalent of `Observable.empty().doOnSubscribe()`.
225225
- Alternative for scenarios often represented with types such as `Single<Void>` or `Observable<Void>`.
226226

227227
Usable for:
228228

229-
- sync or async
230-
- 0 items
229+
- Sync or async.
230+
- 0 items.
231231

232232
*Type Signature*
233233

@@ -325,9 +325,9 @@ In the addition of the previous rules, an operator for `Flowable`:
325325

326326
### Creation
327327

328-
Unlike RxJava 1.x, 2.x base classes are to be abstract, stateless and generally no longer wrap an `OnSubscribe` callback - this saves allocation in assembly time without limiting the expressiveness. Operator methods and standard factories still live as final on the base classes.
328+
Unlike RxJava 1.x, 2.x base classes are to be abstract, stateless and generally no longer wrap an `onSubscribe` callback - this saves allocation in assembly time without limiting the expressiveness. Operator methods and standard factories still live as final on the base classes.
329329

330-
Instead of the indirection of an `OnSubscribe` and `lift`, operators are to be implemented by extending the base classes. For example, the `map`
330+
Instead of the indirection of an `onSubscribe` and `lift`, operators are to be implemented by extending the base classes. For example, the `map`
331331
operator will look like this:
332332

333333
```java
@@ -353,36 +353,36 @@ public final class FlowableMap<T, R> extends Flowable<R> {
353353
}
354354
```
355355

356-
Since Java still doesn't have extension methods, "adding" more operators can only happen through helper methods such as `lift(C -> C)` and `compose(R -> P)` where `C` is the default consumer type (i.e., `rs.Subscriber`), `R` is the base type (i.e., `Flowable`) and `P` is the base interface (i.e., `rs.Publisher`). As before, the library itself may gain or lose standard operators and/or overloads through the same community process.
356+
Since Java still doesn't have extension methods, "adding" more operators can only happen through helper methods such as `lift(C -> C)` and `compose(R -> P)` where `C` is the default consumer type (i.e. `rs.Subscriber`), `R` is the base type (i.e. `Flowable`) and `P` is the base interface (i.e. `rs.Publisher`). As before, the library itself may gain or lose standard operators and/or overloads through the same community process.
357357

358-
In concert, `create(OnSubscribe)` will not be available; standard operators extend the base types directly. The conversion of other RS-based libraries will happen through the `Flowable.wrap(Publisher<T>)` static method.
358+
In concert, `create(onSubscribe)` will not be available; standard operators extend the base types directly. The conversion of other RS-based libraries will happen through the `Flowable.wrap(Publisher<T>)` static method.
359359

360360
(*The unfortunate effect of `create` in 1.x was the ignorance of the Observable contract and beginner's first choice as an entry point. We can't eliminate this path since `rs.Publisher` is a single method functional interface that can be implemented just as badly.*)
361361

362362
Therefore, new standard factory methods will try to address the common entry point requirements.
363363

364364
The `Flowable` will contain the following `create` methods:
365365

366-
- `create(SyncGenerator<T, S>)`: safe, synchronous generation of signals, one-by-one
367-
- `create(AsyncOnSubscribe<T, S>)`: batch-create signals based on request patterns
368-
- `create(Consumer<? super FlowEmitter<T>>)`: relay multiple values or error from multi-valued reactive-sources (i.e., button-clicks) while also give flow control options right there (buffer, drop, error, etc.).
369-
- `createSingle(Consumer<? super SingleEmitter<T>>)`: relay a single value or error from other reactive sources (i.e., addListener callbacks)
370-
- `createEmpty(Consumer<? super CompletionEmitter>)`: signal a completion or error from valueless reactive sources
366+
- `create(SyncGenerator<T, S>)`: safe, synchronous generation of signals, one-by-one.
367+
- `create(AsyncOnSubscribe<T, S>)`: batch-create signals based on request patterns.
368+
- `create(Consumer<? super FlowEmitter<T>>)`: relay multiple values or error from multi-valued reactive-sources (i.e. button-clicks) while also give flow control options right there (buffer, drop, error, etc.).
369+
- `createSingle(Consumer<? super SingleEmitter<T>>)`: relay a single value or error from other reactive sources (i.e. addListener callbacks).
370+
- `createEmpty(Consumer<? super CompletionEmitter>)`: signal a completion or error from valueless reactive sources.
371371

372372
The `Observable` will contain the following `create` methods:
373373

374-
- `create(SyncGenerator<T, S>)`: safe, synchronous generation of signals, one-by-one
375-
- `create(Consumer<? super FlowEmitter<T>>)`: relay multiple values or error from multi-valued reactive-sources (i.e., button-clicks) while also give flow control options right there (buffer, drop, error, etc.).
376-
- `createSingle(Consumer<? super SingleEmitter<T>>)`: relay a single value or error from other reactive sources (i.e., addListener callbacks)
377-
- `createEmpty(Consumer<? super CompletionEmitter>)`: signal a completion or error from valueless reactive sources
374+
- `create(SyncGenerator<T, S>)`: safe, synchronous generation of signals, one-by-one.
375+
- `create(Consumer<? super FlowEmitter<T>>)`: relay multiple values or error from multi-valued reactive-sources (i.e. button-clicks) while also give flow control options right there (buffer, drop, error, etc.).
376+
- `createSingle(Consumer<? super SingleEmitter<T>>)`: relay a single value or error from other reactive sources (i.e. addListener callbacks).
377+
- `createEmpty(Consumer<? super CompletionEmitter>)`: signal a completion or error from valueless reactive sources.
378378

379379
The `Single` will contain the following `create` method:
380380

381-
- `create(Consumer<? super SingleEmitter<T>>)`: relay a single value or error from other reactive sources (i.e., addListener callbacks)
381+
- `create(Consumer<? super SingleEmitter<T>>)`: relay a single value or error from other reactive sources (i.e. addListener callbacks).
382382

383383
The `Completable` will contain the following `create` method:
384384

385-
- `create(Consumer<? super CompletionEmitter>)`: signal a completion or error from valueless reactive sources
385+
- `create(Consumer<? super CompletionEmitter>)`: signal a completion or error from valueless reactive sources.
386386

387387

388388
The first two `create` methods take an implementation of an interface which provides state and the generator methods:
@@ -509,10 +509,10 @@ There are two main levels of operator fusion: *macro* and *micro*.
509509

510510
Macro fusion deals with the higher level view of the operators, their identity and their combination (mostly in the form of subsequence). This is partially an internal affair of the operators, triggered by the downstream operator and may work with several cases. Given an operator application pair `a().b()` where `a` could be a source or an intermediate operator itself, when the application of `b` happens in assembly time, the following can happen:
511511

512-
- `b` identifies `a` and decides to not apply itself. Example: `empty().flatMap()` is functionally a no-op
512+
- `b` identifies `a` and decides to not apply itself. Example: `empty().flatMap()` is functionally a no-op.
513513
- `b` identifies `a` and decides to apply a different, conventional operator. Example: `just().subscribeOn()` is turned into `just().observeOn()`.
514514
- `b` decides to apply a new custom operator, combining and inlining existing behavior. Example: `just().subscribeOn()` internally goes to `ScalarScheduledPublisher`.
515-
- `a` is `b` and the two operator's parameter set can be combined into a single application. Example: `filter(p1).filter(p2)` combined into `filter(p1 && p2)`
515+
- `a` is `b` and the two operator's parameter set can be combined into a single application. Example: `filter(p1).filter(p2)` combined into `filter(p1 && p2)`.
516516

517517
Participating in the macro-fusion externally is possible by implementing a marker interface when extending `Flowable`. Two kinds of interfaces are available:
518518

@@ -540,7 +540,7 @@ Currently, two main kinds of micro-fusion opportunities are available.
540540

541541
###### 1) Conditional Subscriber
542542

543-
This extends the RS `Subscriber`interface with an extra method: `boolean tryOnNext(T value)` and can help avoiding small request amounts in case an operator didn't forward but dropped the value. The canonical use is for the `filter()` operator where if the predicate returns false, the operator has to request 1 from upstream (since the downstream doesn't know there was a value dropped and thus not request itself). Operators wanting to participate in this fusion have to implement and subscribe with an extended Subscriber interface:
543+
This extends the RS `Subscriber`interface with an extra method: `boolean tryOnNext(T value)` and can help avoiding small request amounts in case an operator didn't forward but dropped the value. The canonical use is for the `filter()` operator where if the predicate returns false, the operator has to request 1 from upstream (since the downstream doesn't know there was a value dropped and thus not request itself). Operators wanting to participate in this fusion have to implement and subscribe with an extended `Subscriber` interface:
544544

545545
```java
546546
interface ConditionalSubscriber<T> {
@@ -562,9 +562,9 @@ protected void subscribeActual(Subscriber<? super T> s) {
562562

563563
###### 2) Queue-fusion
564564

565-
The second category is when two (or more) operators share the same underlying queue and each append activity at the exit point (i.e., poll()) of the queue. This can work in two modes: synchronous and asynchronous.
565+
The second category is when two (or more) operators share the same underlying queue and each append activity at the exit point (i.e. `poll()`) of the queue. This can work in two modes: synchronous and asynchronous.
566566

567-
In synchronous mode, the elements of the sequence is already available (i.e., a fixed `range()` or `fromArray()`, or can be synchronously calculated in a pull fashion in `fromIterable`. In this mode, the requesting and regular onError-path is bypassed and is forbidden. Sources have to return null from `pull()` and false from `isEmpty()` if they have no more values and throw from these methods if they want to indicate an exceptional case.
567+
In synchronous mode, the elements of the sequence is already available (i.e. a fixed `range()` or `fromArray()`, or can be synchronously calculated in a pull fashion in `fromIterable`. In this mode, the requesting and regular onError-path is bypassed and is forbidden. Sources have to return null from `pull()` and false from `isEmpty()` if they have no more values and throw from these methods if they want to indicate an exceptional case.
568568

569569
In asynchronous mode, elements may become available at any time, therefore, `pull` returning null, as with regular queue-drain, is just the indication of temporary lack of source values. Completion and error still has to go through `onComplete` and `onError` as usual, requesting still happens as usual but when a value is available in the shared queue, it is indicated by an `onNext(null)` call. This can trigger a chain of `drain` calls without moving values in or out of different queues.
570570

@@ -588,10 +588,10 @@ For performance, the mode is an integer bitflags setup, called early during subs
588588

589589
Since RxJava 2.x is still JDK 6 compatible, the `QueueSubscription` can't itself default unnecessary methods and implementations are required to throw `UnsupportedOperationException` for `Queue` methods other than the following:
590590

591-
- `poll()`
592-
- `isEmpty()`
593-
- `clear()`
594-
- `size()`
591+
- `poll()`.
592+
- `isEmpty()`.
593+
- `clear()`.
594+
- `size()`.
595595

596596
Even though other modern libraries also define this interface, they live in local packages and thus non-reusable without dragging in the whole library. Therefore, until externalized and standardized, cross-library micro-fusion won't happen.
597597

0 commit comments

Comments
 (0)