Why use inheritance at all?

47,181

Solution 1

If you delegate everything that you haven't explicitly overridden to some other object implementing the same interface (the "base" object), then you've basically Greenspunned inheritance on top of composition, but (in most languages) with a lot more verbosity and boilerplate. The purpose of using composition instead of inheritance is so that you can only delegate the behaviors you want to delegate.

If you want the object to use all the behavior of the base class unless explicitly overridden, then inheritance is the simplest, least verbose, most straightforward way to express it.

Solution 2

[note: This question was originally tagged as being language-agnostic. Based on that, this answer was written to be fairly language agnostic, so it discusses inheritance as it's used across a wide range of languages, such as Smalltalk, C++, and Object Pascal. It's since been re-tagged as being specifically about Java. Java is different in defining a class and an interface as two entirely separate things. The idea that the purpose of inheritance is code reuse, not polymorphism is reasonable from a Java-specific viewpoint, but clearly wrong from a language-agnostic viewpoint. If you only care about Java, this probably isn't the best answer.]

The purpose of inheritance is code reuse, not polymorphism.

This is your fundamental mistake. Almost exactly the opposite is true. The primary purpose of (public) inheritance is modeling the relationships between the classes in question. Polymorphism is a large part of that.

When used correctly, inheritance isn't about reusing existing code. Rather, it's about being used by existing code. That is to say, if you have existing code that can work with the existing base class, when you derive a new class from that existing base class that other code can now automatically work with your new derived class as well.

It is possible to use inheritance for code re-use, but when/if you do so it should normally be private inheritance not public inheritance. If the language you're using supports delegation well, chances are pretty good that you rarely have much reason to use private inheritance. OTOH, private inheritance does support a few things that delegation (normally) doesn't. In particular, even though polymorphism is a decidedly secondary concern in this case, it can still be a concern -- i.e., with private inheritance you can start from a base class that's almost what you want, and (assuming it allows it) override the parts that aren't quite right.

With delegation your only real choice is to use the existing class exactly as it stands. If it doesn't do quite what you want, your only real choice is to ignore that functionality completely, and re-implement it from the ground up. In some cases that's no loss, but in others it's quite substantial. If other parts of the base class use the polymorphic function, private inheritance lets you override only the polymorphic function, and the other parts will use your overridden function. With delegation, you can't easily plug in your new functionality so other parts of the existing base class will use what you've overridden.

Solution 3

Every one knows polymorphism is a great advantage of inheritance. Another Benefit which i find in inheritance is that helps to create replica of real world. For example in pay roll system we deal managers developers ,office boys etc. if we inherit all these class with super class Employee. it makes our program more understandable in context of real world that all these classes are basically employees. And one more thing classes not only contain methods they also contain attributes. So if we contain attributes generic to employee in the Employee class like social security number age etc. it would provide greater code reuse and conceptual clarity and of course polymorphism. However while using inheritance things we should keep in mind is the basic design principle "Identify the aspects of your application that vary and separate them from that aspects which change". You should never implement those aspect of application that change by inheritance instead use composition. And for those aspects which are not changeable u should use inheritance ofcourse if an obvious "is a" relation lies.

Solution 4

Inheritance is to be preferred if:

  1. You need to expose the whole API of the class you extend (with delegation, you will need to write lots of delegating methods) and your language doesn't offer a simple way to say "delegate all unknown methods to".
  2. You need to access protected fields/methods for languages that have no concept of "friends"
  3. The advantages of delegation are somewhat reduced if your language allows multi-inheritance
  4. You usually have no need delegation at all if your language allows to dynamically inherit from a class or even an instance at runtime. You don't need it at all if you can control which methods are exposed (and how they are exposed) at the same time.

My conclusion: Delegation is a workaround for a bug in a programming language.

Solution 5

I always think twice before using inheritance as it can get tricky fast. That being said there are many cases where it simply produces the most elegant code.

Share:
47,181
KaptajnKold
Author by

KaptajnKold

JavaScript developer by trade. Ruby developer in my free time. Lover of dynamic, reflective languages.

Updated on July 08, 2022

Comments

  • KaptajnKold
    KaptajnKold almost 2 years

    I know the question has been discussed before, but it seems always under the assumption that inheritance is at least sometimes preferable to composition. I'd like to challenge that assumption in hopes of gaining some understanding.

    My question is this: Since you can accomplish anything with object composition that you can with classical inheritance and since classical inheritance is very often abused[1] and since object composition gives you flexibility to change the delegate object runtime, why the would you ever use classical inheritance?

    I can sort of understand why you would recommend inheritance in some languages like Java and C++ that do not offer convenient syntax for delegation. In these languages you can save a lot of typing by using inheritance whenever it is not clearly incorrect to do so. But other languages like Objective C and Ruby offer both classical inheritance and very convienient syntax for delegation. The Go programming language is the only langage that to my knowledge has decided that classical inheritance is more trouble than it's worth and supports only delegation for code reuse.

    Another way to state my question is this: Even if you know that classical inheritance is not incorrect to implement a certain model, is that reason enough to use it instead of composition?

    [1] Many people use classical inheritance to achieve polymorphism instead of letting their classes implement an interface. The purpose of inheritance is code reuse, not polymorphism. Furthermore, some people use inheritance to model their intuitive understanding of an "is-a" relationship which can often be problematic.

    Update

    I just want to clarify what I mean exactly when I talk about inheritance:

    I am talking about the kind of inheritance whereby a class inherits from a partially or fully implemented base class. I am not talking about inheriting from a purely abstract base class which amounts to the same thing as implementing an interface, which I for the record am not arguing against.

    Update 2

    I understand that inheritance is the only way to achieve polymorphism i C++. In that case it's obvious why you must use it. So my question is limited to languages such as Java or Ruby that offer distinct ways to achieve polymorphism (interfaces and duck typing, respectively).

  • KaptajnKold
    KaptajnKold almost 14 years
    Re 1) That's why I wrote that inheritance sort of makes sense in some languages, namely the ones that make delegation very verbose. Re 2) Possibly. But you'd have to work hard to convince me that such a need is not a flaw in the design to begin with. Re 3) I don't see why. Re 4) This has more to with overcoming the limitations of inheritance, which demonstrates my point. Inheritance is limiting and difficult to get right. Delegation does not seem to have the same problems.
  • KaptajnKold
    KaptajnKold almost 14 years
    I agree with most of what you write. But just because there's no discernible difference between implementing an interface and inheriting from a class with only abstract methods in some languages, that does not provide a compelling reason to use classical inheritance in the rest of the cases, ie. when you extend a class whose methods are not abstract.
  • KaptajnKold
    KaptajnKold almost 14 years
    I thank you for putting all this work into your answer, but I already know what interfaces are for. Can you also tell me what classical inheritance is for and specifically in what ways it is better than delegation?
  • Dlaor
    Dlaor almost 14 years
    Hey, what program did you use to make that diagram?
  • this. __curious_geek
    this. __curious_geek almost 14 years
    It's visual studio 2008 Class-Diagram tool.
  • Aaron Digulla
    Aaron Digulla almost 14 years
    Languages like Java make delegation hard, so inheritance is used very often, even if delegation would have been better.
  • KaptajnKold
    KaptajnKold almost 14 years
    Do you then agree that inheritance in languages that make delegation easy (e.g. Objective C) is more trouble than it's worth?
  • Aaron Digulla
    Aaron Digulla almost 14 years
    I have never used Objective C, so I can't comment on that.
  • KaptajnKold
    KaptajnKold almost 14 years
    +1 for bringing something new to the discussion :-)
  • Frerich Raabe
    Frerich Raabe almost 14 years
    What you call classical inheritance is most likely actually inappropriate inheritance. It just happens that inheritance is, at least in some languages, the mechanism for implementing an interface. This is no either/or thing.
  • L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
    L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ about 12 years
    "there are many cases where it simply produces the most elegant code." Show me one.
  • Alexey
    Alexey over 11 years
    I think that in duck typed languages there is no need to inherit from a class to be able to replace it in existing code. A class that delegates everything to another class would most likely be able to replace it.
  • Alexey
    Alexey over 11 years
    After some more thinking, i also think that the purpose of inheritance is code reuse and not polymorphism. For polymorphism it is enough to implement a required interface, but with inheritance you inherit the implementation.
  • Jerry Coffin
    Jerry Coffin over 11 years
    @Alexey: Yes, if you're talking specifically about the languages specified in the OP's "Update 2" (written ~6 months after this answer) that becomes a defensible position (i.e., I'm not sure I agree that it's entirely correct, but at least it's not nearly as obviously nonsense).
  • Alexey
    Alexey over 11 years
    @ Jerry: i agree that inheritance can be also useful for polymorphism even in languages like Ruby: in my opinion in such cases it serves as a class contract description.
  • weberc2
    weberc2 over 10 years
    Really, you shouldn't use inheritance in most circumstances. If you want code reuse, define an interface that the would-be parent class implements, make the parent class a member of the "child" class, and expose the same methods in the child as exist in the parent. It's tedious, but it's a better system than with inheritance polymorphism, and it's not tedious in sane languages that give you this for free, a la golang. :)
  • Jerry Coffin
    Jerry Coffin over 10 years
    @weberc2: If you're using Go, that's about your only alternative. In something that actually has inheritance, all you're doing is imitating what inheritance already does, but making it harder to read, harder to use, and generally just worse. Yes, many people over-use inheritance (especially in Java, from what I've seen), but if you want all (or at least 90%) of what inheritance provides, simulating all of it by hand instead is not an improvement. Oh, but the downvote got my rep back to a multiple of 5, so thanks even though it's completely unwarranted.
  • weberc2
    weberc2 over 10 years
    @JerryCoffin How do you figure that it's the only alternative in Go? You aren't imitating what inheritance already does, you're decoupling your "child" class from the "parent" class implementation. <- That's the improvement. It's only "doing it by hand" because most languages don't offer tools to Do It Right by default. ;) Anyway, I didn't downvote you because you disagree with my philosophy, but because you're objectively wrong. I'm glad all is well with your reputation. Cheers.
  • Jerry Coffin
    Jerry Coffin over 10 years
    @weberc2: If there's really a factual error in the answer, I'll be happy to correct it, but at least so far you don't seem to have pointed to anything close to a factual error.
  • weberc2
    weberc2 over 10 years
    @JerryCoffin I don't particularly care if you update your answer or not, but I don't understand why you disagree. Do you think loose coupling is bad? Or do you think that implementation inheritance offers a looser coupling than interface inheritance?
  • Jerry Coffin
    Jerry Coffin over 10 years
    @weberc2: Disagree with what exactly? So far about the closest thing to a factual statement you've made is implying that you like Go. I certainly don't disagree with that. You claimed that the answer was objectively wrong. If so, cite a sentence (or two, or whatever), and specify how it's wrong. Asking vague questions about do I think X or Y isn't showing anything about the answer being objectively wrong.
  • weberc2
    weberc2 over 10 years
    @JerryCoffin You stated, "In something that actually has inheritance, all you're doing is imitating what inheritance already does". I believe this is objectively wrong. Consider this example of interface inheritance: pastebin.com/xAybHaDJ How would you do this with classical inheritance? Would you derive a new class for every combination of Reader and Writer?
  • Jerry Coffin
    Jerry Coffin over 10 years
    @weberc2: So the (first) problem here is that you don't understand the difference between an answer and a comment. These are comments. The answer is the part in larger type above.
  • TigerBear
    TigerBear almost 10 years
    Another big advantage of composition is the ability to change the object that you are delegating to at run time. It would be like inheriting from a parent, but then being able to specify a different parent to inherit from at run time. So even if you just delegate out all of your methods, there is still a big advantage. Especially when testing and mocking.
  • Luaan
    Luaan almost 9 years
    Actually, you might be surprised what many languages that support composition well do with this. There's a lot of useful tricks you can do at runtime to optimize well above anything you could do in compile-time. Regardless, this is one kind of the bad trade-off Knuth meant when talking about premature optimization - if you can argue that you chose OOP over composition because of dispatch overhead... why are you using OOP? Surely there's more of a difference between static dispatch and OOP than between OOP and delegates?
  • weberc2
    weberc2 over 8 years
    Yeah, inheritance is just a weird special case of composition that unreasonably fixes the inner element. There is probably a case in which inheritance might save you some keystrokes, but it doesn't justify all of the confusion and inappropriate uses that it has created.
  • weberc2
    weberc2 over 8 years
    Employee should be the interface, and all of the concrete classes should implement the interface. If all concrete classes have the same data, you should probably make Employee a class with a Type field for what kind of employee it is. Inheritance is not about polymorphism, that's what interfaces are for.
  • weberc2
    weberc2 over 8 years
    This is an implementation detail. If I write struct{int i; struct {int j}} in C, it's still composition and not any more likely to lead to a cache miss.
  • bestsss
    bestsss over 8 years
    @weberc2, The 1st tag is 'Java'. There is no struct (i.e. no headless objects) in Java. You need some struct * not just struct. While indirections are 'implementation detail' the performance gain/loss is non-trivial. Compare LinkedList to ArrayList for instance.
  • bestsss
    bestsss over 8 years
    @Luaan, Java is not amongst those languages (that will save the indirection during composition). Composition also means higher memory footprint and more work for the GC. Don't get me wrong - for anything non-performance critical, I'd frown mindless inheritance... Writing library code/sub milliseconds trading you'd prefer not to pay for the indirections.
  • weberc2
    weberc2 over 8 years
    Ah, I thought you were talking generally. It's a bummer Java punishes you for following best practices (cache misses, increased work for GC, larger memory footprint, etc). :/
  • yyny
    yyny over 7 years
    Your third point isn't a very good one. If you move your logic to another class, you will still have to use inheritance. And if you use composition (Traits, Mixins, Interfaces, Abstract Classes) then it's no longer a "code smell". In fact, these are generally preferred over inheritance anyway, since they allow for shared logic without the need for shared state.
  • Grandpa
    Grandpa over 4 years
    In case the word "Greenspunned" above is unfamiliar, it means bringing a feature from another language into your own, but implementing it badly. See Greenspun's tenth rule and Leaky Greenspunned Abstractions.