Inheritance vs. Composition

Lately there's been a lot of discussion in certain programming communities about which method of object extension makes more sense: inheritance, or composition. Most of the time these discussions turn into debates, and when that happens developers tend to "take sides"--often moving towards extremist positions on the issue. I've been sort of quietly thinking about it all lately, trying to determine which use case warrants which approach. Here I show examples of both, explore some properties and consequences of both composition and inheritance, and finally talk about my own preferences.

Examples of Composition and Inheritance

Before talking about the consequences of inheritance vs. composition, some simple examples of both are needed. Here's a simplistic example of object composition (using Python, of course, as our demonstration language):

class UserDetails(object):
    email = "floguy@gmail.com"
    homepage = "http://www.eflorenzano.com"

class User(object):
    first_name = "Eric"
    last_name = "Florenzano"
    details = UserDetails()

Obviously these are not very useful classes, but the essential point is that we have created a namespace for each User object, "details", which contains the extra information about that particular user.

An example of the same objects, modified to use object inheritance might look as follows:

class User(object):
    first_name = "Eric"
    last_name = "Florenzano"

class UserDetails(User):
    email = "floguy@gmail.com"
    homepage = "http://www.eflorenzano.com"

Now we have a flat namespace, which contains all of the attributes from both of the objects. In the case of any collisions, Python will take the attribute from UserDetails.

Consequences

From a pure programming language complexity standpoint, object composition is the simpler of the two methods. In fact, the word "object" may not even apply here, as it's possible to achieve this type of composition using structs in C, which are clearly not objects in the sense that we think of them today.

Another immediate thing to notice is that with composition, there's no possibility of namespace clashes. There's no need to determine which attribute should "win", between the object and the composed object, as each attribute remains readily available.

The composed object, more often than not, has no knowledge about its containing class, so it can completely encapsulate its particular functionality. This also means that it cannot make any assumptions about its containing class, and the entire scheme can be considered less brittle. Change an attribute or method on User? That's fine, since UserDetails doesn't know or care about User at all.

That being said, object inheritance is arguably more straightforward. After all, an e-mail address isn't a logical property of some real-world object called a "UserDetails". No--it's a property of a user--so it makes more sense to make it an attribute on our virtual equivalent, the User class.

Object inheritance is also a more commonly-understood idea. Asking a typical developer about object composition will most likely result in some mumbling and deflection, whereas the same question about object inheritance will probably reveal a whole host of opinions and experience. That's not to say that composition is some sort of dark art, but simply that it's less commonly talked about in so many words.

As more of a sidenote than anything else, inheritance can be speedier in some compiled languages due to some compile-time optimizations vs. the dynamic lookup that composition requires. Of course, in Java you can't escape the dynamic method lookup, and in Python it's all a moot point.

My Preferences

In general, I find object composition to be desirable. I've seen too many projects get incredibly (and unnecessarily) confusing due to complicated inheritance hierarchies. However, there are some cases where inheritance simply makes more sense logically and programmatically. These are typically the cases where an object has been broken into so many subcomponents that it doesn't make sense any more as an object itself.

The Django web framework has an interesting way of dealing with model inheritance, and I think that more projects should follow its example. It uses composition behind the scenes, and then flattens the namespace according to typical inheritance rules. However, that composition still exists under the covers, so that that method may be used instead.

The answer is not going to be "composition always" or "inheritance always" or even any combination of the two, "always". Each has its own drawbacks and advantages and those should be considered before choosing an approach. More research needs to be done on the hybrid approaches, as well, because things like what Django is doing will provide more answers to more people than traditional approaches. Cheers to continued thought about these problems and to challenging conventional thought!

23 Comments So Far...

By schmichael at 9:22 p.m. on May 4, 2008

I may have only taught 2 CS classes as an adjunct professor, but the purist in me just has to speak out:

Inheritance represents an "is-a" relationship between the parent and child object.

UserDetail is a User.

Object compesition is a "has-a" relationship. If Email were a class in this example, you would have:

UserDetail has an Email.

Obviously UserDetail shouldn't inherit from Email because a User is not an Email.

Anyway, I'm working in the real world now, so I could be remembering the is-a/has-a stuff all wrong. ;) It sounds good, right?

 

By Eric Florenzano at 11:12 p.m. on May 4, 2008

That's a good point, that inheritance is "is-a" and composition is "has-a".

It depends on how nitpicky you want to be, because technically each of those string attributes is a composed object as well, given that a string is a full object with methods, etc.

Also, when you start getting to things like RequestContext or something that doesn't map to a real-world noun, these "is-a" or "has-a" relationships start to get muddy.

But all of that being said, I do agree with you! It's a good thing to note.

 

By Adrian Kuhn at 12:43 a.m. on May 5, 2008

I'd like to raise another issue than isa and hasa.

The real issue in the inheritance vs composition discussion is delegation. If I, as an object, can not handle a message do whom do I delegate it? To my parents or to my friends? So, the question is do we delegate along an axis that will never change in our live (inheritance) or one that may change when necessary (composition)? Speaking in technical terms again, the difference between inheritance and composition is rather about "static" versus "dynamic" delegation than isa and hash.

 

By Alex at 3:34 a.m. on May 5, 2008

True, but how about the case where you have a User and you want to have an author, you can either do an Author is-a User, or a User has-an AuthorProfile, both are valid and represent the data accurately.

This was shameless stolen from Gulopine.

 

By frits at 9:23 a.m. on May 5, 2008

Exactly. And because inheritance implements the is-a relationship, it also could facilitate polymorphism. And where would we be without polymorphism?

 

By Raghu at 1:32 a.m. on May 5, 2008

Some times Compositon or Inheritence is not a choice.

Eg: Take a Car Engine and Car Tyre. The Car Object obviously have to be a composition than extend Engine or Tyre classes!

Decision seem to totally base on the problem we are modelling and not much that of a choice. Just my thoughts.

 

By kevin at 9:17 a.m. on May 5, 2008

eric,

In regards to composition and django, the one thing I would like to see supported someday, (but I don't have the chops to even attempt to add this to django itself), is the concept of partials.

"...A partial class is a fragment of a class definition;
partial classes allow to spread the definition of
a class over several modules. One location serves
as the original definition of the class..."

So in my experience with c# this works beautifully. Take the User model example - just create another User class file (w/in the same namespace) but with this keyword modifier, "public partial class User", then add the additional props, methods, etc that you need and this allows you to "extend" the model w/out altering (forking) the existing model.

A partial class library already exists over on cheeseshop, http://cheeseshop.python.org/pypi/partial/1.0

here's the announcement... http://groups.google.co.uk/group/comp.lang.python.announce/browse_thread/thread/5baee147eed7470e

 

By Eric Florenzano at 9:19 a.m. on May 5, 2008

This sounds a little bit like the idea of an "open" module in Ruby. I think that this is a really interesting idea, but one with some potentially dangerous consequences.

Maybe it's because it's foreign to me, but it seems like this could be abused horribly. Have you seen any kind of terrible debug situations with partials, or does it mostly work out fine?

 

By zahari at 5:13 p.m. on May 29, 2008

The "is-a" and "has-a" relationships are rules of thumb for me as well. I see that experienced software architects follow these naturally, without even thinking of them.

 

By Bob Haugen at 8:34 a.m. on April 30, 2009

Eric, I just ran into this old post while googling for django multi-table inheritance. At Pycon 2009, you said you disliked MTI (if I understood correctly). I have a use case that MTI fits nicely, while composition, abstract base classes or GenericForeignKeys do not. Wondered if you could expound a little more about problems you have had or seen with MTI?

Thanks.

 

By wholesale jewelry at 11:46 p.m. on May 7, 2009

Good site,it is really pretty nice,i have paid so much attention to ur site for along time.pls keep update ur site often,i will visit it often too.

 

By 925 silver jewelry at 2:31 a.m. on May 19, 2009

it is really pretty nice i will visit it often

 

By ben10 oyunları at 3:01 a.m. on May 25, 2009

he question is do we delegate along an axis that will never change in our live (inheritance) or one that may change when necessary (composition)? Speaking in technical terms again

 

By wow gold at 8:34 p.m. on June 9, 2009

This sounds a little bit like the idea of an "open" module in Ruby. I think that this is a really interesting idea, but one with some potentially dangerous consequences.

 

By plastic injection molding at 9:57 p.m. on June 13, 2009

Nice throught!

 

By Cheap WoW Gold at 5:05 a.m. on June 17, 2009

Well, a cool idea

 

By sexy lingerie at 8:04 p.m. on June 22, 2009

It is important especially because the these tricks will probably break with public API aggregation support.

 

By jordan shoes at 2:58 a.m. on June 25, 2009

Well, a cool idea

 

By jordan shoes at 2:58 a.m. on June 25, 2009

Nice throught!

 

By ugg boots at 2:59 a.m. on June 25, 2009

he question is do we delegate along an axis that will never change in our live (inheritance) or one that may change when necessary (composition)? Speaking in technical terms again

 

By nike shoes at 2:59 a.m. on June 25, 2009

it is really pretty nice i will visit it often

 

By tiffany jewellery at 3:01 a.m. on June 25, 2009

It is important especially because the these tricks will probably break with public API aggregation support.

 

By lingerie wholesale at 9:57 a.m. on June 28, 2009

Hope to know more important things regarding design from it.

 

Voice your opinion...