Skip to content

Commit 130c014

Browse files
committed
Documentation
1 parent 2580ba9 commit 130c014

File tree

33 files changed

+1604
-622
lines changed

33 files changed

+1604
-622
lines changed

Documentation/API.md

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
API
2+
===
3+
14
## RxSwift supported operators
25

36
In some cases there are multiple aliases for the same operator, because on different platforms / implementations, the same operation is sometimes called differently. Sometimes this is because historical reasons, sometimes because of reserved language keywords.
@@ -73,7 +76,7 @@ Operators are stateless by default.
7376
* [`replay`](http://reactivex.io/documentation/operators/replay.html)
7477
* variable / sharedWithCachedLastResult
7578

76-
Creating new operators is also pretty straightforward.
79+
Creating new operators is also pretty straightforward.
7780

7881
## RxCocoa extensions
7982

@@ -139,7 +142,7 @@ extension NSNotificationCenter {
139142

140143
```swift
141144
class DelegateProxy {
142-
145+
143146
public func observe(selector: Selector) -> Observable<[AnyObject]> {}
144147

145148
}
@@ -215,11 +218,11 @@ extension UITextField {
215218

216219
```swift
217220
extension UITextView {
218-
221+
219222
override func rx_createDelegateProxy() -> RxScrollViewDelegateProxy { }
220-
223+
221224
public var rx_text: Observable<String> { }
222-
225+
223226
}
224227
```
225228

@@ -256,7 +259,7 @@ extension UIImageView {
256259

257260
public func rx_subscribeImageTo
258261
(animated: Bool)
259-
(source: Observable<UIImage?>)
262+
(source: Observable<UIImage?>)
260263
-> Disposable {}
261264

262265
}
@@ -268,7 +271,7 @@ extension UIScrollView {
268271
public var rx_delegate: DelegateProxy {}
269272

270273
public func rx_setDelegate(delegate: UIScrollViewDelegate) {}
271-
274+
272275
public var rx_contentOffset: Observable<CGPoint> {}
273276

274277
}
@@ -292,7 +295,7 @@ extension UISlider {
292295

293296
```swift
294297
extension UITableView {
295-
298+
296299
public var rx_dataSource: DelegateProxy {}
297300

298301
public func rx_setDataSource(dataSource: UITableViewDataSource) -> Disposable {}
@@ -322,11 +325,11 @@ extension UITableView {
322325

323326
```swift
324327
extension UICollectionView {
325-
328+
326329
public var rx_dataSource: DelegateProxy {}
327330

328331
public func rx_setDataSource(dataSource: UICollectionViewDataSource) -> Disposable {}
329-
332+
330333
public func rx_subscribeWithReactiveDataSource<DataSource: protocol<RxCollectionViewDataSourceType, UICollectionViewDataSource>>(dataSource: DataSource)
331334
-> Observable<DataSource.Element> -> Disposable {}
332335

@@ -374,7 +377,7 @@ extension UIAlertView {
374377
public var rx_clickedButtonAtIndex: Observable<Int> {}
375378

376379
public var rx_willDismissWithButtonIndex: Observable<Int> {}
377-
380+
378381
public var rx_didDismissWithButtonIndex: Observable<Int> {}
379382

380383
}
@@ -427,7 +430,7 @@ extension NSButton {
427430
extension NSImageView {
428431

429432
public func rx_subscribeImageTo(source: Observable<NSImage?>) -> Disposable {}
430-
433+
431434
public func rx_subscribeImageTo
432435
(animated: Bool)
433436
(source: Observable<NSImage?>) -> Disposable {}
@@ -438,10 +441,9 @@ extension NSImageView {
438441
extension NSTextField {
439442

440443
public var rx_delegate: DelegateProxy {}
441-
444+
442445
public var rx_text: Observable<String> {}
443446

444447
public func rx_subscribeTextTo(source: Observable<String>) -> Disposable {}
445-
}
448+
}
446449
```
447-

Documentation/DesignRationale.md

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
Design Rationale
2+
================
3+
4+
## Why error type isn't generic
5+
6+
```Swift
7+
enum Event<Element> {
8+
case Next(Element) // next element of a sequence
9+
case Error(ErrorType) // sequence failed with error
10+
case Completed // sequence terminated successfully
11+
}
12+
```
13+
14+
Let's discuss pros and cons of `ErrorType` being generic.
15+
16+
If you have generic error type you create additional impedance mismatch between two observables.
17+
18+
Let's say you have:
19+
20+
`Observable<String, E1>` and `Observable<String, E2>`
21+
22+
There isn't much you can do with them without figuring out what will be the resulting error type.
23+
24+
Will it be `E1`, `E2` or some new `E3` maybe? So you need a new set of operators just to solve that impedance mismatch.
25+
26+
This for sure hurts composition properties, and Rx really doesn't care about why sequence fails, it just forwards failure further.
27+
28+
There is additional problem that maybe in some cases operators will fail for some internal error, and in that case you won't be able to construct resulting error and report failure.
29+
30+
But ok, let's ignore that and assume we can use that to model sequences that don't error out. It looks like it could be useful for that purpose?
31+
32+
Well yes, it potentially could be, but lets consider why would you want to use sequences that don't error out.
33+
34+
One obvious application would be for permanent streams in UI layer that drive entire UI. But when you consider that case, it's not really only sufficient to use compiler to prove that sequences don't error out, you also need to prove other properties. Like that elements are observed on `MainScheduler`.
35+
36+
What you really need is a generic way to prove traits for sequences (`Observables`). And you could be interested in a lot of properties. For example:
37+
38+
* sequence terminates in finite time (server side)
39+
* sequence contains only one element (if you are running some computation)
40+
* sequence doesn't error out, never terminates and elements are delivered on main scheduler (UI)
41+
* sequence doesn't error out, never terminates and elements are delivered on main scheduler, and have refcounted sharing (UI)
42+
* sequence doesn't error out, never terminates and elements are delivered on specific background scheduler (audio engine)
43+
44+
What you really want is a general compiler enforced system of traits for observable sequences, and a set of invariant operators for those wanted properties.
45+
46+
A good analogy IMHO would be
47+
48+
```
49+
1, 3.14, e, 2.79, 1 + 1i <-> Observable<E>
50+
1m/s, 1T, 5kg, 1.3 pounds <-> Errorless observable, UI observable, Finite observable ...
51+
```
52+
53+
There are many ways how to do that in Swift by either using composition or inheritance of observables.
54+
55+
Additional benefit of using unit system is that you can prove that UI code is executing on same scheduler and thus use lockless operators for all transformations.
56+
57+
Since Rx already doesn't have locks for single sequence operations, and all of the remaining locks are in statefull components (aka UI), that would practically remove all of the remaining locks out of Rx code and create compiler enforced lockless Rx code.
58+
59+
So IMHO, there really is no benefit of using typed Errors that couldn't be achieved cleaner in other ways while preserving Rx compositional semantics. And other ways also have huge other benefits.
60+
61+
## Pipe operator
62+
63+
This is the definition of `>-` operator.
64+
65+
```swift
66+
func >- <In, Out>(lhs: In, rhs: In -> Out) -> Out {
67+
return rhs(lhs)
68+
}
69+
```
70+
71+
This enables us to write
72+
73+
```swift
74+
a >- map { $0 * 2 } >- filter { $0 > 0 }
75+
```
76+
77+
instead of
78+
79+
```swift
80+
a.map { $0 * 2 }.filter { $0 > 0 }
81+
```
82+
83+
This is another explanation:
84+
85+
```swift
86+
a >- b >- c is equivalent to c(b(a))
87+
```
88+
89+
So why was this introduced and not just use "." and extensions? Short answer is that Swift extensions weren't powerful enough, but there are other reasons as well.
90+
91+
Next version of RxSwift for Swift 2.0 will probably also include extensions that will enable the use of
92+
`.`.
93+
94+
">-" also enables us to chain results easily. For example, if using protocol extensions typical example would look like this.
95+
96+
```swift
97+
disposeBag.addDisposable(
98+
observable
99+
.map { n in
100+
n * 2
101+
}
102+
.subscribeNext { n in
103+
print(n)
104+
}
105+
)
106+
```
107+
108+
This code could be written more elegantly using `>-` operator.
109+
110+
```swift
111+
observable
112+
>- map { n in
113+
n * 2
114+
}
115+
>- subscribeNext { n in
116+
print(n)
117+
}
118+
>- disposeBag.addDisposable
119+
```
120+
121+
All of the Rx public interfaces don't depend at all on the `>-` operator.
122+
123+
It was actually introduced quite late and you can use Rx operators (map, filter ...) without it.
124+
125+
If you dislike `>-` operator and want to use `|>` or `~>` operators, just define them in your project in this form:
126+
127+
```swift
128+
infix operator |> { associativity left precedence 91 }
129+
130+
public func |> <In, Out>(source: In, @noescape transform: In -> Out) -> Out {
131+
return transform(source)
132+
}
133+
```
134+
135+
or
136+
137+
```
138+
infix operator ~> { associativity left precedence 91 }
139+
140+
public func ~> <In, Out>(source: In, @noescape transform: In -> Out) -> Out {
141+
return transform(source)
142+
}
143+
```
144+
145+
and you can use them instead of `>-` operator.
146+
147+
```swift
148+
let a /*: Observable<Int>*/ = Variable(1)
149+
let b /*: Observable<Int>*/ = Variable(2)
150+
151+
combineLatest(a, b) { $0 + $1 }
152+
|> filter { $0 >= 0 }
153+
|> map { "\($0) is positive" }
154+
|> subscribeNext { println($0) }
155+
```
156+
157+
```swift
158+
let a /*: Observable<Int>*/ = Variable(1)
159+
let b /*: Observable<Int>*/ = Variable(2)
160+
161+
combineLatest(a, b) { $0 + $1 }
162+
~> filter { $0 >= 0 }
163+
~> map { "\($0) is positive" }
164+
~> subscribeNext { println($0) }
165+
```
166+
167+
So why was `>-` chosen in the end? Well, it was a difficult decision.
168+
169+
Why wasn't standard function application operator used?
170+
171+
I've first tried to find a similar operator in swift core libraries, but couldn't find it. That meant that I'll need to define something myself or find some third party library that contains reference function application operator definition and use it.
172+
Otherwise all of the example code would be unreadable.
173+
174+
Why wasn't some standard library used for that operator?
175+
176+
Well, I'm not sure there is a clear consensus in the community about funtion application operators or libraries that define them.
177+
178+
Why wasn't function application operator defined only for `Observables` and `Disposables`?
179+
180+
One of the solutions could have been to provide a specialized operator that just works for `Observables` and `Disposables`.
181+
In that case, if an identically named general purpose function application operator is defined somewhere else, there would still be collision, priority or ambiguity problems.
182+
183+
Why wasn't some more standard operator like `|>` or `~>` used?
184+
185+
`|>` or `~>` are probably more commonly used operators in swift, so if there was another definition for them in Rx as general purpose function application operators, there is a high probability they would collide with definitions in other frameworks or project.
186+
187+
The simplest and safest solution IMHO was to create some new operator that made sense in this context and there is a low probability anyone else uses it.
188+
In case the operator naming choice was wrong, name is rare and community eventually reaches consensus on the matter, it's more easier to find and replace it in user projects.
189+
190+
I have experimented for a week with different operators and in the end these are the reasons why `>-` was chosen
191+
192+
* It's short, only two characters
193+
* It looks like a sink to the right, which is a function it actually performs, so it's intuitive.
194+
* It doesn't create a lot of visual noise. `|>` compared to `>-` IMHO looks a lot more intrusive. When my visual cortex parses `|>` it creates an illusion of a filled triangle, and when it parses `>-`, it sees three lines that don't cover any surface area, but are easily recognizable. Of course, that experience can be different for other people, but since I really wanted to create something that's pleasurable for me to use, that's a good argument. I'm just hoping that other people have the same experience.
195+
* In the worst case scenario, if this operator is awkward to somebody, they can easily replace it using instructions above.

0 commit comments

Comments
 (0)