Poly Morphism

Polymorphism

Same interface, different implementation. Substitutability.

Actually, I think this should be broader, because Parametric Polymorphism and other instances of code working differently in various contexts are also polymorphism. -- Panu Kalliokoski

Some have argued that parametric polymorphism that depends on the quantity of parameters is not really polymorphism because the interface is different. It is like calling a different method using quantity of parameters to distinguish a name collision instead of name alone.

"Parametric polymorphism" does not mean different behavior depending on the number of parameters. - That's overloading...

[so overloading is a basic form of function indirection]

If it only depends on the "types" of the parameters, then it does not contradict "same interface, different implementation". In that case, I don't understand the "broader" comment.

Well, the types of the parameters might have mutual requirements. For example, the identity (=) function requires (in ML-type languages) that its operands be of the same type, but they may be of whatever type as long as both are of the same one. The identity function is polymorphic, but you have to stretch the notion of "interface" (and implementation, substitutability) quite far to have the original description apply to this case.


I generally classify Poly Morphism into two conceptual categories: sub-type and utility polymorphism. In sub-type polymorphism, you have a taxonomy of mutually-exclusive sub-types or variations of something, and have a method or attribute name that is the same for each one. A classic example is a Shape class which is subclassed into Rectangle, Circle, etc. Each shape implements its own "draw" method. In other words, variations on a common theme.

The second type I call "utility polymorphism". Very different "kinds" of classes may have the same method or attribute. An example is "toString" where each class or object is required to provide a string representation of itself regardless of what its parent(s) is or what entity it represents.

Note that there may not be any clear-cut wall between these two kinds.


Luca Cardelli and Peter Wegner's paper On Understanding Types gives definitions of several kinds of polymorphism.


Polymorphism can be reduced to this. Suppose you have some function call f(x1, x2, x3, ...). If the semantics of the function call is polymorphic, then the x1, x2, ... values can have different types. If the semantics is polymorphic, then the arguments have to conform to a particular type signature, otherwise the expression is erroneous. Polymorphism can be static: the semantics of f are determined once based on the static properties of the expressions x1, x2, ... . Then each time the same function call is evaluated, the arguments always have the same type signature; the behavior of f can differ only because the values may be different. However, different instances of function calls that invoke f may have different type signatures. So in the subprogram f(x); f(y) static polymorphism may allow x to be an integer and y to be a string. But x must always be an integer, and y must always be a string. Under dynamic polymorphism, the arguments can have a different type signature each time the expression is evaluated. The function f can handle the type combinations, some of which may be valid, while others erroneous. Thus in the subprogram f(x); f(y) the types of x and y can vary each time that subprogram is invoked.

Polymorphism is a form of flexibility. If we take any system that has flexibility and dig through the layers, we find some inviolate, rigid substrate. For example, if we look closely at dynamic polymorphism as described above, we find that it works because types are represented as components of values, and at a deeper level, there is no polymorphism: the function call f accepts rigidly defined object references that contain a rigidly defined type field.

The static versus dynamic distinction occurs when the processing of a program is divided into stages, each of which produces output that serves as input to the next. Static polymorphism is really dynamic polymorphism which happens while the source code is being processed, but without being run. The processing program, often called a compiler, does work with the type information in a dynamic way. But when it is done, it produces a translation in which that information no longer plays a dynamic role, if it is preserved at all.

How does this definition work within the framework of Prototype Based Programming?

In prototype based programming and all object oriented programming a value and its behavior are combined in an object. Since the behavior is sent along with the value, the language is polymorphic.

It is also hard for me to apply this definition to "utility polymorphism", as described above. Further, "type" also lacks an agreed-upon definition (There Are No Types).

A type defines the behavior of a value. A language supports Poly Morphism when values of two different types can have identical behavior. For example, letting any aggregate type support a procedure named 'count' that returns the number of elements in the aggregate. Implementing polymorphism and static type checking can be tricky, but in a dynamic language it just works.

I see problems with the "identical behavior" statement. For example, in a game two different characters may respond to an "attack opponent" request differently. A dog monster may try to bite your head off while a cat monster may try to scratch you to death.


Some have suggested that functions are polymorphic because one can swap the implementation without changing the interface. I generally discard this usage of polymorphism as overly broad, but am interested in other opinions.

Please, do not speak in the first person on wiki, unless you sign. The unsigned portions tend to be a commonly agreed view or a view that is held by an important segment of the programming population. Who are you so important to "discard" certain usages or to classify other usages ? We already have Luca Cardellis authoritative classification for that.


In my attempt to define What Is Delegation, I came up with approximately this:

polymorphism = delegation + indirection

But this requires separate definitions of delegation and indirection. I thought I might have gone in a circle, but it seems polymorphism demands indirection (for flexibility), while the simplest possible delegation does not.

I came to the conclusion that delegation is done by the caller, while indirection is a function of (dispatch to) the callee.

So polymorphism follows from these elements combined: the caller delegates, and the callee indirects. Presto, the behavior is polymorphic.

Thus polymorphic object oriented behavior comes from: delegation via message sending, and indirection via object-centric message dispatch. It also implies (as before) that dispatch is a detail of indirection, not of delegation.

To make one further note here, I've been very careful to avoid mentioning "types" and such, since in a language where all non-primitive objects are the same "type" (such as Lua Language, in which all objects are type "table"), they are are not a prerequisite for polymorphic behavior. Polymorphous means literally "having multiple forms," but identifying and categorizing those forms is a separate problem (see What Are Types and There Are No Types). Types may be a useful implementation mechanism, and do even exist in a type-independent language in the Set Theory sense, but as I've defined it they aren't necessary for Poly Morphism.


Poly Morphism is the core of OOP, but it doesn't address one specific issue of real world OOP usage. I haven't seen any standard topic to address that issue anywhere, so I coined a term to represent it, and I try to propose it wherever I go. The behavior I'm looking for is Meta Morphism. -- uk

I don't think the consensus is that polymorphism is the "core" of OO. "Encapsulation" tends to score higher. See Oo Best Feature Poll.



See original on c2.com