views:

596

answers:

12

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.

+13  A: 

The main reason for using inheritance is not as a form of composition - it is so you can get polymorphic behaviour. If you don't need polymorphism, you probably should not be using inheritance, at least in C++.

anon
I respectfully disagree: Inheritance is *not* about polymorphism. That's what interfaces are for. I agree that polymorphism is what inheritance is most often used for, and that's part of my point: Inheritance is abused for things it is not best suited for.
KaptajnKold
@Kap Well, what can I say, except "you are wrong" - C++ (for example) does not have the concept of interfaces. And the only time I use inheritance in my own code is when I need polymorphism.
anon
I did not know that C++ had no concept of interfaces. My mistake. In that case you are obviously required to use inheritance to achieve polymorphism. But let's say you decided to only inherit from purely abstract classes. Would you feel limited by that, or are there in your opinion good reasons to use inheritance from non-abstract classes?
KaptajnKold
@Kap In C++, it is considered best practice to only inherit from abstract classes. Most of us duck this at one point or another (and regret it later), but base classes are almost always abstract - I don't see this as a limitation on me.
anon
Well, then you've practically proved my point :-)
KaptajnKold
@Kap I thought your point was that you can replace inheritance with composition?
anon
Yes, it is. But you need to differentiate between inheritance of an implementation and inheritance of an interface (or purely abstract class). I am only talking about the former kind.
KaptajnKold
@Kap So your question is really "Is there any case where it is preferable to use inheritance to replace composition?" - somewhat different to "Why use inheritance at all?", I think you will agree.
anon
"But you need to differentiate between inheritance of an implementation and inheritance of an interface (or purely abstract class)" I don't see a big difference here. Why don't you look at Qt 4 or any other GUI library for C++? They should be enough to illustrate when inheritance is useful.
SigTerm
@Neil No, i don't agree. IMO it is you who are confusing two distinct concepts because they share the same syntax in C++. There is less reason for confusion among Java programmers, because the two concepts are distinct in syntax also. I'll admit to having a bit of a problem myself because I do not know of a substantive to describe the kind of inheritance we both like but which in my opinion is not really inheritance at all. Feel free to enlighten me if you know of one.
KaptajnKold
@SigTerm I don't doubt there are applications and frameworks that use classical inheritance while avoiding all of the problems it can get you. But my question remains: What are they gaining by this that they couldn't also have gained if they had used composition? When is classical inheritance better than composition and why?
KaptajnKold
Neil said "In C++, it is considered best practice to only inherit from abstract classes." He talked about abstract classes, but not necessarily *purely* abstract classes (which correspond to Java-style interfaces). I think inheriting from an abstract class that is not purely abstract is entirely fine.
Philipp
@Philipp You may be right, but I'm still nowhere nearer to understanding what the *concrete* benefits are :-(
KaptajnKold
@Kap Well, you seem to have your own, unique definition of inheritance. And I'm still not clear what question you are asking and, from your comments, neither are you. But one last try - good C++ programmers do not use inheritance (classical or otherwise) as a substitute for composition.
anon
@Neil You're not trying hard enough ;-). Re. my "unique definition": I am not alone in making a distinction between implementing an interface and inheriting an implementation. Gang Of Four makes this same distinction. But let me try to rephrase the question for you: Do you think inheriting from an non-abstract class in C++ is a useful feature? If so, when would you recommend doing so instead of using a delegate object to achieve the same result?
KaptajnKold
@Kap As I've said (at least twice) the purpose of inheritance in C++ is to provide polymorphism; to do this it is best to derive from abstract classes. I would not recommend its use in other cases. And the C++ in the GoF book is pretty poor stuff.
anon
@Neil I'm sorry if you feel you have to repeat yourself, but it was you who claimed to still not understand my question, which is why I restated it. I don't feel as if I've had any trouble understanding your points and in fact feel like we've never been very far from each other: You explicitly do not recommend using inheritance from anything other than an abstract class. It is the fact that many languages also support *that other kind of inheritance*, you know, the kind you do not recommend, that made me pose the original question.
KaptajnKold
@Kap I explicitly do not recommend using inheritance to do anything but implement polymorphism - it's certainly possible to do this with non-abstract classes.As for us not being far from each other, when you come out with statements like "Inheritance is not about polymorphism" (in your first comment), then yes, we are. But of course then you were talking about this mysterious "other" kind of inheritance, I suppose.
anon
@Kap, if you specify 'implementation inheritance' you may be able to keep this from spiraling out of control.
Jeff Sternal
@Neil Re. "Inheritance is not about polymorphism": I ceded this point to you in my 2nd comment, but you must have missed it. But if you do not agree that there are 2 distinct uses for inheritance in C++ I guess there's not more I can say at this point to convince you. You've completely ignored that many other languages have a separate mechanism to achieve polymorphism, whether it be interfaces in Java or duck typing in Ruby. You ignore that inheritance in these languages is done to achieve something more than polymorphism, or there would be no reason to have this feature also.
KaptajnKold
@Jeff The last paragraph in my original question was meant to clarify this distinction.
KaptajnKold
@Neil Wikipedia explains the distinction better than I could hope to: http://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)
KaptajnKold
@Kap Link is broken.
anon
Sorry. SO eats the closing paranthesis for some reason. Just add it, or look up "inheritance (object oriented programming)" manually.
KaptajnKold
@KaptajnKold: I think you are trying to describe interface inheritance aka subtype polymorphism.
0A0D
http://en.wikipedia.org/wiki/Inheritance_%28object-oriented_programming%29 - and about as useful as most wikipedia articles.
anon
@KaptajnKold: "What are they gaining by this that they couldn't also have gained if they had used composition?" Honestly, I don't see a point of this discussion. IMO your questions are too abstract and too far from reality to be useful. Why don't you simply check real APIs? If you want to know what you gain from using inheritance instead of other techniques, simply find inheritance-based API, and redo it (at least part of it) using your favorite technique (the one you think is better than inheritance). In this case you'll get a live demonstration of all benefits and disadvantages.
SigTerm
@KaptajnKold: Without real examples, the whole discussion looks like some kind of talk about migrations of non-existent flying pink elephants. Take a Qt or real GUI api. I don't see how you could do it (in C++, at least) without inheritance. If you think it can be done differently, do it differently to illustrate your point. If you think it can be done in Go/Ruby/Whatever, then do it in that language. Compare results (inheritance/no inheritance), think about differences, and you'll get your answers. Purely abstract discussion looks a bit useless for me.
SigTerm
+5  A: 

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.

Aaron Digulla
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
Languages like Java make delegation hard, so inheritance is used very often, even if delegation would have been better.
Aaron Digulla
Do you then agree that inheritance in languages that make delegation easy (e.g. Objective C) is more trouble than it's worth?
KaptajnKold
I have never used Objective C, so I can't comment on that.
Aaron Digulla
A: 

IMHO the concept of "isA" relationships has become very subjective, and was blurred when using concrete inheritance as a lazy way of reuse became commonplace, although doing so can violate the very principle of the isA concept - see LSP.

However, good or bad, concrete inheritance is still in wide use in frameworks like Win/WebForms, MFC etc, so it isn't entirely dead.

nonnb
A: 

You wrote:

[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.

In most languages, the line between 'implementing an interface' and 'deriving a class from another' is very thin. In fact, in languages like C++, if you're deriving a class B from a class A, and A is a class which consists of only pure virtual methods, you are implementing an interface.

Inheritance is about interface reuse, not implementation reuse. It is not about code reuse, as you wrote above.

Inheritance, as you correctly point out, is meant to model an IS-A relationship (the fact that many people get this wrong has nothing to do with inheritance per se). You can also say 'BEHAVES-LIKE-A'. However, just because something has an IS-A relationship to something else doesn't meant that it uses the same (or even similiar) code to fulfill this relationship.

Compare this C++ example which implements different ways to output data; two classes use (public) inheritance so that they can be access polymorphically:

struct Output {
  virtual bool readyToWrite() const = 0;
  virtual void write(const char *data, size_t len) = 0;
};

struct NetworkOutput : public Output {
  NetworkOutput(const char *host, unsigned short port);

  bool readyToWrite();
  void write(const char *data, size_t len);
};

struct FileOutput : public Output {
  FileOutput(const char *fileName);

  bool readyToWrite();
  void write(const char *data, size_t len);
};

Now imagine if this was Java. 'Output' was no struct, but an 'interface'. It might be called 'Writeable'. Instead of 'public Output' you would say 'implements Writable'. What's the difference as far as the design is concerned?

None.

Frerich Raabe
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
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.
Frerich Raabe
+2  A: 

Interfaces only define what an object can do and not how. So in simple terms interfaces are just contracts. All objects that implement the interface will have to define their own implementation of the contract. In practical world, this gives you separation of concern. Imagine yourself writing an application that needs to deal with various objects you don't know them in advance, still you need to deal with them, only thing you know is what all different things those objects are supposed to do. So you'll define an interface and mention all operations in the contract. Now you'll write your application against that interface. Later whoever wants to leverage your code or application will have to implement the interface on the object to make it work with your system. Your interface will force their object to define how each operation defined in the contract is supposed to be done. This way anyone can write objects that implement your interface, in order to have them flawlessly adapt to your system and all you know is what needs to be done and it is the object that needs to define how it is done.

In real-world development this practice is generally known as Programming to Interface and not to Implementation.

Interfaces are just contracts or signatures and they don't know anything about implementations.

Coding against interface means, the client code always holds an Interface object which is supplied by a factory. Any instance returned by the factory would be of type Interface which any factory candidate class must have implemented. This way the client program is not worried about implementation and the interface signature determines what all operations can be done. This can be used to change the behavior of a program at run-time. It also helps you to write far better programs from the maintenance point of view.

Here's a basic example for you.

public enum Language
{
    English, German, Spanish
}

public class SpeakerFactory
{
    public static ISpeaker CreateSpeaker(Language language)
    {
        switch (language)
        {
            case Language.English:
                return new EnglishSpeaker();
            case Language.German:
                return new GermanSpeaker();
            case Language.Spanish:
                return new SpanishSpeaker();
            default:
                throw new ApplicationException("No speaker can speak such language");
        }
    }
}

[STAThread]
static void Main()
{
    //This is your client code.
    ISpeaker speaker = SpeakerFactory.CreateSpeaker(Language.English);
    speaker.Speak();
    Console.ReadLine();
}

public interface ISpeaker
{
    void Speak();
}

public class EnglishSpeaker : ISpeaker
{
    public EnglishSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak English.");
    }

    #endregion
}

public class GermanSpeaker : ISpeaker
{
    public GermanSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak German.");
    }

    #endregion
}

public class SpanishSpeaker : ISpeaker
{
    public SpanishSpeaker() { }

    #region ISpeaker Members

    public void Speak()
    {
        Console.WriteLine("I speak Spanish.");
    }

    #endregion
}

alt text

this. __curious_geek
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?
KaptajnKold
Hey, what program did you use to make that diagram?
Dlaor
It's visual studio 2008 Class-Diagram tool.
this. __curious_geek
A: 

When you asked:

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?

The answer is no. If the model is incorrect (using inheritance), than it's wrong to use no matter what.

Here are some problems with inheritance that I've seen:

  1. Always having to test the run time type of derived class pointers to see if they can be cast up (or down too).
  2. This 'testing' can be achieved in various ways. You may have some sort of virtual method that returns a class identifier. Or failing that you may have to implement RTTI (Run time type identification) (At least in c/c++) which can give you a performance hit.
  3. class types that fail to get 'cast' up can be potentially problematic.
  4. There are many ways to cast your class type up and down the inheritance tree.
C Johnson
+2  A: 

What about the template method pattern? Let's say you have a base class with tons of points for customizable policies, but a strategy pattern doesn't make sense for at least one of the following reasons:

  1. The customizable policies need to know about the base class, can only be used with the base class and don't make sense in any other context. Using strategy instead is do-able but a PITA because both the base class and the policy class need to have references to each other.

  2. The policies are coupled to each other in that it wouldn't make sense to freely mix-and-match them. They only make sense in a very limited subset of all possible combinations.

dsimcha
+1 for bringing something new to the discussion :-)
KaptajnKold
+3  A: 

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.

dsimcha
+3  A: 

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.

ChaosPandion
A: 

Classical inheritance's main usefulness is if you have a number of related classes that will have identical logic for methods that operate on instance variables/properties.

There are really 3 ways to handle that:

  1. Inheritance.
  2. Duplicate the code (code smell "Duplicated code").
  3. Move the logic to yet another class (code smells "Lazy Class," "Middle Man," "Message Chains," and/or "Inappropriate Intimacy").

Now, there can be misuse of inheritance. For example, Java has the classes InputStream and OutputStream. Subclasses of these are used to read/write files, sockets, arrays, strings, and several are used to wrap other input/output streams. Based on what they do, these should have been interfaces rather than classes.

R. Bemrose
A: 

One of the most useful ways I see to use inheritance is in GUI objects.

Brad Barker
+6  A: 

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.

Jerry Coffin