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.