An object is a grouping of primitives. So according to your logic OOP should have the same problem.
The real issue isn't grouping. The true nature of abstractions is the formation of higher level abstractions from "groupings" of lower level primitives. So "grouping" is fundamental to abstraction and therefore fundamental to programming.
The problem with OOP is that the groupings are forced. I cannot reuse a method outside of the context of the object because the method is tied to mutable state.
For example:
Try to write a function addOneTimesTwo from the composition of the three primitives below (in python):
def addOne(number):
return number + 1
def timesTwo(number):
return number * 2
def compose(f, g):
return lambda x: f(g(x))
Answer:
addOneTimesTwo = compose(timesTwo, addOne)You will note, compose is a universal functional operator. The definition for compose above is the most primitive way to compose functions in FP.
Try to do the same with OOP:
class AdditionObject:
def __init__(self, number):
self.number = number
def addOne(self):
self.number += 1
class MultiplicationObject:
def __init__(self, a, b):
self.a = a
self.b = b
def mult(self):
return self.a * self.b
Certainly do-able with OOP. But I cannot extract the methods away from the state. In order to use the banana (method) I need the gorilla holding it and the entire forest it lives in (Object) to come with it.It can be done, but generally you need a lot more glue code to make it work especially given the fact that people can get more creative with OOP. As you can see the MultiplicationObject is an example of this creativity. It was written with a different interface then the AdditionObject.
Basically if you know haskell even similar issues to the above can be dealt with in terms of haskell. You can certainly define a composition operator for even the most complex types. The issue with OOP is that EVERYTHING is a complex type. A standard Object already has enough complexity to necessitate custom composition operators so you're basically writing custom glue code everywhere. Either you're writing complex glue code or your bending all your code to fit into a framework.
Nothing is truly modular.