Unlearning object oriented programming I think OOP became popular because it feels profound when you first grasp it. There is that euphoric moment when all the abstractions suddenly interlock, when inheritance, polymorphism, and encapsulation seem to dance together in perfect logic. It feels like you have entered a secret order of thinkers who understand something hidden. Each design pattern becomes a small enlighten…
The great achievement of OOP is that it inspires such passion. In essence OOP is just, "hey, if you have a struct and a bunch of operations that operate on that struct, let's put the name of the struct and a dot in front of the names of those operations and you don't need to pass the struct itself as an argument" It beats me how either the high priests or its detractors get so worked up about it, even with the add-on…
When state is mutable, every method that touches it becomes coupled to every other method that touches it. The object stops being a collection of independent behaviors and turns into a shared ecosystem of side effects. Once you mutate state, all the code that relies on that state is now bound together. The object becomes a single, indivisible unit. You cannot take one method and move it elsewhere without dragging the rest of its world along with it.
Functional programming avoids that trap. Functions are isolated. They take input and return output. They don’t secretly reach into a shared pile of state that everything else depends on. That separation is not aesthetic, it is structural. It’s what makes functions genuinely modular. You can pull them out, test them, recombine them, and nothing else breaks.
# OOP version
class Counter:
def __init__(self):
self.value = 0
def increment(self, n):
self.value += n
def double(self):
self.value *= 2
c = Counter()
c.increment(5)
c.double()
print(c.value)
Here, every method is bound to self.value. Change how one works and you risk breaking the others. They share a hidden dependency on mutable state.Now compare that to the functional version:
def increment(value, n):
return value + n
def double(value):
return value * 2
increment_and_double = lambda x: double(increment(x, 5))
print(increment_and_double(0))
In this version, increment and double are completely independent. You can test them, reuse them, and combine them however you like. They have no shared state, no implicit dependency, no hidden linkage.People often think OOP and FP are complementary styles. They are not. They are oppositional at the core. OOP is built on mutation and shared context. FP is built on immutability and isolation. One binds everything together, the other separates everything cleanly.
Mutation is what breaks modularity. Every time you let a method change shared state, you weave a thread that ties the system tighter. Over time those threads form knots, and those knots are what make change painful. OOP is built around getters and setters, around mutating values inside hidden containers. That’s not structure. It’s coupling disguised as design.
Functional programming escapes that. It separates state from behavior and turns change into a controlled flow. It makes logic transparent and free. It’s not just another way to code. It’s the only way to make code truly modular.