HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Is subtype polymorphism a kind of ad hoc polymorphism?

Submitted by: @import:stackexchange-cs··
0
Viewed 0 times
kindsubtypepolymorphismhoc

Problem

"Ad-hoc polymorphism is obtained when a function works, or appears to work, on several different types (which may not exhibit a common structure) and may behave in unrelated ways for each type." – Strachey 1967

Subtype polymorphism seems to fit this description, albeit usually with late binding on the type that dictates the function's behavior. In Java, for example, the toString function works on any object at all, but has many wholly distinct implementations which are distinguished from one another based on the runtime type of the object; i.e., any class can override it and create a new ad hoc definition.

But when I poke around online, I usually find people making a sharp distinction between subtype polymorphism and ad hoc polymorphism; they are treated as wholly different beasts. Would it be correct to say that subtype polymorphism is a kind of ad hoc polymorphism? If not, why not?

Solution

Keep in mind that, in PL lingo, the term "polymorphism" is used for different notions.

In OOP, polymorphism usually means subtype polymorphism. If we have a function foo(x: A) we can call foo with any object having a subtype of A. In this way, the function is defined only once but can operate on "many types" -- which justifies the usage of the word "polymorphism".

In functional programming, we often do not have subtypes. Still functions can have a universally quantified type such as bar : forall a b, a -> b -> a. This function can take two arguments of any types a and b (chosen by the caller), and return a value of type a. Hence, this is called a polymorphic function.
In some OOP languages, a similar feature can be found with the name of "generic function", e.g. A bar(A a, B b) in Java. We can call also this feature "parametric polymorphism".

There is a terminology mismatch here since OOP decided to use the "polymorphism" term to refer to the subtyping one, hence it needed a new term for "parametric polymorphism".

Anyway, in parametric polymorphism, values of the "unknown" quantified types a,b can not be concretely used (since we do not know what they are), but can be merely passed around. This is why bar above must be the projection of its first argument: the function has no other way to produce a return value of type a except to reuse its first argument. Similarly, baz : forall a, a->a must be the identity function.

In real-world languages, sometimes parametric polymorphism is broken by some specific constructs in the language. Minor offenders are

  • non termination: infinite loops / recursion allows to write a baz : forall a, a->a which never terminates, hence it differs from the identity function.



  • exceptions / runtime errors: similar to non termination.



  • null values: if null is a value of any type a, that can be returned by baz as well, making it differ from the identity.



When these are present, one still obtains a weaker form of parametric polymorphism. Worse offenders are

  • checked type casts / instanceof



  • reflection



Indeed, consider this pseudo-Java code

 baz(A x) {
  if (x instanceof Integer)
     return (x+1);    // Some casting omitted to make this work
  else
     return x;
}


This is the identity function on all types, except Integer where it does something arbitrarily different. The function above is ugly: it does not handle the x argument as an argument of an unknown type. It actually checks the type of x at runtime and makes decisions on that. We no longer have parametric polymorphism here, since type A is not handled in a "uniform" way: the A=Integer is now "special".

What we get, instead, is just a function which can act on each type A (so it is still polymorphic) but which on each A can have a completely unrelated behavior. In a sense, it is just an unconstrained family of functions, indexed over a type $A$. This is what we call "ad hoc polymorphism".

Code Snippets

<A> baz(A x) {
  if (x instanceof Integer)
     return (x+1);    // Some casting omitted to make this work
  else
     return x;
}

Context

StackExchange Computer Science Q#82485, answer score: 5

Revisions (0)

No revisions yet.