Live data from Hacker News

If Inheritance is so bad, why does everyone use it?

buttondown.email

371–380 of 389 posts

Re: If Inheritance is so bad, why does everyone use it?

#371

There is no valid use case I've ever seen where inheritance was better than composition (that does not mean a use case does not exist, but evidence is mounting against it). I would say it's used because every language made a poor decision by building that in as the way to encapsulate reusable logic. i.e., a mistake. Some APIs may expose themselves as requiring you extend a base class, and in that case you might as we…

I have just the one use case: to escape out of framework/annotation hell.

Say I have a well-designed, self-contained BusinessService class which is perfectly unit-testable.

Then someone comes along and sprinkles some @Magic bullshit on it. Now its true behaviour won't be exercised in plain junit - you need custom test runners with class-path scanning and late-binding configuration ("The gorilla holding the banana and the rest of the jungle" in Joe Armstrong speak).

If you want to reclaim your unit-testable class, you can divide it into two: SpringBusinessService extends BusinessService. Move all the Spring dependencies out of the latter into the former.

Now you get the best of both worlds - clean, unit-testable logic, and a service that Spring can obfuscate with middleware to produce 200-line-long stacktraces after a lengthy startup.

Re: If Inheritance is so bad, why does everyone use it?

#372

Earlier quoted context omitted.

> Composition implies a level of complexity How?

If I combine A and B to make C, I have more than A and B. Now I have A and B and C and the relationship of A to C and B to C. Composition usually creates complexity. Interfaces (via aspects, aspects, traits, whatever) tend to simplify, when the complexity is quantitatively extensive enough to outweigh the cost of the interface complexity creation + the complexity saved by using the interface. At least, that's how I t…

Why are you making this distinction between composition and interfaces? Just because you're using interfaces does not mean you aren't doing composition.

> Interfaces (via aspects, aspects, traits, whatever) tend to simplify, when the complexity is quantitatively extensive enough to outweigh the cost of the interface complexity creation + the complexity saved by using the interface.

That sentence is more complicated than anything that has been done with composition.

Re: If Inheritance is so bad, why does everyone use it?

#373
In my mind, the more generic rule underneath these rules is you want to be able to comprehend what a unit is doing without jumping between a massive number or files or contexts. Inheritance hierarchies with shared state and overrides means you need to understand multiple files and their interactions vs interfaces and composition tend to allow for fairly understandable units with clear interactions.

The big problem these deep inheritance hierarchies cause is mediocre programmers often think they're writing good code (often high focus on maximal reuse) but the interfaces and clarity are terrible.

Re: If Inheritance is so bad, why does everyone use it?

#374
I don't think that inheritance is bad per se. AbstractWindowButtonManagerFactory type of inheritance is bad. I think the reason is that people are not just good at constructing hierarchical relationships between abstract concepts. And once you construct such an elaborate hierarchy, it becomes very hard to correct things after the fact. So you end up with a mess as people add more functionality on top of an already ill-conceived structure.

Re: If Inheritance is so bad, why does everyone use it?

#375

I feel people don't understand what inheritance and (object orientation in general) is useful for, misuse it, and then it gets a bad reputation. It's not about making nice hierarchies of Cars, Fruits, and Ovals. For me the main point is (runtime) polymorphism. E.g. you have a function that takes a general type, and you can pass multiple specific types and it will do the right thing. And if you want to avoid huge if-e…

> you have a function that takes a general type, and you can pass multiple specific types and it will do the right thing What does this have to do with inheritance? This is just a generic function. > And if you want to avoid huge if-else statements, you should put the code for the special cases in the classes, not in each function that operates on them This doesn't sound any different from how people usually talk abo…

> > you have a function that takes a general type, and you can pass multiple specific types and it will do the right thing > > What does this have to do with inheritance? This is just a generic function.

It's a generic function with compile-time compatibility checks.

Re: If Inheritance is so bad, why does everyone use it?

#376

Earlier quoted context omitted.

Polymorphism is doable in plain old C with lookup tables and function pointers. If that is the only benefit, what is the point of creating a language where everything is an object?

> what is the point of creating a language where everything is an object? I think that's the ultimate culprit in everyone hating inheritance. If it weren't for Java, I think we'd all have a healthier view of OO in general. I learned OO with C++ (pre C++-11), and now I work at a Java shop, but I'm luck that I get to write R&D code in whatever I need to, and I spend most of my time in Python. In C++ and Python, you get…

> If it weren't for Java, I think we'd all have a healthier view of OO in general. > > I learned OO with C++ (pre C++-11), and now I work at a Java shop, but I'm luck that I get to write R&D code in whatever I need to, and I spend most of my time in Python. > > In C++ and Python, you get to pick the best tool for the job. If I just need a simple function, I use it. If I need run-time polymorphism, I can use it. If I need duck-typing I can do it (in Python).

Those first two you can do in (modern) Java. The third is a mess to be avoided at all costs. Interfaces and lambdas will cover most reasonable use cases for polymorphism.

Re: If Inheritance is so bad, why does everyone use it?

#377

Inheritance is really just a public interface, a private interface and automatic delegation of those interfaces to the base class. The problems with inheritance are: - people shove code in the base class to dedup it without thinking about design - people add public and protected methods without thinking about interface design - the names of the base class and the public and protected interfaces are exactly the same t…

> If base classes were only allowed to be used in inheritance and couldn't be parameters, generics, etc then that would force users to create base classes and public interfaces in pairs and would decouple their names and by writing the public interface down as its own thing developers would be more likely to focus on that design. I agree and like this principle, however, but what would be the difference between the b…

TIL that in Python you cannot use a mixin class to provide implementation for an abstract base class that defines the interface.

In other words, in the inheritance tree, the class providing the common implementation must sit between the interface class and the concrete classes.

Re: If Inheritance is so bad, why does everyone use it?

#378

Earlier quoted context omitted.

Well, it does work well for the engine part of game engines, and graphics related code in particular as the GP says - it's just gameplay code where OO falls a bit flat.

Not really, the data oriented design movement in games programming that eschews OOP is driven by performance concerns of traditional OOP code on areas like rendering. As a graphics programmer for many years I can also say that OOP is not really a good fit design wise for modern rendering engines, it mostly just gets in the way.

I only really know of Bevy that uses ECS for the rendering backend, but iirc even that doesn't really use entities and components, but rather its resource system, such that rendering commands are stored in the ECS "world" but as globally unique resources, rather than entities and components. But, my knowledge doesn't extend to AAA engines, perhaps things are done more extensively there.

Re: If Inheritance is so bad, why does everyone use it?

#379

Earlier quoted context omitted.

Interesting articles! I think the first part of the first article immediately introduces an anti-pattern - forcing the user to make an instance of a class just to be able to call a pure function. It's just unnecessary noise, either make them static methods, group them in an object literal, or import the module as a namespace. Adding the "pattern" as a mutable public field is a bit sketchy, and would make it show up i…

> "yeah I have a User, but I don't know if it's a valid User". This, imo, is one of the big reasons people so easily dismiss OOP. They put whatever data _they think they probably need_ in an object using setters/builders/what have you. This leads to abstractions of data that don't accurately reflect state. They will then let an external entity (service or whatever pattern) manipulate this data. At this point people m…

In psychology, there is an idea of "locus of control".

I think OOP done well and applied in suitable scenarios results in entities that have internal locus of control; it's mutations of state are internally managed.

OOP done poorly has external locus of control where some external "service" or "util" or "helper" manages the mutation of state.

Re: If Inheritance is so bad, why does everyone use it?

#380

Earlier quoted context omitted.

https://gameprogrammingpatterns.com/component.html

Got a simpler example?

Well in my game everything inherits from GameObject. GameObject has a draw method. Enemies, coins, the player, doors, they're all GameObjects. But when it comes to drawing things, the logic doesn't vary by those subtypes. Rather some things are pixel art with a collection of frame by frame animations. Other things are just a static image. Some things I render as text. Some things are really complex, I render them as composable components with different frames of animation/keyframes, created in a custom character editor program. Each of those render modes I described is a different DrawObject. So instead of having an insanely complex inheritance hierarchy of all permutations of things and how they are drawn (or trying multiple inheritance), I have GameObjects and they contain an property/object of type DrawObject. I have a shallow inheritance hierarchy of GameObjects and a shallow inheritance hierarchy of DrawObjects. And I can compose them together as I see fit.

I even have an AggregateDrawObject class for cases where I need to run two animations at once for a single object.

You can do something similar with UpdateObjects too and have composable behavior.

Note that I still use inheritance, but just don't let it get out of control. Anyone saying "inheritance is bad" is either a moron or really means "deep inheritance hierarchies are bad" or maybe "bad designs are bad".

Post reply on HN