A new beginning?
Functional Programming Concepts
Fasten your seat belts, the journey begins.
What does it mean to program in a functional way? Well, code written that way is based on, yes you guessed it, functions…these functions are tiny chunks of code that do something specific with the data that was passed to them. And in comparison with the object-oriented programming paradigm, these functions can be passed as arguments to other functions, which will receive them, execute them, perform some other computations and then either return some value or may this function is passed as an argument to another one. Ideally, these functions should complain about what is known as pure functions, which bring extra benefits to how the data flow through the execution of the code.
Now, what is a pure function? A pure function is a function that:
- provided a given argument, it always returns the same results.
- performs its computation without any kind of side effects.
Those two characteristics make a pure function powerful.
If a function returns always the same results given the same input, it means that it has no dependency on the “external world”, it is just a standalone function that does its job without any kind of footprint.
Following the same line of thought, these functions do not change anything on their “surroundings”. That means that there is no data mutation whatsoever. You can trust these guys.
With that comes the next concept, immutability. Immutability is key in the Functional Programming paradigm; data binding occurs of course, but once a value is bounded to, let’s say, a name, there is no way to modify it. That leads a functional code to be referentially transparent. In simple words, if we replace all the value identifiers by their values, the program behavior does not change. For example:
In an imperative language, we can write
amount = amount * 2def not_transparent(x)
amount = 10
x + amount
end
in the first line of code, the value of the amount variable is modified. Each time we execute that line, amount will contain always a different value (unless of course, the starting value is 0). Besides that, the not_transparent method modifies that amount variable as well, which in the case makes the whole scenario even worse. All that tells us, we are unable to replace amount by its value and expect that the behavior of the code to be the same. It is not transparent at all…in fact, assignment statements are never referentially transparent.
Now, if we take a look at
amount = 20def transparent(x)
x + 1
end
the transparent method does not change state, it does not even try to modify its input. We can say, without any kind of problem, that that code is referentially transparent and it does not have any side effects. Functional programs exclusively use this type of function and are therefore referentially transparent.
Let’s talk a little bit about the treatment of a variable depending on if your program in an imperative or functional way.
From an imperative or object-oriented point of view, a variable is a name associated with a given memory slot, which can be modified as we wish, that is, a programmer can directly access that memory location and write whatever he wants on it. With that in mind, we can say that the code workflow behaves upon how the value in that memory location changes.
Going back to the roots and mathematically speaking, a variable is a name associated with a value and that value changes as an effect of some mathematical operations performed on it.
So, having talked about that, the functional programming point o view aligns with the mathematical vision…variables are simply names bounded to a value, but these values, which represent the state of an application, can only be transformed by performing some operations on them (just like as the mathematical perspective). In other words, functions (i.e. operations) can only change the state. So if from an imperative point of view, the behavior of a program is given by the value of the memory locations, from a functional perspective the behavior of the program is driven by data transformation flow — when I say “transformation”, I’m not contradicting myself because I’m actually not talking about data modification but state modification. —
What is the difference?
As the data bindings can not be changed, the only way to reflect changes in the application state is by passing the current state to a new function using recursion. We can see it as passing knowledge from generation to generation, from parents to their children. That way, the values resulted from a given operation in a given iteration are passed to the next one, where will be used to set the new state of the app.
And so on until we reach maybe a breaking point and that loop is finished.
The subtitle of the previous article of this series
suggests that Functional Programming is incompatible with Object-Oriented Programming (and maybe even structured programming), which is not true. They can be combined to get the best of each one, which can be summarized as follows:
- Direct transfer of control thanks if/then/else kind of constructs derived from structured programming.
- Indirect transfer of control thanks to Object-Oriented polymorphism.
- Immutability.
Each paradigm brings something and supports us, as software engineers, to write better code by not having to use goto statements, function pointers, and assignments.
Well, that’s all for this article. We covered some interesting topics of the functional paradigm and compared them from different points of view. Keep in mind, the functional paradigm is also out there and that is enough reason to take a look at it.