Reactive Extensions for .NET. The quick and dirty on FRP and how it differs from normal programming in most common languages is in the way you think about variable assignment and the meaning of the = operator.
In most languages, such as Java, C#, Ruby and Objective-C, when you use the = operator, it does not actually carry over its meaning from mathematics. It denotes assignment rather than actual equality. So for a simple example in a c like language:
int y = 4; // The value of y is now 4. int x = y; // The value of x is also 4 y = 3; // The value of y is now 3, but the value of x is still 4.
// The value of y is now 4.
// The value of x is also 4
// The value of y is now 3, but the value of x is still 4.
This is expected behavior, and indeed how much programming is done in modern languages. Now let’s take the same example and look at the behavior using FRP:
int y = 4; // The value of y is now 4. int x = y; // The value of x is also 4. y = 3; // The value of y is now 3, and the value of x is also 3. y = 2; // The value of y is now 2, and the value of x is also 2.
inty=4;// The value of y is now 4.
intx=y;// The value of x is also 4.
y=3;// The value of y is now 3, and the value of x is also 3.
y=2;// The value of y is now 2, and the value of x is also 2.
In FRP, the = operator does not simply denote a single assignment. It denotes assignment over time. That is, when we say that x = y, what we are saying is that the value of x is equal to the value of y, even when the value of y changes over time. This is one of the key components to understanding FRP and ReactiveCocoa. In the above example, we would say that x is bound to the value of y, and no matter how many times the value of y changes, x would always reflect that value.
So what is the use of this seemingly simple change, and why would you want your program to behave in such a way? Take for example the humble spreadsheet. You put in your formula for a cell, and the result of the calculation of the cells is always up-to-date. You don’t have to manually tell the spreadsheet to recalculate your values every time you make a change. It simply reacts to your input and updates in real time. Imagine how unusable and frustrating it would be to use a spreadsheet if it did not behave in this way. Now, apply that to the apps you build and you can start to see the advantage of FRP.
How is this actually modeled in a real language? ReactiveCocoa uses signals and subscribers. A signal is like a pipe for data. Any data that flows through an application can be modeled in terms of signals, and a signal is just a wrapper around some data that can be used to transform and direct the flow of that data.
A subscriber, on the other hand, can be thought of as the endpoint for a signal. A signal will transform and compose data, and a subscriber will observe a signal and react to changes the signal sends. You can think of a signal as a pipe, or series of pipes, and a subscriber as the final destination of whatever is flowing through the pipes.
What does this actually look like in ReactiveCocoa? Let’s take a very simple example of a signal that simply returns a value and a subscriber that receives that value.
In this very simple example, we create a signal that simply returns the value “pikachu”, and we subscribe to the result of that signal using the RAC macro. title is an NSString property on the current view controller, and what we are saying is that we want the value of title to be assigned to the value that is sent by the signal created by +[RACSignal return:@"pikachu"];.
So now what? There is not much you can do with this example. The signal sends one value, “pikachu” and then completes. The title property is now equal to “pikachu”, but that is all it will be equal to. Let’s look at a more useful example.
In this example, we have an input field where a user can register for some service with a username and email address. We have two text fields for input: one that accepts a username and one that accepts an email address. We use the handy rac_textSignal property on UITextField, which creates a signal from the text field that always reflects the current value of the text field.
We subscribe the username property to the values sent from the usernameTextField. So now every time the user types something into that text field, the value of the username property will be updated to reflect that.
For the email field, we want to make sure the user puts in a valid email address before the email property gets a value so we use the filter method. This method takes a block with a boolean predicate and then returns a new Signal that only sends values that pass the predicate in the given block. In this example, the email field will not receive a value from the signal unless that value is a valid email address.
In this small example, we have two signals and two subscribers. The username subscriber will always reflect the value of the usernameTextField, and the email subscriber will only reflect the value of the emailTextField when the email address is valid. Although this is a simple example, the concepts can be taken and applied universally throughout your apps.
These examples should whet your appetite for FRP and the power and expressiveness of ReactiveCocoa. All of the data you deal with can be modeled in terms of signals and subscribers. Having a unified interface for dealing with your data along with the assignment semantics provided by ReactiveCocoa can positively impact both the way you write code and the way your users experience your apps.