This page contains an archived post to the Design Forum (formerly called the Flexible Java Forum) made prior to February 25, 2002.
If you wish to participate in discussions, please visit the new
Inheritance, composition, and interfaces
Posted by Pierre-Antoine Champin on 02 Dec 1998, 4:02 PM
I received this e-mail from Pierre-Antoine Champin, which
I thought everyone here might find interesting. I'm posting
it here with Pierre-Antoine's permission. - Bill Venners
I just read your last two articles in JavaWorld, with great interest.
Nevertheless, I don't *quite* agree with you on a few points I would be happy
to have your comments on...
Not to get confused, when I'll talk about inheritence, it will be in a
conceptual, language independant point of view. I will write "java-inheritance"
when I speak about the language-specific feature.
First I am a bit confused by your considering together composition and
inheritance; and well, an Apple with an attribute Fruit seems to me a bit
(don't mind me writing) anti-object, isn't it ?
I was reliefed when I finally read that inheritance stands for an "is-a"
relationship an ONLY in that case (not to get code re-use alone nor
polymorphism alone). But that is so true to me that I didn't even thought of
it as a problem... but then again you raised some interesting problems:
- inheritance provides 'week encapsulation', which makes subclasses (and code
using them) very affected by inteface modification in the superclass. But
that problem still exists with the use of Interfaces. And what about
maintaining both interfaces (in all classes or only subclasses, depending on
the needs) of 'deprectaded' API's - which is the solution Sun uses between
differents versions of Java.
Another point is: in your example of the Fruit and the Apple, with composition,
you can alter Fruit's implementation without modifying the Example application.
But if you have many subclasses, you'll have a lot of code to change, which
inheritance tends to avoid - that's the point of code re-use too.
- the is-a relationship can vary in the time : I would say then that the choice
of the classes is not good : if, in an application, a Person which is en
Employee can become unemployed or if the application may use Employee's methods
without using the Person instance behind the Employee, then I'd rather use a
class Job (with a composition relation with Person) than a class Employee.
- this problem you didn't raise, and I've been thinking of it for a time
without ever reading something about that; I call it "inheritance insertion".
What if I have classes Dog and Bird inheriting a class Animal, and that for
some reason I want to add a class Cat. Cat would inherit Animal, but that would
be great to have a class Mammal instead, inheriting Animal and inherited by
both Cat AND Dog...
If I have the source code of Dog, I may have a lot of cut-paste work...
If I don't, then all I can do is write to the author...
If all that happens at runtime, then this is even more itchy !
Your approach of replacing inheritance with composition may give me some way of
solving that problem... but once again that looks kind of anti-objects !
May be too the magical package java.lang.reflect may help in some way - adding
at least an INTERFACE Mammal to classes Cat and Dog? - but I didn't have time
As you point it, there are 2 aspects in inheritance :
- code re-use, achieved by composition or java-inheritance
- polymorphism, achieved by java-inheritance or interface
Java inheritance allows both, or polymorphism alone with abstract classes,
but Java classes, unlike interfaces, don't allow multiple inheritance - and
that's a point I still don't get.
I sure know about the diamond problem (say B1->A, B2->A and C->B1,B2),
providing ambiguity in interface (B1 and B2 having identical methods) and
implementation (does A's implementation occur once or twice in C).
But I think - maybe naively - that the compiler could force the solving of
interface ambiguity (just as it force the implementation of abstract methods in
non abstract classes), or that a convention could be decided (based on the
order of the superclasses, like in Python, by example).
And for the implementation problem, if inheritance is a strict 'is-a'
relationship, then A's implementation SHOULD occur once in C. Someone could
argue that consistence in A's implementation could be broken by concurent use
of B1 and B2; but that kind of critical implementation should normally be
private and its consistence be checked entirely inside A itself.
You bring as argument that Java philosophy is to separate interface from
implementation, which is good. In other words (pardon me if I betray your
words), Java is more concerned in polymorphism than in code re-use. But then
why even providing the 'extends' keyword? Everything could be done by only
You wrote you never used multiple inheritance in C++, which surpised me a bit.
May be it's because I used C++ after I learned Java, but I did use multiple
inheritance and polymorphism in C++ a lot, and I appreciated much code
re-using - even if I fancy java much more than C++ in the end ;)
On the other hand, I'm writing a Java application where I have had to write
some artificial class Foo_Implementation, which I instanciate as an attribute,
just to avoid copying entire methods in several classes implementing interface
Foo in just the same way.
Again, it's a good thing to make Foo an Interface, so it can be implemented
in many different ways by different classes - I agree with that. But that
would be good too to allow different classes to INHERIT some TypicalFoo class
and avoid a lot of copied code which makes coding AND maintainance painful.
That's all folks !
I hope you didn't mind me writing so long, but I'm deeply concerned and
interested in the subject.
thanks for reading