"Thomas G. Marshall"
/Almost/. Dynamically typed languages do not need inheritance for
polymorphism to exist.
A message is sent to an object, and that object is specified
by an expression.
expression.message( arguments )
Depending on the value of that expression, the receiver will
be determined; possibly late at runtime.
Possibly, the class (the form, the "morph") of the receiver is
not known until that determination. When there is more than
one ("poly-") possibility, the receiver is "polymorph".
In languages with static types, in order for this to be
allowed, all those types must be of a subtype of the type of
the expression. That's when inheritance (or
interface-implementation) is needed in Java.
In languages without static types, there is no need for
inheritance. The receiver, however, needs to be able to
understand the message sent. If not, a runtime "error" might
occur.
Depending on their type (class, form [morph]), different
receivers might have different interpretations ("methods") of
the same message.
One might go to two different restaurants and give the same
message to the waiter (order the dish with the same name) and
might get two different meals. If one wants to order a french
dish and makes sure that the restaurants receiving the message
indeed are of the type "french", one can be sure to get at
least something; which might still depend on the subtype of
the restaurant. The menu serves as the interface
specification, the kitchen is the implementation - usually
hidden.