Live data from Hacker News

Inheritance was invented as a performance hack (2021)

catern.com

131–140 of 252 posts

Re: Inheritance was invented as a performance hack (2021)

#131
post #36

Earlier quoted context omitted.

> The bottom line is, no one ever really used inheritance that much anyway If you think that, you have no idea how much horrible code is out there. Especially in enterprise land, where deadlines are set by people who get paid by the hour. I once worked on a java project which had a method - call a method - call a method - call a method and so on. Usually, the calls were via some abstract interface with a single imple…

Yeah, I have seen things like you describe. But I have also seen the same code, copy-pasted a dozen times throughout a codebase and modified over years. That is a much worse situation; the links between the abstractions still exist without the inheritance, but now they are untraceable. At least with inheritance there are links between the methods and classes for you to follow. Without it, you've got to crawl the enti…

> OOP is easily the lesser of the two evils; without it, you're doomed to violate DRY in ways that will make your project unmaintainable.

Inheritance isn't the only way to avoid duplicating code. Composition works great - and it results in much more maintainable code. Rust, for example, doesn't have class based inheritance at all. And the principle of DRY is maintained in everything I've made in it. And everything I've read by others. Its composition all the way down, and it works great. Go is just the same.

If anything, I think if you've got a weak team it makes even more sense to stick to composition over inheritance. The reason is that composition is easier to read and reason about. You don't get "spooky action from a distance" when you use composition, since a struct is made up of exactly the list of fields you list. Nothing more, nothing less. There's no overridden methods and inherited fields to worry about.

Re: Inheritance was invented as a performance hack (2021)

#132
post #39

Earlier quoted context omitted.

It is a good idea because it's the most fundamental idea. You have two objects. A and B. How do you merge the two objects? A + B? The most straight forward way is inheritance. The idea is fundamental. The reason why it's not practical has more to do with human nature and the limitations of our capabilities in handling complexity then it has to do with the concept of inheritance itself. Literally think about it. How e…

> Literally think about it. How else do you merge two structs if not using inheritance? What? Using multiple inheritence? That's one of the worst ideas I've ever seen in all of computer science. You can't just glue two arbitrary classes together and expect their invariants to somehow hold true. Even if they do, what happens when both classes implement a method or field with the same name? Bugs. You get bugs. I've bee…

> Even if they do, what happens when both classes implement a method or field with the same name?

It's done in Java with interfaces with default implementations, and the world hasn't imploded. It just doesn't seem like that big of a problem.

Re: Inheritance was invented as a performance hack (2021)

#133
post #36

Earlier quoted context omitted.

> The bottom line is, no one ever really used inheritance that much anyway If you think that, you have no idea how much horrible code is out there. Especially in enterprise land, where deadlines are set by people who get paid by the hour. I once worked on a java project which had a method - call a method - call a method - call a method and so on. Usually, the calls were via some abstract interface with a single imple…

Yeah, I have seen things like you describe. But I have also seen the same code, copy-pasted a dozen times throughout a codebase and modified over years. That is a much worse situation; the links between the abstractions still exist without the inheritance, but now they are untraceable. At least with inheritance there are links between the methods and classes for you to follow. Without it, you've got to crawl the enti…

I think you have the consequences of AI exactly backwards. AI provides virtual headcount and will vastly increase the ability of small teams to manage sprawling codebases. LLM context lengths are already on the order of millions of tokens. It takes a human days of work to come to grips with a codebase an LLM can grok in two seconds.

The cost of working with code is much lower with LLMs than with humans and it's falling by an order of magnitude every year.

Re: Inheritance was invented as a performance hack (2021)

#134

Earlier quoted context omitted.

To me, inheritence makes sense if you view your codebase as actual "Objects" The reality is that a codebase is not that simple. Many things you create are not representable as realworld "objects" - to me, this is where is gets confusing to follow especially when the code gets bigger. I remember those OOP books (I cannot comment on modern OOP books) where the first few chaptors would use Shapes as an example. Where A…

I’m not on the cutting edge of gamedev, but I still believe that ECS is a solid pattern with lots of use cases.

Sounds like relational databases: Entities are IDs. Components are tables with an ID column.

Re: Inheritance was invented as a performance hack (2021)

#135
post #130
post #58

Earlier quoted context omitted.

I'd still generally prefer intrusive lists to be done via composition. I've seen plenty of intrusive lists where each item was a member of multiple lists at the same time - which is quite hard to do if you need to inherit from an intrusive list element superclass.

metoo, but how do you pull that off in C++? How do you get back from node to containing value? Multiple inheritance, possible but you'd have to jump some hoops to disambiguate since you're dealing with multiple copies of the same base class.

Composition. Sorry about the syntax - its been awhile since I wrote C++.

    class IntrusiveListNode { T* next, T* prev }

    class SomeObj {
        IntrusiveListNode list_foo;
        IntrusiveListNode list_bar;
    }

Re: Inheritance was invented as a performance hack (2021)

#136
post #2

Huh, I was always told that inheritance hurt performance as it requires additional address lookups. Thats why many game engines are moving away from it. I guess it could simplify the GC but modern garbage collectors have come a long way.

I was in the game industry when we originally transitioned from C to C++, and here's my recollection of the conversations at the time, more or less.

In C++, inheritance of data is efficient because the memory layout of base class members stays the same in different derived classes, so fields don't cost any more to access.

And construction is (relatively fast, compared to alternatives) because setting a single vtable pointer is faster than filling in a bunch of variable fields.

And non-virtual functions were fast because, again, static memory layouts and access and inlining.

Virtual functions were a bit slower, but ultimately that just raised the larger question of when and where a codebase was using function pointers more broadly - virtual functions were just one way of corralling that issue.

And the fact that there were idiomatic ways to use classes in C++ without dynamically allocating memory was crucial to selling game developers on the idea, too.

So at least from my time when this was happening, the general sense was that, of all the ways OO could be implemented, C++ style OO seemed to be by far the most performant, for the concerns of game developers in the late 90's / early 2000's.

I've been out of the industry for a while, so I haven't followed the subsequent conversations since too closely. But I do think, even when I was there, the actual reality of OO class hierarchies were starting to rear their ugly heads. Giant base classes are indeed drastically bad for caches, for example, because they do tend to produce giant, bloated data structures. And deep class hierarchies turn out to be highly sub-optimal, in a lot of cases, for information hiding and evolving code bases (especially for game code, which was one of my specialties). As a practical matter, as you evolve code, you don't get the benefits of information hiding that were advertised on the tin (hence the current boosting of composition over inheritance). I think you can better, smart discussions about those issues in this thread, so I won't cover them.

But that was a snapshot of those early experiences - the specific ways C++ implemented inheritance for performance reasons were definitely, originally, much of the draw to game programmers.

Re: Inheritance was invented as a performance hack (2021)

#137
post #130

Earlier quoted context omitted.

metoo, but how do you pull that off in C++? How do you get back from node to containing value? Multiple inheritance, possible but you'd have to jump some hoops to disambiguate since you're dealing with multiple copies of the same base class.

Composition. Sorry about the syntax - its been awhile since I wrote C++. class IntrusiveListNode { T* next, T* prev } class SomeObj { IntrusiveListNode list_foo; IntrusiveListNode list_bar; }

Ah, of course; templates and linking the full object.

Thanks for the update, my C++ is pretty rusty.

But it brings up another problem for me; when iterating a list like that, how do you know which of the links to follow? I get that you can do it manually step by step, but if you wanted to say write an iterator. Member pointers?

Re: Inheritance was invented as a performance hack (2021)

#138
post #39

Earlier quoted context omitted.

> Literally think about it. How else do you merge two structs if not using inheritance? What? Using multiple inheritence? That's one of the worst ideas I've ever seen in all of computer science. You can't just glue two arbitrary classes together and expect their invariants to somehow hold true. Even if they do, what happens when both classes implement a method or field with the same name? Bugs. You get bugs. I've bee…

> Even if they do, what happens when both classes implement a method or field with the same name? It's done in Java with interfaces with default implementations, and the world hasn't imploded. It just doesn't seem like that big of a problem.

> It just doesn't seem like that big of a problem.

It really, really depends on the codebase. There are absolute mammoth tire fire codebases out there - particularly in "enterprise code". These are often made up of insane hierarchies of classes which in practice do nothing but obscure where any of the actual logic lives for your program. AbstractFactoryBuilderImpl. Wild goose chases where you need some bizzaire and fragile incantation to actually create an object, because every class somehow references every other class. And you can't instantiate anything without instantiating everything else first.

If you haven't seen it in your career yet (or at all), you are lucky. But I promise you, hell is programmed by mediocre teams working in java.

Re: Inheritance was invented as a performance hack (2021)

#139

Earlier quoted context omitted.

Yeah, I have seen things like you describe. But I have also seen the same code, copy-pasted a dozen times throughout a codebase and modified over years. That is a much worse situation; the links between the abstractions still exist without the inheritance, but now they are untraceable. At least with inheritance there are links between the methods and classes for you to follow. Without it, you've got to crawl the enti…

I think you have the consequences of AI exactly backwards. AI provides virtual headcount and will vastly increase the ability of small teams to manage sprawling codebases. LLM context lengths are already on the order of millions of tokens. It takes a human days of work to come to grips with a codebase an LLM can grok in two seconds. The cost of working with code is much lower with LLMs than with humans and it's falli…

So if you've got a data object, defined in multiple places in a sprawling codebase, that you want to change, are you going to trust the LLM to find them all, and not miss a single one?

Re: Inheritance was invented as a performance hack (2021)

#140
post #88

Earlier quoted context omitted.

As they say about OOP, everything is somewhere else. The only part of inheritance I’ve ever found useful is allowing objects to conform to a certain interface so that they can fulfill a role needed by a generic function. I’ve always preferred the protocol approach or Rust’s traits for that over classicist inheritance though.

And Rust's traits can sort-of inherit from each other.

I'm fine with trait inheritance. (If you want to call it that - its maybe better to describe it as trait preconditions.)

I'm fine with it because trait inheritance doesn't increase code complexity in the same way C++ / Java class inheritance does. If you call foo.bar(), its usually pretty obvious which function is being called. And you only ever have to look in one place to see all the fields of a struct.

In C++, its common to have a class method say "blah = 5;" or something. Then you need to spend 5 minutes figuring out where "blah" is even defined in the class hierarchy. By the time you find it, you have 8 code windows open and you've forgotten what you were even trying to do. And thats to say nothing of all the weird and wonderful bits of code which might modify that field when you aren't looking. Ugh.

Post reply on HN