Understanding Functional, Reactive and Functional Reactive Programming paradigms…
In this era of community driven development with massive technology crossovers, it’s both overwhelming and impractical for a developer to keep track of all the jargons and the different programming concepts and paradigms. More than ever, today, we are fundamentally challenging our traditional approach to programming, with unconventional ways of solving the problem statements. Gone are the days when an enterprise or a committee would rule the game and dictate how we solve our problems using some predefined notions. It’s all about creativity, community and open source that drive today’s breed of modern programmers.
If we go by the books, it can be defined as,
“A programming paradigm in which we treat all our computations as pure mathematical functions that are side-effects free, without any mutations.”
There are a few key highlighted words that constitute this definition, and understanding those is the essence of functional programming.
- pure functions
- side-effects free
- without mutations
Let's first try to understand what is a side-effect and a mutation in context of a function. Suppose we have a function such that,
add(a, b) -> sum.
At this point you might be thinking, who would do such a someMemoryDeallocationFunction for something as trivial as an add function. That’s not the point, in real life code examples it’s tempting and in many cases need-of-the-hour to do such imperative operations that has no real co-relation with the actual function but are essential to the problem in hand. Nevertheless, we get an idea about what precisely are side-effects inside of a function definition.
Now lets see what are mutations. We’d be extending our example such that the parameters are references to real values,
add(*a, *b, *sum) -> sum.
From the above example we see that mutation simply refers to the idea of modifying the original values or some other global states in your code while performing the computation. Though the above example is trivial, it’s not far from the real world scenarios. Imagine a function that takes an array and returns the sorted array by mutating the originally supplied array.
“Functions that do not contain any side-effects and mutations inside their implementation, are Pure Functions.”
Any function that has side-effects and/or mutations inside of it, is an impure function. Then what is a pure function? Well, yes, you guessed that right, functions that do not contain any side-effects and mutations inside their implementation, are Pure Functions. Given an input x, they produce an output y in all cases
f(x) -> y, no matter in what state the other parts of application are. They do not rely on any global state and their output is solely dependent on their arguments.
The idea of Pure Functions seems simple, right? Then why is this a big deal and what’s the fundamental problem in implementing these inside of the traditional object oriented languages. Well I’d come to the “big deal” part in a bit, but the fact that functions are never treated as first-class citizens in the OO languages and are mere properties of the object, makes the idea of pure functions a lot inconvenient and impractical to use in the OO world. In most real cases, unless an object exists, a function cannot exist on its own, and there-in lies the tight coupling of the object state and function. It’s fundamentally not allowed to pass around functions as arguments to other functions to enable data composition out of various smaller pure functions (which forms the basic building block of functional programming). Now let's see why Functional Programming being such a simple concept, still is such a big deal and gaining so much popularity over the years.
“Functional Programming enables code predictability, composition and testability at its peak.”
Functional Programming enables some of the greatest perks to software development, right out-of-the-box. The highlights being, code predictability, composition and hight scale testability. There are no mutations or side-effects in your code, which makes it easier to reason about your code, and figure out and isolate bugs to their true sources. Further more, if you are like me, a big fan of function composition, its included with building blocks like map, reduce, filter etc. without much added noise. And last but not the least, if you prefer TDD, or believe in writing highly testable code, you can test every nook and corner of your code with 100% guarantee and utmost satisfaction.
The word reactive is enough to sum up this programming paradigm in which, the code reacts and updates its state to any data changes.
“An asynchronous programming paradigm where we process data streams to propagate changes in our code.”
I would not go deep into explaining the different aspects of a reactive programming, however we’d try to understand the key highlights with a minimalistic example.
- data streams
- propagate changes
Unlike an imperative code where
a = b + c; would result in the evaluation of the whole statement at the instance and storing the result in the variable, in a reactive world this whole process is asynchronous. Unless the data streams (in this example variable b and c) that define the values on the right hand side are not available, the expression’s final result is not evaluated. Once we have the data, the expression is evaluated and the result is made available. One interesting thing to note here is the fact that all this is live, any further change to the data stream, would mean a re-evaluation and automatic update of the result aka propagate changes in the different parts of the code.
Though there are many libraries, frameworks and architecture patterns that enable reactive programming in real world programming languages, I haven’t heard of any language that has this paradigm at it’s core, except for Verilog, which is a hardware description language and not meant for any other pure soft usages.
With the basic understanding of Functional Programming and Reactive Programming it sums up the whole of this programming paradigm.
“A reactive programming paradigm using the building blocks of functional programming.”
Functional Reactive Programming aka FRP exists in various forms. We’d not be discussing these variations as it’s not worth of a time trying to dig into these technicalities that are mostly meaningless to the real world programming problems. And furthermore this paradigm is mostly implemented as extensions provided by different libraries to support this behaviour across various different languages, and I’m yet to come across a language that has FRP at its core. ReactiveX provides one such cross language implementation of the reactive extensions to enable FRP inside a variety of different languages.
This article may not be exhaustive and if I have missed something that you think should have been included, please leave a feedback and I’d include those as edits to the article. The idea is to provide just enough understanding to clear any myths or preliminary doubts plaguing our minds while using these paradigms in our oblivion.