Others have already answered, but perhaps some examples may help.
Python, for example, stores type information until runtime:
>>> def f(x): ... if type(x)==type(0): ... return (x+1,x) ... else: ... return (x,x) ... >>> f("hello") ('hello', 'hello') >>> f(10) (11, 10)
The function above, taking any argument x into account, returns a pair (x,x) , unless x is of type int . The function checks this type at runtime, and if x turns out to be int , it behaves in a special way, returning instead (x+1, x) .
To implement the above, the Python runtime must track types. That is, when we do
>>> x = 5
Python cannot just store a representation of byte 5 in memory. It is also necessary to mark this view with an int tag, so that when we make type(x) , the tag can be restored.
Next, before performing any operation such as x+1 , Python must check the type tag to make sure that we are actually working on int s. If x is, for example, str ing, Python will throw an exception.
Statically verified languages, such as Java, do not need such checks at runtime. For example, when we run
SomeClass x = new SomeClass(42); x.foo();
the compiler already checked there really the foo method for x at compile time, so there is no need to repeat this again. This can, in principle, increase productivity. (In fact, the JVM does some runtime checks during class loading, but let it just ignore them)
Notwithstanding the above, Java should store type tags such as Python, since it has type(-) similar:
if (x instanceof SomeClass) { ...
Therefore, Java allows you to write functions that can behave "specifically" for certain types.
The above foo() function simply returns its argument, unless it is of type B , for which a new object is created instead. This is a consequence of using instanceof , which requires each object to carry a tag at runtime.
Honestly, such a tag is already present in order to be able to implement virtual methods, so it costs nothing more. However, the presence of instanceof allows you to call the above uneven behavior on types - some types can be handled differently.
Haskell instead does not have such a type/instanceof operator. Haskell parametric function of type
foo :: a -> (a,a)
should behave the same on all types. There is no way to cause any kind of "special" behavior. Specifically, foo x should return (x,x) , and we can see that just by looking at the annotation like above. To emphasize, there is no need to look at the code (!!) to prove such a property. This is what provides parametricity from the type indicated above.