There are many types of polymorphism in the world:
* Internal vs External
* Parametric (generic) vs Subtype ("inheritance") vs Ad-Hoc (explicit enumeration)
Others may construct other taxonomies on the subject; I consider Luca Cardelli's On Understanding Types to be an excellent resource.
At any rate, the internal/external and parametric/subtype/ad-hoc axes are orthogonal; meaningful examples of each kind exist:
Overridding of inherited virtual functions (or abstract function specficiations--the bread and butter of OO) is internal subtype polymorphism.
Multi-Methods, ala CLOS or Dylan, are an example of external subtype polymorphism.
Templates (generics are examples of parametric polymorphism. In C++, Java, and other OO languages with generics, this can be internal; it is generally external in functional languages.
Pattern matching is a common example of internal ad-hoc polymorphism. Function/operator overloading is also ad-hoc polymorhism, and can be internal or external depending on the language (C++, for instance, allows either).
And finally, the procedural control structures (if, case) are time-honored ways of implementing external ad-hoc polymorphism. (Table-oriented programming is another way as well, though nobody other than topmind seems to use it. :)
The OO uber-zealotry that I refer to in the title of this message is the notion (which seems to spring from the Smalltalk community) that internal polymorphism is good, external polymorphism is bad--that any decision-making should be implemented through inheritance and specialization. (The communities of other OO languages--C++ and Java, and even Smalltalk-derived scripting languages like Python or Ruby, seem to have less of an issue with this).
Needless to say, I consider this a questionable stance to take. In many cases, decisions made by software which might be made on the type (or identity) of an object, are made in modules other than where the object is defined--and are only of concern to that particular module or application. 'Tis better, I think, to keep local concerns local, then burden an object definition with every possibly contingency in every possible application or domain the object might be useful in--which might be a very large set.
While internal polymorphism is a great thing to have and use--so is external polymorphism. One thing I like about C++ (despite its numerous flaws) is it doesn't force me into one style or another--I can define templates, overloaded operators, and such either within a class definition, or outside it. Many other languages make this more difficult. (Of course, C++ operator overloading is broken in the presence of subtypes--CLOS style multimethods would be preferable to the C++ implementation, which uses the declared static type of a term rather than the actual type of the object).