Live data from Hacker News

Inheritance was invented as a performance hack (2021)

catern.com

211–220 of 252 posts

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

#211

I think a lot of the arguments against inheritance come from C++'s peculiar implementation of it, which it clearly, ah, inherited from Simula. Slicing, ambiguous diamond inheritance, stuff like that are C++ problems, not inheritance problems. This isn't to say inheritance isn't problematic, but when you're making a properly substitutable sub- type of something, it's hard to beat.

What are examples of better inheritance?

For the specific problems I mentioned like slicing, literally anything else that actually abstracts the memory layout.

For OOP in general, I'd say anything with a metaobject protocol for starters, like Smalltalk, Lisp (via CLOS), Python, Perl (via Moose). All but the first support multiple inheritance, but also have well-defined method resolution orders. Multiple inheritance might still lead frequently to nasty spaghetti code even in those languages, but it will still be predictable.

CLOS and Dylan have multiple dispatch, which is just all kinds of awesome, but alas is destined to remain forever niche.

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

#212

Earlier quoted context omitted.

I'm not sold on the evidence of much in the way of programming language features from the "object oriented" era. They were pushed by cultish types with little evidence. There was this assertion that all these things were wonderful and would reduce effort and therefore they must be good and we all must use them. We got object oriented everything including object oriented CPUs, object oriented relational databases, obj…

If encapsulation wasn't useful, we wouldn't write microservices. If abstraction wasn't useful, we wouldn't use containers.

That's not evidence though even if we take it as true. You can of course make layers of abstraction or encapsulation without "object oriented" languages.

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

#213

I always thought this was common knowledge. I guess it isn’t. The only reason inheritance continues to be around is social convention. It’s how programmers are taught to program in school and there is an entire generation of people who cannot imagine programming without it. Aside from common social practice inheritance is now largely a net negative that has long outlived its usefulness. Yes, I understand people will…

Or because there are some situations where inheritance is useful. There was a reason Simula, Smalltalk, C++, Common Lisp (CLOS), Java, OCaml, Ruby, etc. implemented OOP. That's a lot of different languages. The program designers found it to be a useful abstraction and so did the language users. There's no reason to be dogmatic about programming abstractions. Just because OOP became dogma for a while and got abused do…

> There's no reason to be dogmatic

I absolutely disagree. Some things in programming exist to bring products to market, but many things in programming only exist to bring programmers to market. That is a terrible and striking difference that results ultimately from an absence of ethics. Actions/decisions that exist only to discard ethical considerations serve only two objectives: 1) normalization of lower competence, 2) narcissism. It does not matter which of those two objectives are served, because the conclusions are the same either way.

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

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

"But there's a reason the crowd is moving against inheritance" Yep: it requires skills that aren't taught in schools or exercised in big companies organized around microservices. We've gone back to a world where most developers are code monkeys, converting high-level design documents into low-level design documents into code. That isn't what OOP is good for: OOP is good for evolving maintainable, understandable, test…

> That isn't what OOP is good for: OOP is good for evolving maintainable, understandable, testable, expressive code over time.

Whoa that’s quite the claim. Most large projects built heavily on OO principles I’ve seen or worked on have become an absolute unmaintainable mess over time, with spider webs of classes referencing classes. To say nothing of DI, factoryfactories and all the rest.

I believe you might have had some good experiences here. But I’m jealous, and my career doesn’t paint the same rosy picture from the OO projects I’ve seen.

I believe most heavily OO projects could be written in about 1/3 as many lines if the developers used an imperative / dataflow oriented design instead. And I’m not just saying that - I’ve seen ports and rewrites which have born out around that ratio. (And yes, the result is plenty maintainable).

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

#215

Earlier quoted context omitted.

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…

That is probably because you identify with the Rust tribe. Anything that Rust has is good while things in other languages have seem less good. This is fine, use the innate tribe affinity energy to get better at Rust.

Thanks for the diagnosis but no. I’ve had these opinions for years - since long before rust came along. If we had this conversation a decade ago, I might have made the same argument on the back of Java’s interfaces or obj-c’s protocols - which are both more or less the same concept.

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

#216

Earlier quoted context omitted.

Although Java/C# make you put functions in a class, you aren't compelled to think of a class as a "noun". Just call it "Utils" or something like that. A class is just a thing that you can put functions and / or data in. Use that however you want.

if anything, in C#, you can import the entire class as `using static MyFunctions;` and make such functions top-level. Well, usually you write an extension method instead since most functions act on some form of data but you get the idea. (can also be imported globally with 'global using static ..' in a usings file)

Yeah, the problem with OO isn’t really in the languages. The problem is in the community, and what people consider “best practice”. C#, Java and C++ are all arguably multi-paradigm languages. They give you a lot of flexibility in how you structure your code. C# and C++ support value types. Modern Java has great support for a lot of FP concepts too.

So I agree with you. You can write good C# if you want to. The problem is that a lot of people - for some strange reason - actively choose to make their programs heavily OOP.

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

#217
post #80

Earlier quoted context omitted.

> But assume there are 3 objects with distinct properties... Why would we assume that? If the objects are entirely distinct, why are you combining them together into one class at all? That doesn't make any sense. Let distinct types be distinct. Let consumers of those types combine them however they like. > But fundamentally there's no OTHER SIMPLER way to merge two objects without resorting to complex nesting. [...]…

>Why would we assume that? If the objects are entirely distinct, why are you combining them together into one class at all? That doesn't make any sense. Let distinct types be distinct. Let consumers of those types combine them however they like. Human = torso, legs, arms. Three distinct objects combine into one thing. A human by definition is the union of these things. It's fundamental. It's just your bias is trying…

> Human = torso, legs, arms. Three distinct objects combine into one thing. A human by definition is the union of these things. It's fundamental. It's just your bias is trying to see it as something else.

No, it’s not. If I put a torso, legs and arms (and perhaps a head) on a table, I don’t get a human being. I’d say a human composes all of those things (and more!). But a human doesn’t inherit from them. For example, each leg can kick(). But you can’t inherit from two legs! And if you did, which leg is the one that kicks when you call the function? Much better to have human class which contains two legs. Then human can have a kick(RIGHT_LEG) function which delegates its behaviour to right_leg.kick().

There’s lots more ways composition helps us model this. Let’s say we want to model blood temperature, which is tracked in every limb separately. Composition makes it more straightforward to have different behaviour (& state) in the Body class for blood temperature than in any of the limbs. (Eg maybe the blood temperature is the average of all limbs temperature. That is more straightforward to implement with composition.)

> inheritance minimizes code copying. It reuses code in the most efficient way possible.

On the surface, I agree with this claim. But it’s funny - programs which make heavy use of OO always seem unnecessary verbose. I wonder why that is? I’m thinking of Java where it’s common to see utility classes that just have 1 or 2 fields take up 100+ lines of code, due to class boilerplate, custom hashCode, toString and isEqual methods and all the rest.

But in any case, as you say, we aren’t just trying to optimise for the fewest lines of code. We’re trying to optimize for how easy something is to read, write and maintain. Adding code to increase simplicity is often worth it. Inheritance increases complexity because it adds a layer of hidden control flow. When I’m reading a program, I need to do a lot of work to figure out if foo.bar() is calling a function in one of the base classes or in the derived class. As you say, humans don’t deal with that kind of complexity well. In general, explicit is better than implicit - this.leg.kick() is more explicit than this.kick() when kick() exists somewhere in one (or more?) of the base classes.

Also let’s say I have 3 classes A, B extends A and C extends A. If there’s a bug in B that involves something in the base class A, fixing that bug may break implicit invariants in C. This kind of “spooky action at a distance” is horrible. Ironically, it violates the principle of encapsulation that OO claims as one of its core principles. I find this kind of problem is rarer in compositional systems. And when it happens, it’s usually much more straightforward to debug and fix. The reason is because classes are all self contained. You don’t have partially-specified base classes that only kinda sorta maintain their invariants. And derived classes don’t implicitly include their base class’s behaviour. As a result, there’s less implicit entanglement. B and C can much more easily change how they wrap A’s behaviour.

At the end of the day, I think we more or less agree that inheritance makes code harder to reason about. I don’t write code to express a pure conceptual representation of the world. (And neither should you!). I write code to get stuff done. If inheritance makes it harder for humans to be productive with our software, then that’s reason enough to abandon it.

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

#218

Earlier quoted context omitted.

if anything, in C#, you can import the entire class as `using static MyFunctions;` and make such functions top-level. Well, usually you write an extension method instead since most functions act on some form of data but you get the idea. (can also be imported globally with 'global using static ..' in a usings file)

Yeah, the problem with OO isn’t really in the languages. The problem is in the community, and what people consider “best practice”. C#, Java and C++ are all arguably multi-paradigm languages. They give you a lot of flexibility in how you structure your code. C# and C++ support value types. Modern Java has great support for a lot of FP concepts too. So I agree with you. You can write good C# if you want to. The proble…

Maybe we need to tease "community" apart from language. Let's have Java / C# "A" people (who need at least 10 levels of inheritance, gotta use DI, insist on every character of SOLID (and actually remember and care about the Liskov substitution principle - and insist that it wasn't chosen simply because it starts with "L" and makes the acronym sound better) and have never written any code that added any value - only frameworks. Then we can have Java / C# "B" people that care about allocations, hate DI, avoid inheritance, know when they are messing up cache line hits and even feel slightly bad a about using generics.

Something like that, pick your tribe or, even better, be an individual and do whatever (TF) you want.

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

#219

Earlier quoted context omitted.

Here's my take on implementing this in rust. I made a trait for fetching metadata, that can be implemented by Image, Video, Document, etc: trait MetadataSource { fn fetch_metadata(&self) -> Metadata; } impl MetadataSource for Image { ... } impl MetadataSource for Video { ... } impl MetadataSource for Document { ... } And a separate object which stores an image / video / document alongside its cached metadata: struct…

When you call myImageInstance.fetchMetadata, what does it do? I don't know rust, so it's not clear to me how the value gets cached.

In this example, ThingWithMetadata does the caching. image.fetch_metadata fetches the image and returns it. It’s up to the caller (in ThingWithMetadata) to cache the returned value.

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

#220
post #51

Earlier quoted context omitted.

> I don't think Inheritance is always bad - sometimes it's a useful tool. I can only think of one or two instances where I've really been convinced that inheritance is the right tool. The only one that springs to mind is a View hierarchy in UI libraries. But even then, I notice React (& friends) have all moved away from this approach. Modern web development usually makes components be functions. (And yes, javascript…

> And yes, javascript supports many kinds of inheritance Funny you mention it, since JavaScript has absolutely no concept of contracts, which is one of the most important side-effects of inheritance. Especially not at compile time, but even at runtime you can compose objects willy-nilly, pass them anywhere, and the only way to test if they adhere to some kind of trait is calling a method and hoping for the best. At l…

Yes. JavaScript is an incredibly dynamic language. If you don’t like that, don’t use it.
Post reply on HN