Functional Reactive Programming

Ankit Trehan
10 min readMar 4, 2022

To explain what functional reactive programming is, let’s look at reactive programming first. Reactive programming is the idea of “reacting” to a change or a message from a data stream in an asynchronous manner. A data stream can mean anything here, mouse clicks to updates in a database to GPS location updates etc. A very basic example to clarify this would be to imagine having a key to start your car engine. There are two ways to update your engine’s state when the key is turned. The first would be how we traditionally think of dealing with such updates, have a function within the Engine class that can be invoked from the IgnitionLock to update its state to start/stop. This would lead to higher coupling, since the logic of updating the engine’s state now falls in the IgnitionLock class. The other way would be to have the Engine class subscribe to changes on the IgnitionLock and react to those events. This would lead to a more decoupled code by giving the control back to the engine class to perform any changes it needs to for itself whenever a change in the IgnitionLock is pushed on the subscription data stream.

One common example of Reactive programming is given through spreadsheets. Say you have 3 cells a, b and c which hold values dependent upon a and you have a function calculating the values for b and c. When you update the value in a, the value in b and c are automatically updated. This sort of captures the idea of reactive programming where an event, in this case value change, is being propagated down into a stream, the other cells are reacting to this change and updating their own value. Reactive programming’s Wikepedia page also has a similar example to the one above. A more formal definition of Reactive programming from the same page is:

Reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change

How does reactive programming differ from the Observer pattern?

Observer pattern is very similar to Reactive programming where observers are notified of a change when it happens in the subject. But the major differences between the two are pointed out by Venkat Subramaniam in this talk. The main distinctions between the two lie in the channels that are propagated by the subject (in reactive terms the observable) vs the invocation of a method from the subject in the Observer pattern to notify an observer. In Reactive programming, there are three different types of channels, one to signal the end of propagation, one to send all the changes and one to propagate error. Unlike the Observer pattern where the observer never really knows when the data being sent out from the other side has stopped, reactive streams have a special channel that lets the observers know that data propagation has completed and you can begin clean up activities now. Some other major differences between the two are explained in this StackOverflow question.

The core properties of a Reactive systems are defined in the Reactive manifesto. It states how the increase in the number of devices and the increase in data to be processed has lead to a need for a new type of architecture that is more flexible, loosely coupled and scalable. The four main properties of Reactive systems are Responsive: applications should respond as quick as possible (clients being notified of something loading), Resilient: applications should be resilient to critical failures and should still remain responsive during failures, Elastic: applications should scale for usage when and if needed and Message Driven.

To sum up everything that was just said, Reactive programming is a solution to the ever increasing demand of concurrent users and increasing data. It provides an asynchronous event driven solution where the observers can subscribe to changes being published on the event stream.

So where does the need for asynchronous behavior come from?

Modern applications can use a lot of concurrent users and require a lot of data processing at the same time. There are two main ways to deal with this increased data that a lot of the times cannot be solved by upgrading the hardware. So an easy way to get around this is to write asynchronous code which does not need to wait for each request/action to finish and can come back to the current process when the asynchronous processing has finished.

Reference

Okay so now that we have an idea of what reactive programming is, the second part to define is what is functional programming. Functional programming is when we deal with pure functions. Think of these like your math functions where there is an input and there is a result, no other values get updated or changed. So in functional programming there are no side effects. This means that none of the states in the application should be updated when a function is executed and a function should never return void since returning that would mean the function does nothing. Similar to mathematical functions, these functions should return the same values for the same inputs. Finally, the inputs to these functions should be immutable, so that there is a guarantee that another process running does not update the values of the inputs while a function is trying to process them. A very basic example of impure function vs pure function is as follows, notice how the first function has a side effect of updating the state of the total object whereas the second one takes in two values, processes them and returns them with no other side effects:

// Impure
public int total = 0
public void imp(int a, int b) {
this.total = a + b;
}
// Pure
public int pure(int a, int b) {
return a+b;
}

Finally we come to functional reactive programming. But before we get into FRP let’s dive into some of the term and concepts that are good to know in order to be more familiar with it.

  • Backpressure: backpressure is in broader context exactly what it seems like, opposing the pressure coming from one end or the pipe/stream. It means the ability for the consumer to signal the producer that the rate of emission is too high; Reactive streams allow the consumer to signal how much it can process at a time.

Reactive systems rely on asynchronous message-passing to establish a boundary between components … [enabling] load management, elasticity, and flow control by shaping and monitoring the message queues in the system and applying back-pressure when necessary… Non-blocking communication allows recipients to only consume resources while active, leading to less system overhead.

  • Obervable: An observable can be thought of as the producer of events in Reactive Programming where it is the entity that is producing a stream of events for the observer to see. Each observable can have multiple observers and they are inherently lazy (they emit functions only when a signal is passed) and don’t produce data until an observer has subscribed to it.
  • Non-blocking: non-blocking methods are the ones that execute asynchronously. Blocking happens when your code needs to wait for execution to finish for something like an external call. Reactive systems are inherently non blocking because of the async architecture that they use.

A definition by Rossen Stoyanchev from Project Reactor Team using these terms is “In a nutshell reactive programming is about non-blocking, event-driven applications that scale with a small number of threads with backpressure as a key ingredient that aims to ensure producers do not overwhelm consumers”

Okay so finally onto Functional Reactive Programming. In a sentence, FRP is the combination of the concepts that have been described earlier here. It is the practice of using functional programming to manipulate event streams as they are fed with new data. Here is a definition for FRP:

Functional Reactive Programming is a programming paradigm for reactive programming (asynchronous dataflow programming) using the building blocks of functional programming (e.g. map, reduce, filter)

An example of this might be that you might want to filter the data in an array that is put on a stream by an observer with the help of a function or map an array’s elements to be the square of itself. The following code shows how you can use .filter and .map functions with an observable. Any data emitted out of this observable can be subscribed to by an observer.

Flux
.fromIterable(List.of(2, 3, 4, 5, 6, 7, 8)) // create a reactive stream
.filter(num -> num > 4)
.map(num -> num*num)

The above code uses Project Reactor’s Flux class, where a Flux is nothing but a reactive stream publisher that can produce anywhere between 1 to n items and then signal the onComplete channel. The following image helps visualize how a flux functions:

As you can see, the above code is based on reactive streams but still leverages functional programming code that had been shown above. FRP is the combination of both reactive streams and using the power of functional programming to create a standard method of communication while simultaneously processing it. This type of functional programming coupled with streams might not be intuitive since most of the time we are dealing with imperative and proactive style of coding. The functional aspect of FRP helps keep the code more concise and clear.

So what are the benefits of FRP?

Advantages:

A lot of the advantages of FRP were in the core concepts of reactive systems that were discussed above. These were: Resiliency, Responsiveness, and Elasticity. Other than these, a few other advantages would be:

  • Functional Reactive Programming has a standard mechanism for error propagation. It has a specific channel that an observer can listen to for errors being propagated from the other side.
  • It can make handling UI updates very easy. Button clicks or key presses can easily be “reacted to” and updates can be made to the UI easily.
  • FRP can manage to have lower number of threads since you don’t need a different thread for each time the application needs to wait for the data
  • Functional programming helps to create more readable and concise code as compared to the traditional imperative style of proactive coding.

Disadvantages:

  • Memory Expensive: Creating streams of data and processing them with functions is more memory expensive than a traditional application.
  • Learning Curve: There is a steep learning curve for developers, not only to understand the underlying architecture and behavior of the paradigm but also to shift their thinking towards more functional programming.

Use cases and other info:

An interesting use case of Reactive programming coupled with Apache Kafka was Heroku’s use of it in their data processing pipeline showing how FRP coupled with Kafka can be very powerful by providing processing of data as it comes into the pipeline. Here is one interesting blog from IBM about how to use Kafka in Reactive systems. It details how Kafka can be used as a backbone for a Reactive system:

Apache Kafka is a great tool that is commonly used for this purpose: to enable the asynchronous messaging that makes up the backbone of a reactive system.

If you would like to read further about the theory behind FRP, there are two papers released from Conal Elliot detailing the subject here and here.

For learning FRP in javascript with bacon.js, I would suggest reading this article.

P.S: I am always looking for feedback to improve and learn. Please leave comments if something can be improved upon/if something isn’t accurate.

Also this topic came out of requirements from a job description that caught my interest and I decided to research on it.

References/Further Reading:

https://developer.ibm.com/articles/reactive-systems-getting-started/

--

--