> This argument seems to come up for every criticism of OO.
The same is true of functional and procedural programming, too.
The problem, as I see it, is that the profession has a history of treating programming paradigms as just being a bag of features. They're not just that, they're also sets of guiding principles. And, while there's something to be said for knowing when to judiciously break rules, blithely failing to follow a paradigm's principles is indeed doing it badly.
This is a particular problem for OO and procedural programming. At least as of this current renaissance that FP is enjoying, advocates seem to be doing a much better job of presenting functional programming as being an actual software design paradigm.
It's also the case that, frankly, a lot of influential thought leadership in object-oriented programming popularized some awful ideas whose lack of merit is only beginning to be widely recognized. If null is a billion dollar mistake, then the Java Bean, for example, is at least a $500M one.
> The same is true of functional and procedural programming, too.
There are some specific criticisms that are levied against FP for which proponents respond “that’s not true FP”. For example, the criticism “FP is too preoccupied with monads” might engender such a response; however, this response is appropriate because it’s not one of the defining features of FP. Yet for FP, there are still pretty widely-agreed upon features or conventions (functional composition, strong preference for immutability, etc).
For OOP, I can’t think of any features or styles that are widely agreed upon. If you mention inheritance, half of OOP proponents will argue that inheritance isn’t a defining characteristic because Kay didn’t mention it in his definition. If you mention message-passing, many others will object. If you mention encapsulation, then you’ve accidentally included virtually all mainstream paradigms.
If OOP is a distinct thing, and it isn’t about inheritance or message passing or encapsulation or gratuitous references between objects (the gorilla/banana/jungle problem), then what exactly is it?
The term may be muddied but it’s not meaningless. Alan Kay’s vision of OO (“it’s about message passing”) never seemed to really take off in the world. When people talk about OO they usually mean classes, objects and methods, used for almost everything as the primary unit of composition. And classes with public methods encapsulating private fields. And often with a dash of inheritance. C++ and Java seem like the flag bearers for this style of programming. It’s popular in C# too.
When people criticise OO, they’re usually criticising this the “Effective Java” style, expressed in whatever language. This style is deserving of some criticism - it’s usually more verbose and harder to debug than pure functional code. And it’s usually less performant than the data oriented / data flow programming style you see in most modern game engines.
OOP the paradigm (messaging and memory encapsulation) is pretty different from OOP the style (access modifier, class+method+properties, inheritance).
As a strong proponent of FP the paradigm, I insist OOP the paradigm is great to study and apply in a system software where there are multiple agencies. For example, in a browser there are multiple "agencies", network-facing workers, storage-facing workers, human-facing workers, etc, as each "agencies" runs at different to pace to make its "client" (networkAPI, storageAPI, human) happy, therefore messaging and buffering between those "agencies" inevitable.
FP also suffers the same issue.
FP the paradigm: pure functions, expression-based, recursion, first-class function, parsing > validation (universal, almost applicable in any programming language)
FP the style: monad, functional-based language, tail-call optimization
Being overly-critical over style is not productive in the long term. Someday one will have to leave the tool for a new one.
Learning the universal part of paradigms is useful because it is not dependent to tools.
So, that's still focusing on features. If we're talking about it from a paradigmatic perspective, instead, then I would argue that the prototypical idea behind object-oriented design is indeed encapsulation.
It's true that this is not a distinguishing feature. I don't see that as problematic, it's just how things work. Object-oriented programming, like any paradigm, evolved over time, as people built languages with new ideas, and then spent time figuring out how best to make use of them. And there's no rule saying that nobody is allowed to subsequently adopt and adapt a useful idea in other domains. Fuzzy boundaries are part of the natural order, and that is a good thing.
But, if you go back and read the seminal papers, it's clear that the common thread is encapsulation, every bit as much as referential transparency is the core idea that unites all the seminal work in functional programming. The idea was that programs would be decomposed into modules that were empowered to make their own decisions about what code to execute in response to some instruction. And that this was supposed to liberate the programmer from needing to micro-manage a bunch of state manipulation. Not by eliminating state, as is the ideal in FP, but by delegating the responsibility to manage it.
This is why the concept of Beans bothers me. A Bean is a stateful object that throws its state into your face, and forces you to directly manage it. That sort of approach directly contradicts what OOP was originally supposed to be trying to accomplish. For my part, I am convinced that the bulk of the backlash against OOP is really a response to the consequences of that sort of approach having become orthodox in OOP. Which is deeply ironic, because this is an approach that enshrines the very kinds of practices that the paradigm originally sought to eliminate.
The problem with encapsulation in OOP, is that the (mutable) state is not truly encapsulated, it is just hidden. State encapsulation would be a pure function that uses mutation internally. OOP encourages mutable state and in general it is non-trivial to compose such effectful code. The state space of an OOP application can become a combinatorial explosion. This might be what you want if you are modelling something with emergent complexity, e.g. a simulation or game, but doesn't sound good for a line-of-business app.
As an anecdote, I once saw a stack overflow reply from a distinguished OOP engineer advocating for modelling a bank account with an object containing a mutable balance field! That is certainly not modelling the domain (an immutable ledger). OOP might fit some problems well, but the cult of presenting it as the one-true-way (made concrete in 90's Java) is deserving of a backlash IMHO.
> But, if you go back and read the seminal papers, it's clear that the common thread is encapsulation, every bit as much as referential transparency is the core idea that unites all the seminal work in functional programming. The idea was that programs would be decomposed into modules that were empowered to make their own decisions about what code to execute in response to some instruction. And that this was supposed to liberate the programmer from needing to micro-manage a bunch of state manipulation. Not by eliminating state, as is the ideal in FP, but by delegating the responsibility to manage it.
I agree with that assessment, but I also think the problems with OO are inherent to that paradigm, and it's time to acknowledge that the paradigm is bad and has failed.
> This is why the concept of Beans bothers me. A Bean is a stateful object that throws its state into your face, and forces you to directly manage it.
I disagree.
Beans are Java's version of the ideas expressed in Visual Basic and, later, COM -- ideas often called something like "software componentry". They are objects that can be instantiated and configured without having to write custom code to invoke their methods, because the instantiation and configuration follow accepted standards, as well as the means by which they register to subscribe to and publish events. This lets them be instantiated and manipulated by other tools in the pipeline, such as a GUI builder tool or an automatic configurator like the one in Spring Framework.
If we go by Alan Kay's definition, then we can argue Elixir/Erlang is an OO language [0]. It's not the first language one would think of when talking about OOP, is it?
So is it dot-method notation (`foo.Bar()`)? If so, does that make Go and Rust OOP as well? That's just syntax though; what about the C convention of `ClassName_method_name(ClassName obj)`? That's still namespace by the type even if the language* doesn't have a first-class notion of a type prefix.
The same is true of functional and procedural programming, too.
The problem, as I see it, is that the profession has a history of treating programming paradigms as just being a bag of features. They're not just that, they're also sets of guiding principles. And, while there's something to be said for knowing when to judiciously break rules, blithely failing to follow a paradigm's principles is indeed doing it badly.
This is a particular problem for OO and procedural programming. At least as of this current renaissance that FP is enjoying, advocates seem to be doing a much better job of presenting functional programming as being an actual software design paradigm.
It's also the case that, frankly, a lot of influential thought leadership in object-oriented programming popularized some awful ideas whose lack of merit is only beginning to be widely recognized. If null is a billion dollar mistake, then the Java Bean, for example, is at least a $500M one.