One can often hear that OOP naturally corresponds to the way people think about the world. But I would strongly disagree with this statement: We (or at least I) conceptualize the world in terms of relationships between things we encounter, but the focus of OOP is designing individual classes and their hierarchies.

Note that, in everyday life, relationships and actions exist mostly between objects that would have been instances of unrelated classes in OOP. Examples of such relationships are: "my screen is on top of the table"; "I (a human being) am sitting on a chair"; "a car is on the road"; "I am typing on the keyboard"; "the coffee machine boils water", "the text is shown in the terminal window."

We think in terms of bivalent (sometimes trivalent, as, for example in, "I gave you flowers") verbs where the verb is the action (relation) that operates on two objects to produce some result/action. The focus is on action, and the two (or three) [grammatical] objects have equal importance.

Contrast that with OOP where you first have to find one object (noun) and tell it to perform some action on another object. The way of thinking is shifted from actions/verbs operating on nouns to nouns operating on nouns -- it is as if everything is being said in passive or reflexive voice, e.g., "the text is being shown by the terminal window". Or maybe "the text draws itself on the terminal window".

Not only is the focus shifted to nouns, but one of the nouns (let's call it grammatical subject) is given higher "importance" than the other (grammatical object). Thus one must decide whether one will say terminalWindow.show(someText) or someText.show(terminalWindow). But why burden people with such trivial decisions with no operational consequences when one really means show(terminalWindow, someText)? [Consequences are operationally insignificant -- in both cases the text is shown on the terminal window -- but can be very serious in the design of class hierarchies and a "wrong" choice can lead to convoluted and hard to maintain code.]

I would therefore argue that the mainstream way of doing OOP (class-based, single-dispatch) is hard because it IS UNNATURAL and does not correspond to how humans think about the world. Generic methods from CLOS are closer to my way of thinking, but, alas, this is not widespread approach.

Given these problems, how/why did it happen that the currently mainstream way of doing OOP became so popular? And what, if anything, can be done to dethrone it?

OOP is unnatural for some problems.  So's procedural.  So's functional.  I think OOP has two problems that really make it seem hard.


Some people act like it's the One True Way to program and all other paradigms are wrong.  IMHO everyone should use a multiparadigm language and chose the best paradigm for the subproblem they're currently working on.  Some parts of your code will have an OO style.  Some will be functional.  Some will have a straight procedural style.  With experience it becomes obvious what paradigm is best for what:

a.  OO is generally best for when you have behaviors that are strongly coupled to the state they operate on, and the exact nature of the state is an implementation detail, but the existence of it cannot easily be abstracted away.  Example:  Collections classes.

b.  Procedural is best for when you have a bunch of behaviors that are not strongly coupled to any particular data.  For example, maybe they operate on primitive data types.  It's easiest to think of the behavior and the data as separate entities here.  Example:  Numerics code.

c.  Functional is best when you have something that's fairly easy to write declaratively such that the existence of any state at all is an implementation detail that can be easily abstracted away.  Example:  Map/Reduce parallelism.
OOP generally shows its usefulness on large projects where having well-encapsulated pieces of code is really necessary.  This doesn't happen too much in beginner projects.

