DEV Community

Cover image for FP vs OOP ? I choose both !
Meidi Airouche for Onepoint

Posted on • Edited on

FP vs OOP ? I choose both !

Often, programmers consider Object Orientation and Functional Programming to be mutually exclusive forms of programming.

Usually, two camps clash (#humour) :

  • Those who think that OOP programers are naive boomers living in a past time
  • Those who think that FP is for imperative programers struggling to learn OOP

Those bias are based on a misunderstanding of what OO and FP really are.


The key differentiator of OOP is not state

"Objects are not data structures : they may use data structures." - Martin Fowler

The manner in which those data structures are used or contained is hidden. This is why data fields are private. From the outside looking in you cannot see any state. All you can see are methods (functions). Therefore, from an outside perspective, objects are about functions not about state.

Outside of their own context, objects are bunch of functions, not bunch of data.


OOP & FP are composed of functions that operate on data

  • Every functional program is composed of a set of functions that operate on data.
  • Every OO program is composed of a set of functions that operate on data.

However, it is common for OO programmers to define OO as functions and data bound together. All programs are functions bound to data. No matter the nature of the call (f(o) or o.f()). (this is where I lost Python programers)


So what are the main differences ?

FP requires discipline upon assignment

A pure functional programming language must have no assignment operator. You cannot change the state of a "variable" (constant would be a better naming : Hi JS developers !)

Does it mean that you can never change the state of something in a functional language? No, not at all.

F# allows you to use "mutable variables", clojure special "objects" (lmao) that may change their values.

The point is that a functional language imposes some kind of discipline and methodology on changes of state. You have to jump through the right hoops in order to do it.

Unfortunately, 99% of time, people don't.

OO induces discipline upon function pointers

Of course people will say OO is closer from "real life objects" and "the way we think". But, in fact, it's about pointers.

Think about polymorphism. It is implemented with function pointers. OO languages simply do that implementation for you, and hide the function pointers from you. Trying to write polymorphic code with function pointers depends on complex conventions that everyone must follow in every case.

In Java, every function you call is polymorphic. That means that every java function is called indirectly through a pointer to a function.

Using OOP to keep this complexity away from our code is a great asset.


So are FP and OOP mutually exclusive?

Can you have a language that imposes discipline on both assignment and pointers to functions? Of course you can. These two things don’t have anything to do with each other. And that means that OOP and FP are not mutually exclusive at all. It means that you can write OO-Functional programs.

It also means that all the design principles, and design patterns, used by OO programmers can be used by functional programmers if they care to accept the discipline that OO imposes on their pointers to functions.

But why would a functional programmer do that? What benefit does polymorphism have that normal Functional Programs don’t have? By the same token, what benefit would OO programmers gain from imposing discipline on assignment?

Benefits of Polymorphism

In most software systems when one function calls another, the runtime dependency and the source code dependency point in the same direction. The calling module depends on the called module.
However, when polymorphism is injected between the two there is an inversion of the source code dependency.

This inversion allows the called module to act like a plugin.

Plugin architectures are very robust because stable high value business rules can be kept from depending upon volatile low value modules such as user interfaces and databases (ex: Hexagonal architecture).

This means that in order to be robust a system must employ polymorphism across significant architectural boundaries.

Benefits of Immutability

The benefit of not using assignment statements is obvious: you can’t have concurrent update problems if you never update anything.

Since functional programming languages do not have assignment statements, programs written in those languages don’t change the state of very many variables. Mutation is reserved for very specific sections of the system that can tolerate the high ceremony required. Those sections are inherently safe from multiple threads and multiple cores.

The bottom line is that functional programs are much safer in multiprocessing and multiprocessor environments.


Conclusion

Finally, I chose to work in an OO-functional programming style because it allows me to get the most out of each approach. This is also, why I like Typescript.

Good news therefore: there is no need to choose, so, stay open-minded ;)

Top comments (3)

Collapse
 
fabricehategekimana profile image
fabriceHategekimana

Hi, I love your post ! You have a really deep understanding of both paradigm and you changed my point of view. I have my two cents on this topic:

Of course people will say OO is closer from "real life objects" and "the way we think".

Yes, I was thinking the same until I discovered algebraic data types from FP which are a more expressive way of representing things. Nowadays I don't think in term of classes and objects (which are limiting) but in term of types

In most software systems when one function calls another, the runtime dependency and the source code dependency point in the same direction. The calling module depends on the called module.
However, when polymorphism is injected between the two there is an inversion of the source code dependency.

To be honest I didn't understood this part. To be more precise which kind of polymorphism (generics, ad-hoc, etc.) is used there ? Or is it about late binding that let some flexibilities in the run time creating a more dynamic program ?

Finally I am also using both paradigms: FP for modeling data and functions and OOP for protocols and communication between entities

Collapse
 
mairouche profile image
Meidi Airouche

Hi,

Thanks a lot for your feedback. I'm glad you share the same vision.
I should probably add an exemple for the dependency part. I would add this example below, what do you think ?

Let's consider two classes: Service and Client.

In a system without polymorphism, Client directly calls a method on Service. Client directly depends on Service both in the source code and at runtime.

If we introduce an interface ServiceInterface, which Service implements, Client no longer depends directly on Service. Instead, Client depends on ServiceInterface. Now, the source code dependency is inverted: Service depends on ServiceInterface, and Client depends on ServiceInterface, but not directly on Service. However, at runtime, Client will still depend on an instance of Service, or another class that implements ServiceInterface.

Collapse
 
fabricehategekimana profile image
fabriceHategekimana

Thanks, that's a great example. I better understand