I don’t think the “X is terrible” rhetorical device serves to really tell us anything about X. I get the idea of a flashy header, it’ll get more reads, generate more discussion, etc.
I think it’s more useful to focus on the tradeoffs inherent in using a tool.
Inheritance gives us a way to treat objects polymorphically and enforces a heirarchy of specialization on those objects.
The tradeoffs for this behaviour are:
any further extension relies on changing parents or using interfaces and composition.
by contrast interfaces and composition can achieve the same behaviour without relying on some external pattern.
That doesn’t make it a useless pattern, it just makes it useful in a few limited cases.
With exceptions it allows us to create ‘families’ of exceptions which are useful for debugging. This would be pretty tricky to pull off with composition or interfaces since the programmer would have to implicitly encode that heirarchy and ensure they’ve extended correctly.
In ruby it (for better or for worse) allows us to add behaviours to all objects or all objects of a given class.
It would be pretty difficult to implement an OO language without single inheritance, and for code that, once stable, is rarely modified the maintenance costs can be amortized over millions of person-hours.
No tool or technique is universally good, but I think avoiding a tool at all costs also prevents us from learning its strengths and weaknesses.
I’d argue that Go is a successful OO (or maybe OO-lite) language without inheritance. It has struct embedding, which forwards method calls from a type to one of its embedded subtypes, but no concept of a abstract base class and super keyword.
I think rather than talking about if X is terrible or not, the discussion should be around if the feature is important enough to be included as a concrete concept in a language. For example, you can implement inheritance yourself with a record and some functions, so is it important enough to have a language construct that, more or less, creates that struct for you.
I’m a big fan of having less, for most languages under debate, that ship has long since sailed though.
Sure, but these discussions are never about if it will be removed from a language of or if developers will stop using it, it’s just about thinking about the value of things. Every once in a while a language like Go gets momentum and people have a chance to reset things a little bit (regardless of if one likes Go or not. it’s a popular language that dials back some existing popular features.