4 ms·
Do we need inheritance at all? It only leads to complicated class hierarchies and leaky abstractions. Are there cases/problems where inheritance approach is s
by cabirum 4y ago
Do we need inheritance at all? It only leads to complicated class hierarchies and leaky abstractions. Are there cases/problems where inheritance approach is superior to composition, interfaces, etc?
- fouronnes3 4y agoSum types are superior IMO.
- jcelerier 4y agoSum types do not support loading new types at runtime which is fundamental in many GUI software
- cjfd 4y ago'Need' is a big word. One 'needs' very few things. Software has actually been written in assembly, so what do we actually 'need'? Answer to both questions is yes. When I read something like this I find the 'one size fits all' dogmatism disturbing. So, maybe someone somewhere created a class hierarchy that was needlessly complex. Now apparently the pendulum needs to swing all the way to the other side and all of inheritance is bad. I hear that lots of people are cutting themselves incidentally with knives. Shall we forbid them? In programming people don't seem to be able to settle on the middle ground, the pendulum always needs to swing to the extremes apparently. An example where implementation inheritance is beneficial? I have a calculation that depends on quite a few parameters. The calculation can be done from the application code but part of the calculation is rather expensive and is only done once every so often. So, I put the parameters of the calculation in a class, inherit another class from that the the application uses and that can do cheap calculations. I inherit another class that does the complicated part of the calculation. All in all three classes so not very complicated. The disadvantage with making the parameter class a member is that the code gets littered with indirection like 'data->param1' all over the place. This is much nicer.
- zozbot234 4y ago> The disadvantage with making the parameter class a member is that the code gets littered with indirection like 'data->param1' all over the place. This is much nicer. Isn't that a rather trivial concern? Implementation inheritance is not "much nicer" than delegation, the opposite in fact is the case. It adds a dispatch step to all calls to virtual methods (including calls that are private to implementations at any level of your 'hierarchy') that is not what you would want in most cases. Which in turn means your entire class hierarchy has to be analyzed as a single, highly-coupled program module; it's quite literally impossible to understand portions of it in isolation.
- cjfd 4y agoI find readability one of the most important properties of code. As the saying goes 'code is more often read then written'. Also, we have all seen where disregarding readability leads us, namely the java language, where one gets the impression that every java programmer is being paid in proportion to the number of characters they type. Any single step that leads us from readable code to typical java code may seem like a minor issue but in the end one ends up with code where the championship of large distance scrolling can be attained just in order to find out what is in a class. In cases I was describing readability really takes a bit hit. It is a bit like writing the abc-formula and having to write (- data->b +/- sqrt(pow(data->b, 2) - 4 * data->a * data->c ) / (2 * data->a). Being able to write (- b +/- sqrt(pow(b, 2) - 4 * a * c) / (2 * a) is so much nicer. Actually, the three classes I described by themselves do not need any virtual methods. But I was skimping on details a bit. There actually is a fourth class that is being used to mock the application facing class and that causes some virtual methods to be necessary.
- cyber_kinetist 4y agoBy the way, Jai (which is a language currently being developed and is beta) has a “using” keyword which allows you to import the scope of the struct in normal functions, which looks like: do_something :: (using data: Data, arg: int) { field1 = field2 + arg … } Which lets you get rid of the annoying data.field1 and data.field2 indirection. I really wish more languages implement this feature…
- aryehof 4y ago1. The production of “frameworks” that provide default behavior that can be extended or changed. 2. The modeling of taxonomies (Aristotolian). 3. Modeling fixed generalization-specialization relationships.
- travisjungroth 4y agoI agree with 1 and 3, but IME using inheritance to model taxonomies is usually a big mistake. It can work well for things inherent to the system (Iterable -> Sequence) but it falls apart when you're trying to model the real world (Mammal -> Dog). It's essentially about whether you're making stuff up, and can choose to operate within the bounds of the type system to get its benefits (the first case) or you're trying to describe something real and any trade-off is actually bad (the second case). It doesn't help you to be unable to express a portion of the problem, but in exchange you get something that doesn't apply. Commentary on an excerpt from an interesting blog series: https://softwareengineering.stackexchange.com/a/361176 https://softwareengineering.stackexchange.com/a/361176
- aryehof 4y agoI somewhat agree, but note that I qualified point 2 with “Aristotelian”. The alternative “prototypical” view (which is what most want to use inheritance for) is unsuited. Regarding the link, I remember Eric Lippert’s series of blog posts and his struggle to (initially) model a prototypical type problem using inheritance. I remember thinking at the time that he was limited in his object modeling experience to only the constructs provided by the C# language. There are no language constructs that specifically deal with rules relating to (optionally) collaborating objects, as he discovered.
- tasubotadas 4y agoYou can't really have State pattern w/o inheritance. At very least it becomes very awkward.
- tialaramex 4y agoThis page of Rust's Book shows how to implement exactly the State pattern without inheritance, and it feels pretty natural. Rust's traits do have inheritance but that isn't used here - at first there is one trait, State, but by the time we're writing idiomatic Rust there are no traits at all. https://doc.rust-lang.org/book/ch17-03-oo-design-patterns.html https://doc.rust-lang.org/book/ch17-03-oo-design-patterns.ht... We end up with three types of post, Post, DraftPost and PendingReviewPost, and our state pattern is implemented by the type transitions implemented in these three types. When you call Post::new() you get a DraftPost, and the only way to get a Post from that is to request the review, obtaining a PendingReviewPost and have somebody accept it to get the Post from there.
- throw_m239339 4y ago> Do we need inheritance at all? It only leads to complicated class hierarchies and leaky abstractions. Are there cases/problems where inheritance approach is superior to composition, interfaces, etc? No, but since Python allows multiple inheritance, one can use parent classes as traits for composition without having to write so silly boilerplate.
- tialaramex 4y agoYou probably want to be able to inherit behaviour. So e.g. in a language with interfaces you want interfaces to have inheritance but perhaps not concrete types. You definitely don't want multiple inheritance of concrete types. I wrote a bunch of Python without ever realising it had multiple inheritance and I feel like that's a lucky escape, inheritance on concrete types causes problems, but multiple inheritance causes exponentially worse problems. Scenarios people have shown me of "good" multiple inheritance in Python all looked like regrettable mistakes.
- magicalhippo 4y agoNeed? No. Everything beyond machine code is sugar. Can certain things be solved neatly with inheritance in a given language? Sure. Is it a hammer for every nail? No. For example, at work we use Delphi. Delphi has fairly excellent support for COM-like interfaces[1]. I prefer using interfaces, and I prefer to use composition where it makes sense, since Delphi has support for delegation[2]. But when implementing certain interfaces I might use inheritance through a base class with one or two abstract methods. Could I have done the same through composition? Absolutely, but sometimes using inheritance leads to a smoother implementation. To me this is a happy middle ground, in Delphi. The resulting hierarchy is very shallow, almost never more than two levels. And the users are shielded from this implementation detail through the interface. [1]: https://docwiki.embarcadero.com/RADStudio/Sydney/en/Object_Interfaces_(Delphi) https://docwiki.embarcadero.com/RADStudio/Sydney/en/Object_I... [2]: https://docwiki.embarcadero.com/RADStudio/Sydney/en/Using_Implements_for_Delegation https://docwiki.embarcadero.com/RADStudio/Sydney/en/Using_Im...
- Der_Einzige 4y agoIn terms of keeping enterprise devs employed forever to fix the generated spaghetti code, inheritance is definitely superior to composition