By this point, we have discovered that:
Now let's discuss why Functional Programming (FP) and Procedural Programming (PP) are not good alternatives when it comes to multi-paradigm languages.
Let's talk about why that's the case:
Functional Programming (FP)
One of the main advantages of functional programming, which became the foundation of all functional languages and constructs, is the parallelization of calculations made possible through immutability.
Let me explain what this means.
Tell me, in what sequence, in any language, will these functions execute:
const user = { name: "David" weight: 87 age: 27 } changeUserAge(user, 28) changeUserWeight(user, 92)
If you don't come from a functional world, you'll say that first
changeUserAge
will run, and then changeUserWeight
.But in the functional world, these two functions will run simultaneously.
Before I give the answer as to why it works this way in both situations, think about it yourself.
3... 2... 1...
The essence is in how mutations are handled in your language.
If your language allows you to mutate any data (e.g.,
const user
), then it has to execute the code sequentially because it cannot know if the next function (changeUserWeight
) is waiting for the results of mutations from the previous one (changeUserAge
).But if your language works with immutable structures and you call 2 functions where you pass an immutable structure, it can run both functions in parallel because it knows for certain that the original value won't change.
To run them sequentially, special continuation techniques are used.
This language feature is also called "stateless," meaning "the absence of state in the programming language."
And it's because of this feature, to maintain "statelessness," that constructs like Monads, Functors, Semigroups, Pipes, and all the other magic of FP languages appear.
But the question arises: why should we use all this if 99% of multi-paradigm languages are stateful, mutable, and without automatic parallelization?
The answer is: we don't need all of this.
We won't get any of the advantages available in FP languages and will only get a bunch of non-native and difficult-to-understand constructs.
Honestly, I would rather work with pure OOP in a multi-paradigm language than with FP in the same language.
Therefore, full-fledged FP is not an option for us, BUT we can extract some techniques and mechanisms from FP that will be super useful to us.
P.S.
I also want to clarify that working with immutability is a very challenging task that can greatly complicate the codebase and affect the performance of multi-paradigm languages. That's why FP doesn't suit us, as working with mutable structures in it is completely different from what we do in multi-paradigm languages.
Procedural Programming (PP)
Procedural programming is a much more suitable alternative to OOP and FP because it solves the problems of OOP (as discussed below), but without adding the unnecessary complexity of FP to multi-paradigm languages.
The problem with PP is that it hasn't evolved since the 90s.
In PP, it's normal to have and mutate global state (which is an extremely dangerous approach), it has no pillars, no techniques like composition, currying, and partial application (which can be very useful), no concept of "higher-order function" (which removes many ways to pass functions to each other), and so on.
All of this also creates the problem that you won't be able to google how to properly solve architectural problems in PP because these architectural rules simply don't exist.
What's good about FP and PP
First of all, both FP and PP solve the main problem of OOP that I wrote about in the previous chapter: excessive atomicity.
The fact is that in both paradigms, a program is a set of functions that can use any data they are interested in.
That is, we simply describe the data:
And then, for each new feature, we can create a function that takes any data as input and operates on it:
Thus, we don't create any additional layers of isolation and use "natural encapsulation" to the maximum.
This approach is called "Data and Behavior Separation," as opposed to OOP's Encapsulation.
Secondly, a consequence of this approach is the absence of problems with Cross Cutting Concern (because any function can use any data), as well as the needlessness of patterns like SOLID (yes, they're simply not needed).
There's a slide that perfectly represents this consequence:
Thirdly, instead of Inheritance and Class polymorphism from OOP, we can actively use Composition and Interface polymorphism (which is considered a best practice even in OOP)
So what do we do?
It was precisely because I wanted to use these advantages of PP and FP that I created Function Oriented Programming (FOP).
FOP is based on Procedural programming but adds all the features that we got through the development of Functional programming, without excessive complication.
What's next
Let's summarize all the above in the chapter 2.5. That's why (λ) FOP emerged
👈 Previous chapter
Next chapter 👉