How does ReactiveSwift relate to RxSwift?
RxSwift is a Swift implementation of the ReactiveX (Rx) APIs. While ReactiveCocoa was inspired and heavily influenced by Rx, ReactiveSwift is an opinionated implementation of functional reactive programming, and intentionally not a direct port like RxSwift.
ReactiveSwift differs from RxSwift/ReactiveX where doing so:
- Results in a simpler API
- Addresses common sources of confusion
- Matches closely to Swift, and sometimes Cocoa, conventions
The following are a few important differences, along with their rationales.
Signals and SignalProducers (“hot” and “cold” observables)
One of the most confusing aspects of Rx is that of “hot”, “cold”, and “warm” observables (event streams).
In short, given just a method or function declaration like this, in C#:
IObservable<string> Search(string query)
… it is impossible to tell whether subscribing to (observing) that
IObservable will involve side effects. If it does involve side effects, it’s
also impossible to tell whether each subscription has a side effect, or if only
the first one does.
This example is contrived, but it demonstrates a real, pervasive problem that makes it extremely hard to understand Rx code (and pre-3.0 ReactiveCocoa code) at a glance.
ReactiveSwift addresses this by distinguishing side effects with the separate
SignalProducer types. Although this
means there’s another type to learn about, it improves code clarity and helps
communicate intent much better.
In other words, ReactiveSwift’s changes here are simple, not easy.
When Signals and SignalProducers are allowed to fail in ReactiveSwift,
the kind of error must be specified in the type system. For example,
Signal<Int, AnyError> is a signal of integer values that may fail with an error
More importantly, RAC allows the special type
NoError to be used instead,
which statically guarantees that an event stream is not allowed to send a
failure. This eliminates many bugs caused by unexpected failure events.
In Rx systems with types, event streams only specify the type of their values—not the type of their errors—so this sort of guarantee is impossible.
In most versions of Rx, Streams over time are known as
Enumerable type in .NET. Additionally, most operations in Rx.NET
borrow names from LINQ,
which uses terms reminiscent of relational databases, like
ReactiveSwift, on the other hand, focuses on being a native Swift citizen first and foremost, following the Swift API Guidelines as appropriate. Other naming differences are typically inspired by significantly better alternatives from Haskell or Elm (which is the primary source for the “signal” terminology).
Rx is basically agnostic as to how it’s used. Although UI programming with Rx is very common, it has few features tailored to that particular case.
Unlike ReactiveUI, which unfortunately cannot directly change Rx to make it more friendly for UI programming, ReactiveSwift has been improved many times specifically for this purpose—even when it means diverging further from Rx.