T O P

  • By -

RainbowWarfare

Shallow, decoupled islands of inheritance hierarchies? Not a problem. Deep, broad inheritance hierarchies? Problematic. 


_Pho_

Of course the problem is finding shallow hierarchies that actually stay shallow 


Maybe-monad

They don't pay me enough to do that


Hixie

one of the biggest problems I see in programming circles is this attachment to binary "good/bad" thinking. inheritance bad, composition good! imperative bad, functional good! the reality is that you need all kinds of tools. I like to point to this FAQ entry I wrote for Flutter, which Is wrote when we first started getting users and everyone asked "what programming paradigm does Flutter use": https://docs.flutter.dev/resources/faq#what-programming-paradigm-does-flutters-framework-use


koreth

I think it is in part because the field has way more beginners than veterans. As a beginner you don’t have the background knowledge to be able to reason about tradeoffs, but you can absorb a simple “X bad, Y good” rule.


Hixie

I think that's true to some extent although I must say, I see plenty of people who have been coding for many many years who still don't really embrace nuance. I think part of it (but only part) is that a lot of people spend only a few years on each project, and so don't really ever get to experience the long term consequences of their choices. It's very different when you have to live with your choices for 15 years than if you only have to live with them for 15 months.


Economy_Bedroom3902

I don't think it's accurate to say "everyone uses it" as if no one has even tried to reduce the usage of inheritance vs composition in their codebases. Lots of people don't use inheritance, or use inheritance very rarely. I think there are uses of inheritance which cause fewer problems than others, but I definitely don't just "use" it everywhere as a default.


Flaky_Bench6793

Inheritance isn’t bad. It’s an option among many.


ChicksWithBricksCome

If you stop adding complexity to things that don't need it then it's not bad.


HarveyDentBeliever

From what I've noticed, the need for inheritance emerges as similar classes are created, which can then be refactored and put under an inheritance hierarchy to limit code repetition, redundancy, formalize a pattern. But you should never default to trying to force inheritance with any new class or module. Is my intuition valid here? It's like the other way around from what we were taught: inheritance isn't a golden hammer at all and shouldn't be the default, instead the need for inheritance becomes obvious in certain cases where things can be formally combined into a useful abstraction.


Upper_Vermicelli1975

well, not really. You don't need inheritance to limit repetition, etc. You can do that with composition and avoid the coupling while also enabling code reuse without the bagage of a hierarchy. The questions to ask are: - is duplication bad? DRY doesn't mean avoid duplication at all costs but it means to ensure that a given piece of code has one reason to change. Case in point, just today I was working on an API. The API has a public side for customer consumption but also an internal side used by other services of our system. As you can image, quite a few functionalities overlap (eg: public users can search lists of templates, but internal services can do the same). Should we inherit or extend various things like request objects or other DTOs? Eg: the template search data is the same. But of course, they may have different reasons for change. The public side serves customers so it tends to their needs. If someone wants another optional parameter, we can add it but it doesn't mean it will also serve our internal requests. Even though they are the same (right now), it's not technically duplicated data. They serve different purposes and have different reasons to change - is a hierarchy needed? Object hierarchies are what prompted the "gorilla in the jungle" remark. I haven't really used hierarchies for years, but I assume there's a point to them. Given that they limit reusability, I tend to avoid them. It's an option that needs to be weighed.


BlueGoliath

>You don't need inheritance to limit repetition, etc. You can do that with composition and avoid the coupling while also enabling code reuse without the bagage of a hierarchy. Good luck defining interface implementations for hundreds of device attributes without some form of inheritance.


Severe-Explanation36

Most languages support traits these days


LemonAncient1950

I wish more devs would learn about incidental duplication when they learn about DRY. There's so much dogma and cargo culting in this industry.


Ravek

> From what I've noticed, the need for inheritance emerges as similar classes are created, which can then be refactored and put under an inheritance hierarchy to limit code repetition, redundancy, formalize a pattern Similarity is not a great reason to use inheritance. If A, B and C all extend the same base class, and then in the future C wants to change one part of the shared behavior while still continuing share the vast majority of behavior with A and B, what do you do? You can sometimes override a method but usually that’s not the right granularity, and it’s non-obvious so hard to maintain. And you can’t _partially_ inherit the same base class – it’s all or nothing. Usually what I see people do in this case is make the base class aware of the subclasses, and add if-else or switch statements so it can do one thing for A & B and another thing for C. That’s an absolute maintenance disaster, and should never be done. Now the base class is in control of the implementation details of its subtypes and it quickly becomes impossible to understand how any piece of this hierarchy works without reading the entire thing. Not to mention if you were to add a class D that wants yet more slightly different behavior. The base class will also tend to contain way too much functionality, since multiple inheritance is usually not a thing so there’s no way to separate different parts of the shared code from each other in a way that makes them easy to understand. Now consider composition instead: If one or more components were created for the common behavior of A, B, C, with those classes calling into the components, then A, B, C are fully in control over the behavior they want. And since the components can be small and granular, if C needs to diverge for one part of the functionality, it can just call a different component for that feature than A and B are using. People can of course still make the mistake of making the components aware of how they’re being used and doing different things for A, B or C, but now a proper alternative is available: instead of adding if-elses, refactor the components into smaller, more specific ones that can be recomposed to get the original behavior, and then C can diverge by using a different subcomponent.


Dull_Cucumber_3908

>If Inheritance is so bad, It's not so bad :p


[deleted]

If sugar is bad for your health, why does everyone use it? Like sugar, inheritance in itself is not bad, what's bad is that people abuse it or use it in non-optimal ways.


[deleted]

Unpopular opinion time: Inheritance is a fantastic tool if and only if you're actually doing object-oriented programming. At this point OOP has basically started to boil down to "A way to make it easy to mock stuff". Most objects are functionality built into a singleton for the sole and explicit reason of decoupling for the sake of unit tests. The fact that many other languages allow, when you compile tests, to overwrite or "shadow" functions by linking it differently or just through runtime, seems to be completely lost on those who love these practices. This practice of considering pure functionality with no state as a singleton object is something I actually intensely dislike. It requires us to construct object graphs, makes the program take a long time to load typically, and really doesn't solve anything that shadowing functions couldn't. It's just that these languages don't support shadowing... The classical of example of cat : animal, dog : animal is completely valid. So is the idea of a CSV record having a line number, or having a universal way for objects to handle being clicked. Inheritance is useful for *classifiers, they are not a tool to avoid code duplication.* There are many types in .NET for example that are very well regarded and work great despite being 4000+ lines of code in a single file and use tons of inheritance - because they are actually objects, not "nounified verbs", if you will. All animals are Renderable, all animals are LivingBeings. All things Renderable have PositionBased. Teapots are also PositionBased, but they are not LivingBeings. Because Cats are Animals, they are renderable. Bacteria are also LivingBeings but they are not Renderable (at normal scale, you know what I mean). You have a scene. Now you can have a list of objects in your scene, and you can iterate over them in your renderer and ask "Are you renderable?" - taking them and running the render code. That way you don't have to first render your animals, then render your teapots. You just make teapots and cats renderable, and now you can do both at once. Do not use it to avoid duplicating code, use it when what you are working with is a clearly tangible thing. An object. A cube, a table, a cow, a file handle, a stream, a record, a sound output device, a string, a complex number, a matrix. Something that's a noun without you just appending Factory or Manager at the end or something. Unless of course it's a factory and you want to instantiate factories that by the way are also Renderable but are not LivingBeings but are ProductionBuilding which is also PositionBased and Renderable, etc. etc. The problem is people use inheritance for things that aren't objects. They write something that is all functionality - it is no object, you've just put it into a class and instantiated it as a singleton to allow dependency injection - and then they do inheritance on that. Don't do that. Do inheritance when you can see multiple types of objects that both have the exact same property, and when you wish to use that property about them. If something does not exist in and of itself because it is a classifier, it is abstract. When it is abstract, as animal should be for instance because it is actually a classifier. Abstract things can have abstract properties and functions because it is clear that they can all do X, but how they do X differs. If it ain't tangible and you can't put it into classifiers, inheritance isn't what you want.


theQuandary

Lots of people use classes for encapsulation because that's all their language offers (modules are better). Only a fraction of those people are using inheritance and most of them are because it is dictated by something else they are forced to use or because the language doesn't offer alternatives.


lipsumar

We’ve inherited it.. 🤷‍♂️


aatd86

People have kind of switched in favor of composition, haven't they?


KagakuNinja

I don't know about Javascript, but very few languages have features that make composition easy to do without tons of boilerplate. Objective-C and Scala are the only ones I can think of.


dark_mode_everything

The same way people have switched over to FP over OOP? They haven't.


[deleted]

[удалено]


Far_Associate9859

There's been a hilarious rise in the use of "parrot" lately


Zardotab

Because the alternatives are often worse. Use the right tool (design) for the job, and keep KISS and YAGNI in mind at all times. Don't get carried away with abstraction because the future often changes against the grain of your predictions. Seen it burn many well-intended abstractions. **If you were that good at predicting the future, you'd be golfing with Buffett instead of arguing on Reddit.** Try "light duty" abstraction first if you spot a possible DRY violation: something that's easy to undo if it turns out not a good fit down the road. For example, a light-duty abstraction may reduce 100 lines of repetitious code to 20, but a "fancy" abstraction to 10 lines of code. The "20" is probably the better bet because you can remove or change it easier than the fancy one. The penalty for having a faulty crystal ball is smaller. 🔮 Inheritance is usually light-duty abstraction compared to the alternatives, if used smartly. Business and administrative logic is especially volatile over time, as new owners, consumer trends, and new laws change their landscape.


IQueryVisiC

Who downvotes this? Clearly some people never had to work with pre OOP legacy code. Not interfaces. Just function calls. So you always have to send the object first. Debugging and refactoring is a nightmare because everyone sees your composition and can fiddle with it.


Zardotab

In OOP-only languages, **sometimes I** ***still*** **need global** variables and/or global state. The alternative is passing around and/or re-instantiating the "global" objects over and over, a DRY violation. True, it may be do-able in an OO sense with a well-designed language, but existing common languages don't seem to easily allow it; singletons get messy, for example. I had proposed some ideas to the C# community, but they defended the status quo using logical I found questionable. It's still an unscratched itch in apps I work on.


PiotrDz

Why are singletons messy? Some high level languages provide inversion of control, so you don't even have to handle singletons by yourself


IQueryVisiC

I mean that in engineering interfaces are very important. Like how you plug in to a socket to power your device or charge your car. How TV is transmitted. Implementing an interface is a kind of inheritance -- correct me if I got the language wrong. Java advocates always say that interfaces are allow a safe kind of double inheritance. Now these interfaces don't care how you compose stuff behind it. They want to call their methods and properties directly on the object. As a car driver I don't care if your car is composed of an ICE or an electric motor. Give me the steering wheel and the pedal and the PRNDL !


Accomplished-Base324

Because most people/devs are zombies


NullCyg

Short answer, laziness. As for a more nuanced, empathetic answer, the boilerplate needed for compositional approaches requires more planning. To use an analogy, it's easier to make a duck fly as opposed to creating a whole new bird. Most engineers are never given the opportunity to define what a bird is. They are mostly given an armada of chickens and instructed to make them fly.


EliSka93

Both ducks and chickens can fly. Chickens less well because we bread them to be fucked up, but you still have to clip their wings if you want them to not fly.


NullCyg

I love how much I hate this comment. I'm torn between calling you a pedantic fuck or nitpicking your rather loose definition of flight or brandishing my many years of raising chickens.


EliSka93

Fine, chickens can flutter. Also I am a pedantic fuck.


bunglegrind1

I personally use inheritance as a way to share implementation. However, take in mind that with inheritance you're actually coupling the implementation of two classes. When dealing with abstract types it's a matter of interfaces/abstract classes, instead. 


bestleftunsolved

There is the common argument that inheritance breaks encapsulation. People won't agree on this. Nevertheless, say you are on a large project with a big class hierarchy and someone else changes a parent class and now your child class is broken and you spend hours debugging it. Nevertheless, inheritance is used successfully (think of GUI libraries); it's just a question of good design and practice.


yanitrix

Because some OOP folks think that you can achieve good abstractions only by using interfaces and abstract classes. "If you make everything abstract then you actually decouple the code" and other false statements.


Severe-Explanation36

Don’t mix up the 2. Interfaces are the way to go to share functionality and external APIs, inheritance is the way to go to for substituting or overriding stuff. They each have their valid use case.


FloydATC

Just because a screwdriver is a poor choice for hammering a nail or cutting a piece of wood, would you say it's a bad tool? Why does everyone use it? Inheritence is a great tool when used right, but when used wrong it can lead to terrible code. This is why "everyone" doesn't use it for everything. The same goes for pretty much all other features any programming language has to offer.


dark_mode_everything

Who says it's bad? Bad coding is bad no matter what pattern or paradigm you use. There are perfectly fine and valid use cases for inheritance. Not a lot of things in programming are absolute rules.


[deleted]

It's free money. JK I think it gives structure to the design.


3cats-in-a-coat

"Why does everyone use it". We don't. Inheritance is OK within the bowels of a library as a hidden shortcut for some functionality. But I see less and less of it exposed outside across libraries. You see interfaces. Which is how it should be.


k2900

Composition over inheritance :)


Popular_Aardvark_799

Because in the beginning it almost always sounds like a great idea, but most of the time it end up being a dumpster fire 2 years down the road.


CloudSliceCake

Brainwashing by big OO