That's a platitude which everybody can and does say about everything.
But I think one can make a case that there is something wrong with OO in general. The original arguments for OO were: it's better for managing complexity, and it creates programs that are easier to change. Both of these turned out not to be true in general. So we need to ask, when is OO a win? But for simpler problems it doesn't matter, because anything would work. So we need to ask: what are the hard problems that OO makes significantly easier? I don't think anyone has answered that.
I suspect it's that OO is good when the problem involves some well-defined system that exists objectively outside the program - for example, a physical system. One can look at that outside thing and ask, "what are its components?" and represent each with a class. The objective reality takes care of the hardest part of OO, which is knowing what the classes should be. (Whereas most of the time that just takes our first hard problem - what should the system do? - and makes it even harder.) As you make mistakes and have to change your classes, you can interrogate the outside system to find out what the mistakes are, and the new classes are likely to be refinements of the old ones rather than wholly incompatible.
This answer boils down to saying that OO's sweet spot is right where it originated: simulation. But that's something of a niche, not the general-purpose complexity-tackling paradigm it was sold as. (There's an interview on Youtube of Steve Jobs in 1995 or so saying that OO means programmers can build software out of pre-existing components and that this makes for at least one order of magnitude more productivity - that "at least" being a marvelous Jobsian touch.)
The reason OO endures as a general-purpose paradigm is inertia. Several generations of programmers have been taught it as the way to program -- which it is not, except that thinking makes it so. How did it get to become so standard? Story of the software industry to date: software is hard, so we come up with a theory of how we would like it to work, do that, and filter out the conflicting evidence.
If people aren't moving on, it's not simply because of 'intertia'. It's because the alternatives aren't offering enough benefit yet.
What will change the paradigm is the desire of a future generation to make its mark by throwing out how the previous generation did things. One can see this trying to happen with FP, though I doubt FP will reach mass appeal.
When you do anything as intensely as writing software demands, your identity gets involved. When identity is involved, emotions are strong. The image of being a rational engineer is mostly a veneer on top of this process.
Edit: 'intertia' - your making fun of an obvious typo rather illustrates the point.
So this is basically a contentless argument that says people are stuck on OO because they are irrational.
As you me 'making fun' of a typo - I don't know what you're projecting onto me. I simply mistyped the word inertia. I put it in quotes because I don't think it's a cause of anything.
As for OO, I think our disagreement has probably reached a fixed point.
Edit: nah, I can't resist one more. I believe I explained how the inertia was overcome before: people who were not identified with the dominant theory at the time (structured programming) came up with a new one (object-orientation) and convinced themselves and others that it would solve their problems. Why did they do that? Because the old theory sucked and they wanted to do better. Their error was in identifying with the new theory instead of failing to see that it also sucks. The only reason they could see that the old theory sucked was that it was someone else's theory.
As for "what would replace OO if not for inertia", I know what my replacement is: nothing. I try to just let the problem tell me what to do and change what doesn't work. Turns out you can do that quite easily in an old-fashioned style. But if you mean what paradigm will replace OO (keeping in mind that we ought to give up our addiction to paradigms), who knows? FP is a candidate. One thing we can say for sure is that something new and shiny-looking will come along, until we eventually figure out that the software problem doesn't exist on that level and that all of these paradigms are more or less cults.
Perhaps I should add that I don't claim to know all these things. I'm just extrapolating from experience and observation of others.
The trouble I have with what you're saying is it suggests that a better paradigm (e.g. FP), higher-level and more powerful, will improve upon and succeed OO. But the greatest breakthroughs in my own programming practice have come from not thinking paradigmatically- to be precise, from seeing what I was assuming and then not assuming it.
Edit: My own experience has been this weird thing of moving back down the power continuum into an old-fashioned imperative style of programming, but still very much in Lisp-land. For me this has been a huge breakthrough. Yet my code isn't FP and it certainly isn't OO, so I guess it must be procedural. How much of this is dependent on the language flexibility that comes with Lisp? vs. just that Lisp happens to be what I like? Hard to say, but I suspect it's not irrelevant. If you can craft the language to fit your problem, you can throw out an awful lot. Like, it's shocking how much you can throw out.
How so? I find OOP code to be much easier to understand and change.
Considerable size of the system is because of considerable complexity of the task at hand. I don't see how you can write 1000-page book of requirements into 2 screens of code. And if you need the system that is able to be customized to satisfy different books with minimal change - you need more complex code.
Wrong. Even the worst Enterprisey mess of Java classes and interfaces that you can find today, is probably better than most of the spaghetti, global state ridden, wild west that existed in the golden days of "procedural" programming.
If you consider that software is composed of Code and Data, then OOP was the first programming model that offered a solid, practical and efficient approach to the organization of data, code and the relationship between the two. That resulted in programs that, given their size and amount of features, were generally easier to understand and change.
That doesn't mean OOP was perfect, or that it couldn't be misused; it was never a silver bullet. With the last generation of software developers trained from the ground up with at least some idea that code and data and need to be organized and structured properly, it's time to leave many of the practices and patterns of "pure" OOP and evolve into something better. In particular, Functional has finally become practical in the mainstream, with most languages offering efficient methods for developing with functional patterns.
With the global state code you have to understand the entire codebase to be sure who exactly is modifying a particular bit of state. This is far more fragile because the "interaction space" of a bit of code is much greater. The dangerous part is that while you must understand the whole codebase, the code itself doesn't enforce this. You're free to cowboy-edit a particular function and feel smug that this was much easier than the enterprisey code. But you can't be sure you didn't introduce a subtle bug in doing so.
The enterprisey code is better because it forces you to understand exactly what you need to before you can modify the program. Plus the layered abstractions provide strong type safety to help against introducing bugs. Enterprisey code has its flaws, but I think its a flaw of organization of the code rather than the abstractions themselves. It should be clear how to get to the code that is actually performing the action. The language itself or the IDE should provide a mechanism for this. Barring that you need strong conventions in your project to make implementations clear from the naming scheme.
I agree that a project needs strong conventions, consistently practiced. See Eric Evans on ubiquitous language for the logical extension of that thinking. But this is as true of OO as anywhere else.
>interactions between objects can be just as hard to understand as any other interactions.
While this is true, there are strictly fewer possible interactions compared to the same functionality written only using primitives. To put it simply, one must understand all code that has a bit of data in its scope to fully understand how that bit of data changes. The smaller the scopes your program operates in, the smaller the "interaction space", and the easier it is to reason about. Class hierarchies do add complexity, but its usually well contained. It adds to the startup cost of comprehending a codebase which is why people tend to hate it.
In my experience, classes don't give the kind of scope protection you're talking about. They pretend to, but then you end up having to understand them anyway. True scope protection exists as (1) local variables inside functions, and (2) API calls between truly independent systems. (If the systems aren't truly independent, but just pretending to be, then you need to understand them anyway.)
In python you can access any classes internals if you're persistent enough. However, the difficulty in doing so and the convention that says that's bad practice gives the perception of a separation, thus one does not need to be concerned about its implementation. It lowers the cognitive burden in using a piece of functionality.
Haven't you noticed this yourself? A simpler interface is much easier to use than a more complicated one. If you're familiar with python, perhaps you've used the library called requests, its a pythonic API for http reqeusts. Compare this to the core library API using urllib2. The mental load to perform the same action is about an order of magnitude smaller with requests than urllib2, and its because there are far more moving parts with the latter.
My contention is that if bits of data and code are exposed to you, it is essentially a part of the API, even if you never actually use it. You still must comprehend it on some level to ensure you're using data it can access correctly, aka interaction space (I feel like I'm selling a book here).
Part of the allure of Java: it gives the illusion that more progress was made before you entered that region.
We've all heard that you can shoot yourself in the foot with any language, but I think the implications haven't fully sunk in: There are no bad paradigms, only bad codebases.