The term "polymorphism" is common in job interviews, exam questions and books on object-oriented programming and design. It really shouldn't be. Don't use it. There's always a better term.
Book learning
polymorphism (noun) theory, programming
A term used to describe a variable that may refer to objects whose class is not known at compile time and which respond at run time according to the actual class of the object to which they refer.The Free On-line Dictionary of Computing
If you've ever studied object-oriented design, then you have probably noticed that one of the first definitions taught is that of "polymorphism". Perhaps you think this is reasonable; afterall, polymorphism can be used to explain many traits of object-oriented languages.
For example, in Objective-C code where a single message is sent to an object, any object which responds to the message's selector can be exchanged for any other object that responds to that selector at runtime. The completely dynamic nature of Objective-C method lookup means that Objective-C is one of the most "polymorphic" languages in existence.
Programmers don't use the term
Given the broad scope for potential use, it may seem strange that few programmers ever really use the term "polymorphism". In fact, if you ever hear a programmer using the term, they're likely only doing it to try to sound like an execu-speak-bot. "We'll proactively synergize our existing product with technologies leveraging polymorphism!"
The reality is that "polymorphism" is never the correct description of why something is done. When it exists, polymorphism is a result of the specific implementation, it is not the reason for the implementation. But even when discussing how the implementation works, polymorphism is never the best term; it is less descriptive, less accurate and less related to the problems where it applies than other more common programming terms.
Let's look at where polymorphism could apply and why it never should.
Subclasses
The canonical example of polymorphism is normally a variable with a base-class type that is initialized as a sub-class. For example:
// Invoked in a regular block of code...
{
MySubClass *newObject = [[[MySubClass alloc] init] autorelease];
[SomeClass methodWantingMyClassObject:newObject];
}
// And then in the implementation of "SomeClass"...
+ (void)methodWantingMyClassObject:(MyClass *)object
{
[object myClassInstanceMethod];
}
In this example, MySubClass is a subclass of MyClass.
This could validly be called polymorphism — the MyClass variable is actually a different type (MySubClass) at runtime — but no one would ever say "here we're using polymorphism".
Instead, we call this what it is:
subclass noun
An alternate implementation of the interface of a base class. The subclass represents a more specific version of the more general base class by adding extra data and methods to the definition but retaining all data and methods from the base class.
By retaining the same data and set of methods, a subclass object is normally interchangeable with a base class object and can be indistinguishable without runtime type information.
Sometimes overriding, extending, deriving or (more broadly) inheritance may be the term used instead (depending on why the subclass was created and how the sentence is worded). Any comment about the what the invocation of myClassInstanceMethod is doing would read: "perform appropriate behavior depending on the subclass" but never "polymorphically do something, default or otherwise".
The term polymorphism implies that we might have switched an unrelated object into the place of the expected type. That isn't what inheritance hierarchies do. While there is more to object than just MyClass, it is also a MyClass instance. This is why the following code:
[object isKindOfClass:[MyClass class]]
returns YES if object is a MyClass or a MySubClass. MySubClass has all the same data as MyClass and all the same methods.
Yes, there is a mechanism that resolves a message sent to an object and invokes the correct implementation for the specific runtime type of the object. In Objective-C, this is the "messaging system". The equivalent in C++ is the vtable. You will never hear anyone call this the "polymorphism system" or the "polymorphic abstraction".
A collection of objects, where the type of the object is unimportant
In Objective-C, objects of type id are frequently used by collections classes (NSArray, NSDictionary, NSSet, etc) because these collection classes don't care what objects they are handling.
NSArray *array = [NSArray arrayWithObjects:someObject, someOtherObject, nil];
This usage does count as "polymorphism" because the exact class of someObject and someOtherObject doesn't need to be known at compile-time.
Most of the time, a programmer will simply say: "NSArray takes objects of type 'id'", and leave it at that. This is literally what happens; it is the best description.
If pressed for a more abstract description, the best term is actually:
generic programming
A style of computer programs where a part of the program is left variable or unknown, to be filled in at a later date.
Generic programming states that the code has been written to allow any object or, in the case of NSArray, any "first class" or NSObject. In contrast to the implied polymorphic case where the code is written to expect type "X" and you are expected to provide something that behaves like type "X", generic programming implies that the code doesn't care what type it is given and won't place any significant requirements on the type.
Using the term "generic" also relates this useage to other languages and setups where the generic use isn't polymorphic. For example, collections programming in C++ for the previous example might look like this:
std::vector<MyClass> array; array.push_back(someMyClassObject); array.push_back(someOtherMyClassObject);
This is still called "generic" programming. The definition of Class std::vector<T> doesn't know about MyClass, yet it's not really polymorphic because the type is known at compile time. C++ generic programming gets the type when the object is declared not when the Class is defined.
Unrelated substitutions
There is a final polymorphic case in Objective-C. There are extremely rare situations in Objective-C where an object of one class might be substituted with an object of an unrelated class. This isn't easily possible in less dynamic languages like C++ but the dynamic binding of selectors to method implementations in Objective-C permits some unique design solutions.
Examples of this type of solution include:
- NSProxy, which receives messages on behalf of another object at the other end of an NSConnection.
- NSKeyValueObserving constructed classes which intercept messages to Observed objects through "isa" swizzling so that NSKeyValueObserving notifications can be sent when data setting messages are received.
In these cases, the Objective-C messaging system is being extended. In the NSProxy case, the messaging system is extended to send messages to a remote location. In the NSKeyValueObserving case, it is extended to perform extra work when certain messages are received.
Since these cases involve the substitution of an unrelated class, they are the most deserving of the term of all the cases explored so far. Scour the documentation on them however, and you'll find that they are never described as such.
The reality is that these classes represent very special cases in programming. Due to their peculiarities, it is important to be specific about the design philosophy employed.
proxy (pattern)
an object of one class functioning as an interface to a different object, possibly of a different class
NSProxy explicitly notes its design approach in its name. Specifically, NSProxy is a "Remote Proxy".
NSKeyValueObserving constructed classes are always noted as "isa" swizzling — an Objective-C specific implementation approach used specifically to extend the messaging system. In essence, this approach wraps the observed class in another class which sends NSKeyValueObserving notifications when appropriate before invoking the underlying class' methods.
While this could be argued as being a "smart proxy" (a proxy object which performs tracking actions as references or messages to the underlying object are made or sent), wrapping objects which add runtime behavior are normally called "Decorators".
decorator (pattern)
an object of one class wrapping an object of another class at runtime, where the outer object exposes the same interface as the inner object.
This wrapping is done to introduce additional functionality to the inner object's interface.
So, while unrelated substitutions are genuinely polymorphism, the term is still rarely used in favor of being very clear and explicit about the underlying design rationale for these unusual cases.
Conclusion
Polymorphism isn't a very useful word. Programmers acknowledge this through their almost complete avoidance of the term in cases where it could technically apply.
Ask relevant questions in job interviews instead. Stop torturing poor computer science students with obfuscating terms that nobody uses. Use common terminology in books. Programming theory is dry and dull enough already.