Live data from Hacker News

Inheritance was invented as a performance hack

catern.com

51–60 of 268 posts

Re: Inheritance was invented as a performance hack

#51
post #4

Fine. But obviously it caught on for other reasons, like code reuse and an intuitive mental model. The HN appetite for posts ragging on inheritance will never be sated.

My roots are in OO but for the life of me I could never figure out why people found inheritance intuitive beyond some automatic delegation (like Go’s struct embedding). I certainly don’t miss the guesswork of trying to figure out which class’s virtual method is being executed out of the dozen in the hierarchy (especially when one virtual method is calling other virtual methods).

Re: Inheritance was invented as a performance hack

#52
post #31

Earlier quoted context omitted.

It’s a misuse because (if you really are only using it for code reuse) it’s creating an essential relationship between different objects that is actually incidental. A list containing two different subclasses of your avoiding-copy-paste base class is now most likely a logical error.

You could just as well argue that there should never be any code reuse ever, code reuse always couples objects, code reuse should never be done if the two different parts doesn't have the same purpose. So the same rules for all code reuse also applies for inheritance, if you follow them then there are no problems using inheritance. If you have a set of data kinds which all needs to implement the same fields that has…

I don’t think it’s true that reuse means tight coupling. With composition you can swap out the composed object at runtime and as far as compile time coupling is concerned you can embed an interface to decouple the outer object from the inner object.

Re: Inheritance was invented as a performance hack

#53

Earlier quoted context omitted.

how is that different from a list containing 2 implementations of an interface?

There is no state to track. If there is, 99% composition has worked out way better for me in the long run since I don't have this really strong coupling between two objects.

So you don't have a need for code reuse then since you don't have many types with the same base structure, just say that instead of saying that it is bad.

Re: Inheritance was invented as a performance hack

#54

Earlier quoted context omitted.

You could just as well argue that there should never be any code reuse ever, code reuse always couples objects, code reuse should never be done if the two different parts doesn't have the same purpose. So the same rules for all code reuse also applies for inheritance, if you follow them then there are no problems using inheritance. If you have a set of data kinds which all needs to implement the same fields that has…

I don’t think it’s true that reuse means tight coupling. With composition you can swap out the composed object at runtime and as far as compile time coupling is concerned you can embed an interface to decouple the outer object from the inner object.

All code reuse creates coupling on some level. Creating more abstractions in between reduces coupling but creates code bloat. There is a trade off.

For example, if you call the same function from many locations those locations are now coupled since if you change the function you change all of those locations behaviour. Many times that is desirable, in which case it is good coupling. The exact same rule applies to inheritance.

Re: Inheritance was invented as a performance hack

#55
post #4

Fine. But obviously it caught on for other reasons, like code reuse and an intuitive mental model. The HN appetite for posts ragging on inheritance will never be sated.

My roots are in OO but for the life of me I could never figure out why people found inheritance intuitive beyond some automatic delegation (like Go’s struct embedding). I certainly don’t miss the guesswork of trying to figure out which class’s virtual method is being executed out of the dozen in the hierarchy (especially when one virtual method is calling other virtual methods).

Because some people understand "is a" better than "has a".

Re: Inheritance was invented as a performance hack

#56
post #34

Earlier quoted context omitted.

In your view, how is "interfaces with default implementations" different from "inheritance for code reuse"? At a minimum it looks like a virtual function with a default implementation in the base class. If a derived class doesn't override it, isn't that code reuse?

Because interfaces don’t confer a relationship between implementations, only that they have some common method signatures.

> Because interfaces don’t confer a relationship between implementations

Having the interface implement functions does exactly that, so your point only applies for interfaces without implementations.

Re: Inheritance was invented as a performance hack

#57
post #4

Fine. But obviously it caught on for other reasons, like code reuse and an intuitive mental model. The HN appetite for posts ragging on inheritance will never be sated.

"Please don't sneer, including at the rest of the community."

https://news.ycombinator.com/newsguidelines.html

Re: Inheritance was invented as a performance hack

#58
post #49

After reading all the comments of many confused and curious, here is when inheritance is bad and why so _in the absence of any performance considerations_. First, inheritance from an interface/trait is totally okay. The problem is class inheritance, meaning implementation inheritance. There are two cases: 1) you inherit from a class and only add methods but don't overwrite anything. This is the good case, you can do…

There are lots of bad uses of implementation inheritance, but it's not all bad. One pattern I use a lot is the "just these 5 missing methods". The base class might be complicated and large, with a lot of logic driving the process, but it needs to have 5 specific functions that it calls. One way is to have that big base class have almost all the logic and then 5 abstract methods and expect a subclass to implement thos…

I think for the usecase you mention, there is a different solution that I personally prefer.

Optimally, if your language supports it, just define an interface with these 5 methods and then define extension methods that work on any type that implements the interface. The reason why this works is that all the other functions are usually helper functions / convenience functions and they only need the other 5 functions to work, so no need to access any inner/private properties.

That is by far the most lightweight solution, and it works even for 3rd-party libraries where you can't control the types.

If your language does not have extension methods, then you can still use composition just like in the example I gave and delegate to the base class. That is a bit more code to write (because you have to delegate to the non-5 methods if you language doesn't automate that for you, some do) but I find it cleaner than hoping that no one overwrites any non-5 method.

But yeah, essentially what you are saying here is to ask people to follow the rule I gave by convention - depending on that context that might work as well.

Re: Inheritance was invented as a performance hack

#59

After reading all the comments of many confused and curious, here is when inheritance is bad and why so _in the absence of any performance considerations_. First, inheritance from an interface/trait is totally okay. The problem is class inheritance, meaning implementation inheritance. There are two cases: 1) you inherit from a class and only add methods but don't overwrite anything. This is the good case, you can do…

Why create virtual methods in a class if you have no intention of it being a parent class? And if you intend for it to be a parent class you can design it so that these things aren't an issue.

Re: Inheritance was invented as a performance hack

#60

After reading all the comments of many confused and curious, here is when inheritance is bad and why so _in the absence of any performance considerations_. First, inheritance from an interface/trait is totally okay. The problem is class inheritance, meaning implementation inheritance. There are two cases: 1) you inherit from a class and only add methods but don't overwrite anything. This is the good case, you can do…

Excellent example. Let me point out that Go's approach to inheritance ("embedding") doesn't suffer from the problem you illustrated. A method on the embedded type can't call a method on the type into which it is embedded. Go's approach to inheritance is a big productivity win, and it's easy to understand
Post reply on HN