I don't think inheritance is bad at all. It is very often the easiest way by far to model a problem. Sure, it's not perfect, but I think it is wildly overhated by a vocal minority.
Have you ever seen wildly over-architected OO code where everything seems to be an abstract class and it seems impossible to find out where stuff actually happens?
Inheritance is like a lot specialised tools - it can be useful in some situations but I think those are rarer than supporters might thing. Completely refusing to use inheritance and always using inheritance both seem like extreme views that should be avoided.
You haven't lived life to the fullest until you've had to debug an issue in a 12-layer-of-inheritance class with the original call ping-ponging a couple dozen times across the layers and overrides everywhere.
I guess one could say this would be workable with proper tools, but the IDEs just aren't there. Move up a level in inheritance, ctrl-click on a call? It was overriden somewhere in the hierarchy, but the IDE will send you to the parent-class definition regardless.
I have actually seen one (1) beautiful C++ codebase with very good use of OOP and multiple inheritance, and author (I was his intern) painstakingly taught me about inheritance and its good uses. He used Design and Evolution of C++ (!) as a bludgeon. It was 2006.
Feels like that time my physics PhD student girlfriend asked me "hey you're a programmer, right" and I was one until I discovered ROOT and suddenly I lost taste for life and anything related to Computers.
Sure, but I have also seen C code where random structs with function pointers are passed to god-knows-where, and I will take inheritance over that any time of the day.
I think that’s just what you’re used to. Since I switched from Java to Go 7 years ago, I don’t think I’ve missed inheritance a single time. I haven’t needed to model anything with inheritance once. There are definitely things I’ve missed from Java, but not inheritance.
A lot of people who only know inheritance and can't understand why a lot of us slag on it so much don't understand how inheritance conflates implementation and interface. Polymorphism based on interface is a fundamental tool of programming. The way inheritance also drags along an implementation turns out not to be, and to probably be more trouble than it's worth. There are other ways of bringing along implementation, including the basic function, and those work better.
When inheritance is your only tool for interface, I absolutely agree that it looks fundamental, but the fundamentalness is coming from the interface side. Once you separate out interface from implementation, it turns out I have little to no use for the implementation portion.
I have also been programming in Go for a long time now. I sketched out an inheritance system once for an exercise. It's doable, though it's a terrible pain in the ass to use. I've kept it in my back pocket in case it is ever the right solution to a problem even so... but it never has been. And that's not because of any irrational hate for the pattern itself. I've imported other foreign patterns sometimes; I've got a few sum types, even though Go isn't very good at it, because it was still the best solution, and I've got a couple of bits of code that are basically dynamically typed, again because it was the best solution, so I'm not against importing a foreign paradigm if it is the correct local solution. Inheritance just... isn't that useful. The other tools that are available are sufficient, and not just begrudgingly sufficient or "I'm insisting they're sufficient to win the argument even though I know they really aren't"... they really are sufficient. Functions are powerful things, as the functional programming community (it's right there in the name) well knows.
> I don't think inheritance is bad at all. It is very often the easiest way by far to model a problem.
I think the point of the article is that in some (very popular) languages, inheritance comes with a lot of baggage - precisely because classes in those languages support 3 different use cases. It's not saying that your usage is bad, but that your language didn't provide you with the best tool(s).
A lot of how people use classes can be solved via ADTs - which are much simpler to grok.
A lot of how people use classes can be solved via namespaces/modules, but not all languages have good support for them - so they use classes.
I have found that single inheritence can be useful but it is very restrictive.
More than once, I have found an inheritance hierarchy that made sense when first created no longer models the problem well. It becomes hard to change it at that point.
Frequently I find I really want to mix in cross cutting concerns across different hierarchies. This isn't really a surprise; most problems do not naturally decompose to only a single view of things.
I don't mind abstract base classes containing common functionality, so it's useful there, but mix ins would be better to be honest.
I have never really seen it work. To me it seems it can work if and only if you are doing serious waterfall projects, with a tightly bounded scope.
If you have to model your data exactly once I believe it can work. But if you are doing any kind of agile, or even somewhat flexible waterfall, you will find out that at some point none of your data models work.
Depends on how you use it, but in Java I prefer to use interfaces and no subclassing. I find classes with abstract methods hard to reason about, and much prefer to leverage Functions/lambdas where possible.