Contrary to popular opinion, implementation inheritance is not a conceptually correct representation of an “is a” relationship in programming.

One of the most common intuitions people have in object oriented programming is that inheritance models an “is a” relationship between objects whereas composition models a “has a” relationship between objects. In the case of composition, this intuition is valid and causes no problems. Unfortunately however, the corresponding intuition for inheritance is actually wrong, despite how extremely popular it is.

The problem is that inheritance only actually models a small subset of possible “is a” relationships, and thus when programmers have the habit of thinking “I should use inheritance!” whenever they see any “is a” relationships the inevitable outcome is nearly always a poorly designed representation of the relationships between the objects being modeled.

Yet, it’s very easy to delude oneself into believing that one’s model of an object system is far better than it is however, due to cognitive biases and lack of imagination, and when you combine that with the high prevalence of this incorrect intuition (“is a” = “inheritance”) being widely taught in college courses and on countless articles and forum discussion pages across the internet the net result is that only a minority of programmers currently seem to actually correctly understand the nuances involved here.

In fact, the only conceptually correct way to represent “is a” relationships is to represent them as subset relationships of some kind. In contrast though, implementation inheritance (in the traditional sense of how most programming languages do it at least) is only capable of correctly representing hierarchical relationships, which are just a small subset of the set of all possible subset relationships. Interfaces (for example) can represent subset relationships, but implementation inheritance in contrast certainly cannot.

Hierarchical relationships are actually highly unnatural and artificial in most contexts, besides for performance in algorithms. Most real relationships are generalized set relationships and composition relationships, not hierarchies. Even seemingly “obvious” cases where people tend to think a hierarchy would be OK are often actually very conceptually wrong. Indeed, you are extremely likely to be shooting yourself in the foot any time whatsoever that you ever use the mere existence of an “is a” relationship as a justification for inheritance. That kind of intuition is simply flatly and fundamentally wrong. Don’t use it.

The conceptual limitations of hierarchical relations are far too pervasive and misleading for it to be conceptually safe to use them much for modelling object relationships. Even the most trivial inheritance hierarchies would nearly always be better designed a different way. The great ease with which people trick themselves into glossing over the details and thinking that a hierarchy is a good idea (when it seldom ever actually is) is why some new programming languages such as Rust and Go have been designed to intentionally not include inheritance.

The near ubiquity of conceptually incorrect intuitions of what inheritance actually is within the programming community are disconcerting. If you think from first principles in contrast though, from clearly thought out logical deductive reasoning, then the wrongness of the idea that inheritance correctly models “is a” relationships is readily apparent and bordering on obvious. This is yet another example of how the power of social pressures, groupthink, and lack of imagination to distort people’s “thinking” should not be underestimated, even within communities that are generally trained to think rationally.

Too much homogeneity in how people think about a problem endangers intellectual freedom and diversity of thought and greatly increases the chances of people becoming effectively blind even to the most logically obvious problems in how things are done. Popularity has no reliable correlation to truth.

A subjective emotional feeling that something “feels right” for modelling something has little to do with genuine logical knowledge of whether it really does fit well or not. Inheritance is just one widely prevalent example of that. Just because a ton of programmers emotionally feel like inheritance fits well for them doesn’t mean it actually does. From an outsider’s perspective it is fairly easy to see the numerous holes in such systems. One should not underestimate how easily one can become blind to the nuances of reality and commit countless subtle errors of thought.

It is easy to trick oneself into believing that one really is “thinking” about something and has a genuine basis for one’s belief, when in reality one is only just conforming to the group and in fact the sense of “certainty” one has is in reality nothing more than an emotion of certainty, which may have zero connection to authentic logical certainty.

Just because something “works” doesn’t make it conceptually correct. Granted that the final value of what is produced is still the most important part of course (and indeed there is lots of very valuable, but conceptually incorrect, software out there), it is still nonetheless true that many false beliefs in circulation in society make life a lot more complicated, brittle, and capricious than it needs to be. Just even a tiny bit of genuine thought (not groupthink) is often all that it takes to break the illusion and to suddenly start seeing things much more clearly.