DEV Community

What the heck is polymorphism?

Jan van Brügge on February 23, 2019

Polymorphism is the idea of defining data structures or algorithms in general, so you can use them for more than one data type. The complete answer...
Collapse
 
hiasltiasl profile image
Matthias Perktold • Edited

Thanks for this!

Regarding subtype polymorphism, I think you can use type classes to achieve something similar.
For instance, the type class for your Vehicle example would look like:

class Vehicle v where
    getWeight :: v -> Int

Each 'subtype' can then be modelled as an instance of Vehicle that implements the getWeight function accordingly.

Now I'm far from a Haskell expert, so what do you think about this relation between subtype polymorphism and type classes?

You can also view it from the other side: If you want to model a Haskell type class in Java, you would use an interface, i.e. subtype polymorphism.

For instance, if we take the Functor type class with the fmap function, we would introduce a Functor<T> interface with an fmap method. Functor instances would then be modelled as classes that implement the Functor interface.

Collapse
 
jvanbruegge profile image
Jan van Brügge • Edited

Yeah, you can emulate parts of it with ad-hoc polymorphism, but it remains an approximation because type classes are more like interfaces and not like base classes. You can't do something like super.getWeight().

On the other hands interfaces (at least in Java) are not powerful enough to model type classes either. For simple type classes like Semigroup or Monoid this works perfectly:

class Semigroup a where
    (<>) :: a -> a -> a

class Semigroup a => Monoid a where
    mempty :: a

and in Java:

public interface Semigroup<T> {
    T combine(T a, T b);
}

public interface Monoid<T> extends Semigroup<T> {
    T mempty();
}

The problem is the more complicated type classes like Functor or Monad. More specifically the type classes that use higher kinded types. You see above that the a from the Monoid definition is directly used in the type signature. This means it can only have the kind Type. But take the definition of Functor for example:

class Functor f where
    fmap :: (a -> b) -> f a -> f b

The f is not directly used, but it is partially applied to another type. This means that f has kind Type -> Type, ie it is a type constructor. In Java this would mean that you would need a generic generic type, something like this:

public interface Functor<F<?>> {
    <A,B> F<B> fmap(Function<A, B> f, F<A> x);
}

which is not valid Java at all.

Collapse
 
hiasltiasl profile image
Matthias Perktold

Thanks for the detailed answer!

You are right, even though the two concepts overlap a bit, there is quite some mismatch.

Collapse
 
wongjiahau profile image
WJH • Edited

Nice article! It helps me a lot on contemplating about the design of my programming language.

I kind of understand every category of polymorphism you mentioned, but I still couldn’t understand how can higher-rank polymorphism is useful.

So, do you mind to provide any practical example of higher rank polymorphism (It would be better if the example you provided is actually used in industrial code, not just in the academia)

Collapse
 
jvanbruegge profile image
Jan van Brügge

Yes, I've added a paragraph about the ST trick there. Another possible use case would be callback functions that receive data from your API:

withHook: (forall a. IsApiData a => a -> IO ()) -> IO ()

This allows withHook to send any data to the callback that implements the IsApiData type class

Collapse
 
drbearhands profile image
DrBearhands

I'm confused, isn't this ad-hoc (or 'first-rank' I guess) as it only quantifies over a?

Thread Thread
 
jvanbruegge profile image
Jan van Brügge

No, as you can see the forall is in the parenthesis, the scope does not go until the return type

Thread Thread
 
drbearhands profile image
DrBearhands

herp derp, realized it myself just now, ∀x(P(x))->Q ≠ ∀x(P(x)->Q).

So this would require an an ad-hoc polymorphic function as argument, yes?

Thread Thread
 
jvanbruegge profile image
Jan van Brügge

Correct 👍

Collapse
 
jacksonelfers profile image
Jackson Elfers

Ever read animorphs?

Collapse
 
jvanbruegge profile image
Jan van Brügge

No, I haven't 😅

Collapse
 
jacksonelfers profile image
Jackson Elfers • Edited

It's a children's book that people like to poke fun at for its hilarious cover art. I always imagine it when I think of polymorphism and it gives me a good chuckle. Might be a bit of a non sequitur. 😁 Great article btw.

Collapse
 
rhymes profile image
rhymes

Great article Jan, I knew of only a subset of them. Haskell definitely blows my mind :D

Collapse
 
jasontechnology profile image
Jason.Technology

Us grey beards call that a union :-)
geeksforgeeks.org/difference-struc...

Collapse
 
jvanbruegge profile image
Jan van Brügge • Edited

Call what a union? I don't see any way a C union could be considered polymorphic. It is basically just a convenience for casting.

Or do you mean that a union is as far as you can bring C's type system?

Collapse
 
madhadron profile image
Fred Ross

Not quite. It's implemented as a tagged union, but the power comes from building a full algebra that makes type composition trivial and very easy to reason about (thus the phrase "algebraic data type"). Their history goes back to the 1970's, so they're not much younger than C and they're older than object oriented programming.

Collapse
 
occipita profile image
occipita

"Their history goes back to the 1970's, so they're [...] older than object oriented programming."

Errr... Object oriented programming dates back to Simula 67, released in 1967 (or even further -- you can do OOP without language support, as long as your language supports indirect function calls, and there are anecdotal stories of people creating objects in assembly language all the way back to the 50s).

Collapse
 
wiltel492019 profile image
Wiltel492019

Great explaination. Of Haskell and or Code Computer Programming Language's.
AAS ITI MICHIGAN

Collapse
 
igrep profile image
YAMAMOTO Yuji

One of the most popular languages implementing row polymorphism is PureScript

How about OCaml?