OO VS FP

Original author: Robert "Uncle Bob" Martin
  • Transfer
My translation , like the original report, caused a mixed reaction in the comments. So I decided to translate Uncle Bob’s response article to the original material.
Over the past few years, many programmers have argued that OOP and FP are mutually exclusive. From the height of an ivory tower in the clouds, FP celestials sometimes glance down at the poor naive OOP programmers and condescend to arrogant comments. Adherents of the PLO, in turn, look askance at the "functionaries", not understanding why scratching the left ear with the right heel.

These points of view ignore the very essence of OOP and FP paradigms. I’ll put in my five cents.

OOP is not about the internal state


Objects (classes) are not data structures. Objects can use data structures, but their implementation details are hidden. This is why private class members exist. From the outside, only methods (functions) are available to you, so objects are about behavior, not state.
Using objects as data structures is a sign of poor design. Tools like Hibernate call themselves ORM. It is not correct. ORMs do not map relational data to objects. They map relational data to data structures. These structures are not objects. Objects group behavior, not data.
I think that here Uncle Bob scolds ORM for what they often push towards an anemic model, and not to a rich one.
Functional programs, like object-oriented ones, are a composition of data transformation functions. In OOP, it is customary to combine data and behavior. So what? Is it really that important? Is there a huge difference between f(o), o.f()and (f o)? What, all the difference in syntax. So what are the real differences between OOP and FP? What is in OOP, what is not in FP and vice versa?

FI imposes discipline on assignment (immutability)


There is no assignment operator in Tru FP. The term “variable” does not apply to functional PLs at all, because once you assign a value, you cannot change it.
Yes. Yes. Apologists for AF often indicate that functions are first-class objects. In Smalltalk, functions are also first class objects. Smaltalk is an object-oriented rather than a functional language.

The key difference is not in this, but in the absence of a convenient assignment operator. Does this mean that there is no mutable state in the phase transition? Not. In FP languages ​​there are all kinds of tricks that allow you to work with mutable state. However, to do this, you will have to perform a certain ceremony. The change of state looks complex, cumbersome, and foreign to AF. This is an exceptional measure, which is resorted to only occasionally and reluctantly.

OOP imposes discipline in work with pointers to functions


OOP offers polymorphism as a replacement for function pointers. At a low level, polymorphism is implemented using pointers. Object oriented languages ​​just do the job for you. And this is great, because working with function pointers directly (as in C) is inconvenient: the whole team needs to adhere to complex and uncomfortable conventions and follow them in each case. Usually, this is simply not realistic.

In Java, all functions are virtual. This means that all functions in Java are not called directly, but using function pointers.

If you want to use polymorphism in C, you will have to work with pointers manually and this is difficult. You want polymorphism in Lisp: you have to pass functions as arguments yourself (by the way, this is called a strategy pattern). But in object-oriented languages, all this is out of the box: take it and use it.

Mutually exclusive?


Are the two disciplines mutually exclusive? Can YaP impose discipline in assignment and when working with pointers to functions. Of course it can! These things are not related at all. These paradigms are not mutually exclusive. This means that you can write object-oriented functional programs.

It also means that OOP principles and patterns can also be used in functional programs if you accept the discipline of "function pointers." But why are these “functionaries”? What new benefits will it give them? And what can object-oriented programs get from immutability.

The benefits of polymorphism


Polymorphism has only one advantage, but it is significant. This is the inverse of source code and runtime dependencies.

In most systems, when one function calls another, runtime dependencies and dependencies at the source code level are unidirectional. The calling module depends on the called module. But in the case of polymorphism, the calling module still depends on the called in runtime, but the source code of the called module does not depend on the source code of the called module. Instead, both modules are dependent on a polymorphic interface.

This inversion allows the called module to behave like a plugin. Indeed, plugins work like that. The plugin architecture is extremely reliable because stable and important business rules can be stored separately from the subject to changes and not so important rules.

Thus, for reliability, systems must use polymorphism to create meaningful architectural boundaries.

The benefits of immutability


The benefits of immutable data are obvious - you will not run into problems with simultaneous updates if you never update anything.

Since most functional PLs do not offer a convenient assignment operator, in such programs there are no significant changes in the internal state. Mutations are reserved for specific situations. Sections containing a direct state change can be separated from multi-threaded access.

In sum, functional programs are much safer in multi-threaded and multi-processor environments.

Boring philosophizing


Of course, adherents of OOP and FP will be against my reductionist analysis. They will insist that there are significant philosophical, philological, and mathematical reasons why their favorite style is better than the other. My reaction is: Pffff! Everyone thinks their approach is better. And everyone is wrong.

So what about principles and patterns?


What caused me such annoyance? The first slides hint that all the principles and patterns that we have developed over decades of work are applicable only to OOP. And in FP everything is decided simply by functions.

Wow, and after that you say something about reductionism? The idea is simple. The principles remain unchanged, regardless of programming style. The fact that you chose PL without a convenient assignment operator does not mean that you can ignore SRP or OCP, that these principles will somehow work automatically. If the “Strategy” pattern uses polymorphism, this does not mean that it cannot be applied in functional PL (for example, Clojure).

In total, OOP works if you know how to cook it. Similarly for FP. Functional object-oriented programs are generally great if you really understand what that means.

Also popular now: