Object-oriented programming (OOP) has been used ever since the 1970s and 1980s and remains a popular paradigm found in languages like Java, C#, Python, etc.
Functional programming (FP) is on the rise, despite its origins tracing back to the 1950s.
OOP models software as objects that bring together data and possible interactions with it whereas FP treats functions as first-class citizens, emphasizes the use of functions, immutability and isolating side-effects.
FP aligns well with calculations-inputs and outputs and OOP models do well for rich domains, for example.
The strengths of OOP include good predictability and the ability to hide internal interactions but it suffers from verbosity and forced object-modeling.
The benefits of FP include immutability, easy debugging with the result of no side-effects and easier to reason code.
The downsides of FP are a steep learning curve and not our natural way of thinking, especially not for concepts we see as ‘objects’ in real life.
The union of the best of both worlds (FOOP) can be modeled using objects while making them immutable and side-effect-free. We can get the best of both worlds by leveraging FP for data processing, and OOP for rich domain modeling.
Individual languages are becoming multi-paradigm, supporting different paradigms to varying degrees.
We can have the best of both worlds. Used well together, these paradigms allow you to synthesize something better than either one could have done by itself.