1. In OOP, one object is special.
Whether it’s the object that is receiving a message or the object that gets a special designation like `this` or `self`, something is always given a special emphasis in a purely OOP design.
However, many useful algorithms take multiple inputs where none needs to be singled out in that way. Where do such algorithms live?
Trivial example: A symmetric binary operator like +.
Grown-up example: You don’t really model funds transfers by sending a `debit` message to one instance of a `BankAccount` class and a `credit` message to another instance.
2. In OOP, one object is special.
This is a generalisation of the point that zmb_ made. Usually in programming we don’t work only with single, self-contained data points. Most interesting things happen when we manipulate structured data and consider relationships between data points.
In purely OOP designs, we often see classes representing single data points, and then further classes to represent containers of that type. However, if the implementation of each data point is locked up behind the interface to a particular class, and then we have to access the points in each container through the container’s own generic interface, we are constrained in the access patterns we can use. Emphasizing individual, self-contained data points is often the wrong level of granularity for promoting either code reuse or efficient designs.
Example 1: What if we want to implement a more efficient representation of a data set that supports a different access pattern, such as the kind of continuous memory case zmb_ mentioned?
Example 2: What if we want to enforce constraints on a whole set of data, or model relationships between structured data of different types?
In each case, it may be very difficult to reuse existing algorithms that are locked up in methods on existing single-data-point classes. We might want to store the underlying data in a different format, and converting between formats just to access functionality artificially tied to a specific variation is likely to be awkward and inefficient.
If we instead build our modules as a set of fundamental data types and a set of accompanying algorithms — which could be as simple as a library of C structs/enums and functions using them — then the artificial barrier doesn’t arise. We can still present a clean interface/implementation for each module as a whole, but we aren’t forcing the implementation details to be separated just because Everything Must Be A Class.