First, there is the obvious idea that functions and data are closely associated within a particular topic area. OOPLs make this easy to do by using namespaces (classes) within which the data and functions can be defined and the functions have easy access to the data.
This has been called encapsulation; and many non-oo languages have facilities for achieving it. It's actually very each to create encapsulations in C that are even better than most OOPLS can achieve. But overall OOPLs offer adequate support for it.
The second is inheritance. The relationship has been much maligned in recent years, and with reason. Much of the recent resistance is due to the fact that statically typed languages have required some kind of inheritance in order to support polymorphism. This has led to an unfortunate menagerie of different kinds of inheritance. (public, private, protected, virtual, implements, extends...)
In reality inheritance should not be necessary for polymorphism. Duck typing works as well; but is more prevalent in dynamically typed languages.
The real benefit of inheritance is the ability to inherit implementation. It is handy to have a suite of encapsulated data and functions that can be inherited into other encapsulations.
The third benefit of OO is the strongest. Dynamic Polymorphism. This facility allows the programmer to safely invert source code dependencies against the flow of control. This could be done in C by using pointers to functions, but was risky and awkward. In OOPLs it is safe and natural.
The ability to invert dependencies makes it much easier to create flexible and robust architectures. Without it architectures are dependent upon the function call hierarchy. With dependency inversion the architecture of the system is _independent_ of the function all hierarchy. This allows plugins, and high level modules that are independent of the low level details they control.
There is much more that could be said about these benefits. But perhaps the most important is that these benefits are completely orthogonal to the benefits of procedural and functional programming. A functional programmer can ALSO do OO and gain the benefits of both. The best programmers use procedural, OO, and Functional together and good programming languages seamlessly support procedural code, OO code, and Functional code without bias.
• • •
Missing some Tweet in this thread? You can try to
force a refresh
I first saw this recommendation in the mid 90s in the Design Patterns book (or possibly in the materials that surrounded it). I believe it was espoused most vocally by John Vlissides.
🧵
First we need to remember that this was during a period when the implications of inheritance were not well understood. Inheritance was a relatively new language feature that the vast majority of programmers had no experience with.
Even those programmers who did have some experience with inheritance were mostly using Smalltalk, or some other dynamically typed language. C++ brought inheritance into a statically typed world that was unprepared for it.
The author’s primary point is that all the design patterns in the GOF book can be replaced with functional programming techniques like first class functions and function composition.
Let’s say that this is true. It is also true that I can replace every pattern in the book with pointers to functions in C. Does this mean that C makes design patterns obsolete? Of course not.
That political divisions have entered the software community is one of the saddest things I have experienced in my long and storied career.
That programmers who once respected each other professionally have now become unwilling, or socially unable, to display that respect due to a difference of political opinion is a disease that causes great harm to our industry and society.
Speakers whom we used to highly regard can no longer be invited to speak because organizers fear the reprisals of a small but vocal gaggle of activists who use despicable and immoral tactics to assassinate the reputations of any who oppose their politics.
There are some threads I’ve been following that suggest that the best design approach is just simplicity. I think that’s fine. Designs should be simple. But what exactly is simplicity? You may find Rich Hickey’s talk illuminating.
The short answer is: Simplicity is not easy. It takes time and thought to make something simple. And it takes something else. It takes principles.
In Rich’s talk he describes the ancient definition of “simple” as “one fold” or “one strand”. Compare that to the Single Responsibility Principle: A module should have only one reason to change. Note the similarity?
First we need to recognize that inheritance is just a special form of composition. Derived classes are composed of their base classes.
However, the coupling of derived to base is much tighter than composite to component.
The reason for this tight coupling is that inheritance is intimately tied to implementation whereas a component can be abstracted. The derived class IS an instance of the base class. The composite is not an instance of the component.
So the answer of when to prefer inheritance is a matter of how much implementation is in the base class. If there is none, as in the case of an interface, the cost of coupling is low. But inheriting a richly populated base class is very risky.
Years ago I was a student of Jiu Jitsu. As we learned and gained belt ranks, we also passed through three different fundamental areas of technique. Shodan, Nidan, and Sandan.
Each of these techniques spawned dozens of maneuvers, each of which had to be mastered. Once the entire set was mastered, then the student could graduate to the next fundamental technique.
Mastery of all the maneuvers within all three fundamental techniques was rewarded with the black-belt rank. And _then_ you _really_ started to learn.