You’re missing the depth of the difference. It’s not just syntax sugar for calling object.method() instead of func(object). The key distinction is what happens when the method mutates the object.
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.