inheritance is not for code-reuse (??)

?

=?iso-8859-1?q?Kirit_S=E6lensminde?=

I remember reading on parashift recently, that "Composition is for code
reuse, inheritance is for flexibility" see
(http://www.parashift.com/c++-faq-lite/smalltalk.html#faq-30.4)

This confused me somewhat as I have always thought you get code reuse
"for free" with inheritance. Am I missing something?. Will someone care
to explain ??

The object models of Smalltalk and C++ have one big difference.
Smalltalk uses something called operational polymorphism, often these
days called duck typing. C++ on the other hand uses inclusional
polymorphism which is a form of type constraint.

This basic difference in the type models/message dispatchers in the
two languages makes a huge difference in how classes are used in
practice, even though they can both be shown to be equivalent (like a
Turing machine being provably equivalent to Church's lambda calculus -
they're the same in one sense, but the way a problem is approached in
each is still completely different).

I think the FAQ is only half right. Most people most of the time use
classes in the way that the FAQ describes in the two languages, but
this is really habitual rather than imposed by the object models of
the languages.

You do get code re-use for free with inheritance, but to get the sort
of re-use you get with Smalltalk in C++ you have to use templates. The
STL makes use of re-use in (pretty much) the same way that the
Smalltalk containers do.

In C++ though a class hierarchy is most often used to constrain the
types that a function will use (and Java uses hierarchy in this way
too). This constraint cannot be used in Smalltalk whose message
dispatcher ignores the actual type of the receiver (well, of course it
doesn't exactly, but compared to C++ it does).

I've not really read through the C++ FAQ's comparison with Smalltalk
before and I'm not entirely sure that it is explained as well as it
could be. Something I'll have to study and think about.

I'm not sure if this really answers your question or not either. The
two languages are quite different in the ways that they are normally
used, but each language can "meet the other" if the context is right.


K
 
J

James Kanze

I remember reading on parashift recently, that "Composition is for code
reuse, inheritance is for flexibility" see
(http://www.parashift.com/c++-faq-lite/smalltalk.html#faq-30.4)
This confused me somewhat as I have always thought you get code reuse
"for free" with inheritance. Am I missing something?. Will someone care
to explain ??

It depends on what you use inheritance for. In most modern OO
langauges (C++, but also Java, C#, Eiffel, Ada 95...), most
inheritance is inheritance of interface ; a class implements a
specific interface.

In older OO languages (e.g. Smalltalk), there was no static type
checking, and so no need for inheritance of interface. (Put in
other words: you find out about your errors at run-time, not at
compile time.) Historically, too, the coupling inherent in
inheritance wasn't recognized when OO was young, so inheritance
was used a lot when today we would prefer composition.

Basically, code reuse occurs when class A contains an instance
of class B, whether it be by inheritance or composition, and
class B contains implementation code used in the implementation
of class A. Because inheritance implies stronger coupling than
composition, composition is preferred IF all other things are
equal. If they aren't inheritance can be, and still is, used
for this; in C++, such inheritance is generally private.

In most cases of public inheritance (but there are exceptions,
e.g. the templat pattern), the base class contains no
implementation code; it only defines an interface. (It may
contain code defining this interface, for example verifying pre-
or post-conditions.)
 
J

Jim Langston

Bart Simpson said:
I remember reading on parashift recently, that "Composition is for code
reuse, inheritance is for flexibility" see
(http://www.parashift.com/c++-faq-lite/smalltalk.html#faq-30.4)

This confused me somewhat as I have always thought you get code reuse "for
free" with inheritance. Am I missing something?. Will someone care to
explain ??

I don't know for sure, can only say my own thoughts.

When a class is designed with inheritance, that's what it's designed for.
The bases and derives usually get coupled fairly tightly unless you
purposely try not to (and I guess are using Composition, whatever that is
:D ).

A base class is usually specifically designed for the types of derived
classes that will use it. Additionally, derived classes are usually
specifically designed for the base class they derive from.

The problem comes in when in another program you decide to try to reuse a
polymorphic class for another purpose. You'll usually wind up redesigning a
good portion of the base class and have to create a new derived class.
Unless you specifically design the base class to be more generic.
 
?

=?iso-8859-1?q?Kirit_S=E6lensminde?=

... unless you
purposely try not to (and I guess are using Composition, whatever that is
:D ).

Inheritance:

MyList : private std::list< int > {
public:
using begin();
};


Composition:

MyList {
public:
iterator begin() { return m_list.begin(); }
private:
std::list< int > m_list;
};


Composition is more work (or at least more typing), but the designs
are generally better. To derive from list non-privately (protected
might just barely be OK) in this sort of situation should be
considered an error (even if it doesn't cause bugs).

Smalltalk doesn't have private inheritance and it doesn't have
inclusional polymorphism so the issues are somewhat different in that
language.


K
 
G

Greg Herlihy

I remember reading on parashift recently, that "Composition is for code
reuse, inheritance is for flexibility" see
(http://www.parashift.com/c++-faq-lite/smalltalk.html#faq-30.4)

This confused me somewhat as I have always thought you get code reuse
"for free" with inheritance. Am I missing something?. Will someone care
to explain ??

"C++ Coding Standards" (Sutter and Alexandrescu) explains the
reasoning behind this advice, and cites as its basis, the "Liskov
Substitution Principle". Essentially, the LSP states that inheritiance
implies substitutability. So if A is a B, then A may inherit from B,
but if A just wants to re-use B's code, then A should make B a class
member.

I can also endorse this advice from my own experience. Having once
worked on a large software project that made heavy use of inheritance,
I can attest to the problems that can arise if perfect
substitutability is not required of a derived type. Without
substitutability, the small differences between base and derived
objects lead either to subtle bugs or otherwise require special
handling that violates encapsulation and that often requires a type-
specific implementation.

In fact, I would describe the problem like this: when inheriting from
a base class, the derived class effectively re-uses all of the base
class's implementation. But it is often the case that the programmer
really wants to re-use only a portion of the base's code - and not its
entire implementation. So what often happens in this situation is that
the programmer has to write code to prevent the derived class from re-
using code in the base class in ways that were neither anticipated nor
intended - so the programmer winds up writing more code - not less.

Greg
 
D

Dave Rahardja

In fact, I would describe the problem like this: when inheriting from
a base class, the derived class effectively re-uses all of the base
class's implementation. But it is often the case that the programmer
really wants to re-use only a portion of the base's code - and not its
entire implementation. So what often happens in this situation is that
the programmer has to write code to prevent the derived class from re-
using code in the base class in ways that were neither anticipated nor
intended - so the programmer winds up writing more code - not less.

I too have encountered projects where public inheritance is used simply to
reuse code, without regard to the LSP. The problem is that such use leads very
quickly to "meaningless" (semantically nonsensical) relationships, which are
impossible to extend any further, and are likely to break algorithms that use
the base class as an abstraction. Whatever reuse you get out of the
inheritance relationship is usually small compared to the fact that you can no
longer use the base class as an abstraction in the rest of your program.

The LSP guarantees that inherited classes will not break algorithms that refer
to base classes polymorphically. This is the basis of a large portion of
successful real-world algorithm reuse that I have encountered.

Composition allows you to use existing code without subverting their
inheritance relationship. The new class you create can be part of a completely
separate inheritance tree, yet use all the facilities of the class you reuse.

-dr
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top