Live data from Hacker News

Why general inheritance is flawed and how to finally fix it

minborgsjavapot.blogspot.com

31–40 of 104 posts

Re: Why general inheritance is flawed and how to finally fix it

#31
The author is onto something but I’m afraid it’s not explained very well. I think he’s mostly right though.

While reading it I was reminded of a design/implementation style I’ve run across several times over the years which is to find an existing class that does something similar to what you want. Then, subclass it and override methods until you get the behavior you want. And you’re done!

This leads directly to the Fragile Base Class problem. I think it also violates the Open/Closed principle. When subclassing occurs across components that are released independently (e.g., a library and an application), it either leads to continual breakage at each release, or ossification of the library. The latter happened to Java’s Swing. It got to the point where it was difficult to fix any bugs, because any “fix” would end up breaking some subclass that relied on the old behavior.

(See also Hyrum’s Law, which is more general than subclassing & inheritance.)

Re: Why general inheritance is flawed and how to finally fix it

#32

I think that composition is absolutely better than inheritance except for one thing: boilerplate. The issue is that boilerplate is kind of important. You don't want to litter your code with "f150.ford.car.vehicle.object.move(50, 50)". You can and should re-implement "move" so that you only have to call "f150.move(50, 50)", but that still requires boilerplate, just in the "F150" class. Often you have class containing…

That's not general [implementation] inheritance, it's just delegation. The problematic, non-compositional feature of implementation inheritance is something known as open recursion, viz. the fact that every call to an overridden method like .move(...) - importantly, even a call that's merely a private implementation detail of some code in the base class - goes through an implied dispatch step that introduces a dependency on the actual derived class instance that the base-class method is being called on. This creates the well-known "fragile base class" problem since method calls to these possibly-overridden methods are relying on fragile, unstated invariants that might be broken in the derived classes, or altered in future versions of the base class.

Re: Why general inheritance is flawed and how to finally fix it

#33
post #17
post #7

Earlier quoted context omitted.

For the same reason, I'm not so absolutist about DRY. Having the most elegant codebase also often means the codebase that's hardest to work on, and it's often better to clean things up afterwards once you know how things will be structured.

Recently (last month basically), i rewrote my code (i'm leaving soon and i want my coworkers/successors to have success improving on what i've done). I followed every principle of good code, except one, DRY. I tried to make generic parts to connectors, because they do have similarities. But this is a work of at least a year, and the price to make it generic was increasingly more complex configuration files (Just the…

Yeah, I had a few connectors (API clients to different APIs with some business logic wrappers to handle low level stuff) and decided that they should share code with a generic connector interface, and then when one of them changed it was pretty painful untangling it. There is a tradeoff between getting stuff done and abstraction engineering, and there are costs to premature abstraction engineering.

Re: Why general inheritance is flawed and how to finally fix it

#34
https://lwn.net/Articles/548560/

I really enjoyed the article above, which I read many years ago (before Rust 1.0!) which discusses how Golang and Rust handle polymorphism and code-reuse without classic object inheritance. My current thinking is that software objects are a general-purpose tool, but classic object inheritance should rarely be used as it is a solution to a narrow problem—classes should be "final" by default, and if not the inheritance pattern should be completely designed up front.

Java had the misfortune to be designed at a time when OOP was the new craze and the design decision to force all code into an object hierarchy has not held up well. I'd rather use languages designed either before or after Java, where you can use objects when they are appropriate and ignore them when they aren't.

Re: Why general inheritance is flawed and how to finally fix it

#35
post #22

Earlier quoted context omitted.

It might be more productive if you were to outright disagree with the statement instead of simply noting a claim that isn't strongly substantiated. If you have experiences that demonstrate to you that this claim is weak I'm sure everyone else would be interested in them (I know I would be!).

"what may be asserted without evidence, may be dismissed without evidence"

Where is your evidence for that claim? Seems like I should dismiss it out of hand.

Re: Why general inheritance is flawed and how to finally fix it

#36
Inheritance is flawed, in Java, mainly because it is the only organizing principle offered, so gets shoehorned into all kinds of problems where it is a poor fit.

Inheritance is just the right thing once in a while, but Java coders are obliged to apply it well beyond its useful range.

Re: Why general inheritance is flawed and how to finally fix it

#37
post #34

https://lwn.net/Articles/548560/ I really enjoyed the article above, which I read many years ago (before Rust 1.0!) which discusses how Golang and Rust handle polymorphism and code-reuse without classic object inheritance. My current thinking is that software objects are a general-purpose tool, but classic object inheritance should rarely be used as it is a solution to a narrow problem—classes should be "final" by de…

Arguably, subtyping in am OO language should either be signatures/interfaces only, or you should go full blown multiple inheritance for everything, as with the Fortress language.

Re: Why general inheritance is flawed and how to finally fix it

#38
post #3

Re: using composition In the past, it was feared that this would lead to reduced performance but this is simply not the case. Great to see the strong evidence here /s

Language Design: Let's start with the admission that there's a lot of cargo culting in language design. Evidence is hard to come by and the best evidence is other languages that succeed with different choices. I remember the flame wars about how multiple inheritance would cause a language to fall apart. When will languages adopt the idea that encapsulation is not sacrosant, as the theoretical issue about the backdoor…

> Language Design: Let's start with the admission that there's a lot of cargo culting in language design. Evidence is hard to come by and the best evidence is other languages that succeed with different choices.

You are going to get a lot of false positives using success as a metric for good language design.

I cannot think of a single popular language, other than Python, in the last 40 years that did not have huge companies with sizable marketing budgets behind them.

Programming languages do not succeed based on merit. They may fail based on lack of it.

Re: Why general inheritance is flawed and how to finally fix it

#39
Fantastic article!

Object oriented programming gets a horrible wrap on the basis of inheritance alone, and it's no wonder. Outside of limited domains, such as GUI programming, object inheritance makes little sense. Computer science students are right to question their introductory classes on inheritance when they teach contrived examples of dogs barking and cats meowing as an example of Mammal.makeSound() inheritance.

It's almost as if we're shoehorning in a code dispatch framework as a major language feature, except that framework sucks and we're stuck building with it. The best strategy working in languages with inheritance is to avoid it.

Duck typing or traits are better ways to represent polymorphic behaviors. We've known this for over a decade now.

Here's hoping that no new languages come with object inheritance as a concept. It's deader than NULL and shouldn't be resurrected.

Re: Why general inheritance is flawed and how to finally fix it

#40
post #34

https://lwn.net/Articles/548560/ I really enjoyed the article above, which I read many years ago (before Rust 1.0!) which discusses how Golang and Rust handle polymorphism and code-reuse without classic object inheritance. My current thinking is that software objects are a general-purpose tool, but classic object inheritance should rarely be used as it is a solution to a narrow problem—classes should be "final" by de…

I mostly agree, but there's one place where it does make a lot of sense to keep the hierarchy open: exceptions. Ability raise a specific error and catch it in a generic handler is very useful.
Post reply on HN