Live data from Hacker News

Inheritance was invented as a performance hack

catern.com

81–90 of 268 posts

Re: Inheritance was invented as a performance hack

#81
post #78

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…

> This problem is impossible to fix and it is a general problem - when overwriting a method, you can never be sure that semantics could break when the base class is changed. I'm not sure what's so special about overwriting methods here. There are many cases where semantics can break as a dependency changes. One example would be whether a callback is executed on the same thread (or event-loop tick) or in the backgroun…

Very good point actually.

If we cannot assume synchronous execution, then semantics can break exactly as you said. That a rather orthogonal problem from the inheritance one and my suggested solution is to make use of pure functional programming (hence purity can be assumed unless the method signature indicates that an effect might happen). Here is an example of how a potentially async Stack might look like:

    class Stack(...) extends Stack {
       def push(element) returns IO[nothing] = ...
       
       def pop() returns IO[element] = ...
    }
The IO would describe an action that can be ran at a later point, which means when the method has being called and returned, nothing has happened until you call `run(io)`.

That way you will be immediately aware of the behavior and adapt your Countstack as follows:

    class CountingStack(underlyingStack) extends Stack {
       override def push(element) returns IO[nothing] =
           underlyingStack.push(element).andThen(nothing => count += 1; return nothing)
       
       override def pop() returns element =
           underlyingStack.pop(element).andThen(element => count += 1; return element)
    }
That ensures that order of events is being kept and also that failures (e.g. a concurrent thread dies in the middle) are handled.

> Assuming that the Stack class specifies that all modifications will go through the push and pop methods

This is a severe restriction on how the Stack can be implemented then and it bears the risk of someone violating this specification by accident (think about the famous equals/hashCode specification in Java).

Re: Inheritance was invented as a performance hack

#82
post #33
post #21

Earlier quoted context omitted.

People care tons about their kids -> Working hard and creating value results in a larger inheritance for their kids -> Exploit biological desires to protect offspring to get yourself to be more productive?

"Working hard and creating value" and "biological desires" are multiple inheritance, which is outside the scope of this article.

Is this the diamond problem?

Re: Inheritance was invented as a performance hack

#83

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…

This is only a problem is the methods on Stack are virtual. If they are non-virtual, inheritance works like your composition example: inheriting from Base basically creates a Base member variable, except missing methods can be automatically forwarded to the Base member. This saves you from having to explicitly wrap all the methods of Stack in CountingStack.

Virtual should be used sparingly.

Re: Inheritance was invented as a performance hack

#84
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…

This pattern is also called the template method pattern, I believe:

https://refactoring.guru/design-patterns/template-method

Re: Inheritance was invented as a performance hack

#85

Pretty off topic comment, but I read the title as "inheriting money is a way avoid being a high performer", which happens to be true, although completely irrelevant to the actual article. ;)

I read it similarly as "inheriting money".

And it's true that inheritance IS a performance hack--not for the children, but for the parents. Inheritance incentivizes parents to accumulate wealth not just for one lifetime but for multiple lifetimes. (Granted it may paradoxically have the opposite effect on the children as you mention.)

Here's Milton Friedman on the matter: https://www.youtube.com/watch?v=km9OCw3f5w4

Re: Inheritance was invented as a performance hack

#87

tl;dr: > Simula created inheritance instead of using composition because it allowed their garbage collector to be simpler. In C++, inheritance (and other OO languages I assume) is implemented as a composition and when multiple inheritance of the same class happens then the members of the twice parent is inherited twice unless the virtual keyword is used. ( in other words, if B : A, A, C then sizeof B = A + A + C + B'…

Doesn’t Parent parent = Child() work because Parent’s constructor is run by implicitly casting ref-to-Child to ref-to-Parent?

Re: Inheritance was invented as a performance hack

#88

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…

An example I often link to is http://okmij.org/ftp/Computation/Subtyping which uses a similarly simple example (bags and sets) to show that supposedly "internal" changes can still break subclasses.

Re: Inheritance was invented as a performance hack

#89

I'm a little confused. Inheritance, types and all that stuff are just language concepts right? Simula may have been one of the first to implement inheritance as a means to an end, but how could they have "invented" inheritance? I'm sure the idea of inheritance was already there in language proofs. [I might be really really wrong here]

Theory usually comes after practice. People create something that works, then theorists formalizes it into a well defined concept.

I hold the view that programming patterns were invented as solutions to technical problems. It was then later that some theoretical "usefulness" or "elegance" was attached to them.

One should know the technical benefits and drawbacks of programming patterns before applying them. Just because some language or environment or majority of programmers promotes it, doesn't mean that its ok to apply it. Without knowing the technical reason for applying a pattern is just cargo cult programming.

Re: Inheritance was invented as a performance hack

#90

I think discussions of OOP and inheritance often miss the influence of Knowledge Representation on OOP: I’m not entirely clear of the history myself, but I’ve gotten the impression that knowledge representation research (things like frame systems) was a semi-independent influence on the design of OO systems

> discussions of OOP and inheritance often miss the influence of Knowledge Representation on OOP

SICP doesn't. :) Which is why it's such a great book, of course.

Post reply on HN