Register to get access to free programming courses with interactive exercises

Parametric polymorphism JS: Polymorphism

The word “polymorphism” can mean different things depending on the context. When programmers in imperative languages talk about polymorphism, they usually mean “polymorphism of subtypes”. At the same time, programmers in functional languages have “parametric polymorphism” in mind. Let's talk about the latter.

We'll see Java code in this lesson. Don't worry if you don't fully understand it. Our goal is to deal with concepts, not Java.

The lodash library has the _.concat() function, which combines arrays passed to it:

_.concat([1], [2, 3, 1]); // [1, 2, 3, 1]
_.concat(['one'], ['two', 'three']); // ['one', 'two', 'three']
_.concat([true], [false, false, true]); // [true, false, false, true]

This function joins any array, regardless of the type of data contained within. Let's try to implement it ourselves.

// This is a slightly stripped-down version of the concat function, it only works with two arguments,
// each of which is an array
// The function creates a new array, then traverses the passed arrays one by one,
// and adds their values to the newly created array. Then it returns the result.
const concat = (coll1, coll2) => {
    const result = [];
    coll1.forEach((value) => result.push(value));
    coll2.forEach((value) => result.push(value));
    return result;
};

Take a close look at this code. Does it perform any operations on the data inside the array? The correct answer is no. This data is moved from one array to another, but no action is performed on it. Our new concat() function, like the original _.concat() function, can handle arrays containing any type of data.

For developers who've only written in dynamic languages, this behavior seems natural, but in static languages it's not so simple. Below is an example of the definition of arrays in Java:

int numbers[] = {3, 1, 2, 5, 4}; 
String words[] = {"one", "two", "three"}; 

The first thing you might notice is the need to specify the type. For the first array, it's int , for the second, it's String. You can't create an array without specifying the what type its values will have. The same applies to functions that process arrays:

class Main {
    public static void main(String[] args) {
        // Declaring array a
        int[] a = {1, 2, 3, 4};
        // Declaring array b
        int[] b = {4, 16, 1, 2, 3, 22};

        // Merging arrays
        concat(a, b);
    }

    // Arrays containing only int can be input
    public static int[] concat(int[] arr1, int[] arr2) {
        // Create a resulting array whose length is equal to the sum of the lengths of the original arrays
        int[] result = new int[arr1.length + arr2.length];

        // Transfer all values from the first array to result
        for (int i = 0; i < arr1.length; i++) { 
           result[i] = arr1[i];
        } 

        // Transfer all values from the second array to result
        for (int j = 0; j < arr2.length; j++) { 
           result[arr1.length + j] = arr2[j];
        }

        return result;
    }
}

Note the signature of the concat() method: concat(): int[] concat(int[] arr1, int[] arr2). In contrast to the JavaScript variant, the input parameters here are arrays of numbers. I.e., this function won't work for an array of strings. Nor will it work for all other data types.

What does this mean in practice? Something very simple, and very sad. We have to implement a similar function for each type even though the algorithm inside is absolutely identical.

This is where parametric polymorphism comes in handy. Static languages have to introduce special constructions into the language to allow these algorithms to be described without regard to the type of parameter. In some languages, they're called templates (C++) or generics (Java, C#):

class Main {
  public static void main(String[] args) {
    Integer[] a = {1, 2, 3, 4};
    Integer[] b = {4, 16, 1, 2, 3, 22};
    concat(a, b);
  }

  public static<T> T[] concat(T[] arr1, T[] arr2) {
      T[] result = (T[]) new Object[arr1.length + arr2.length];

      for (int i = 0; i < arr1.length; i++) { 
         result[i] = arr1[i];
      } 

      for (int j = 0; j < arr2.length; j++) {
         result[arr1.length + j] = arr2[j];
      }

      return result;
  }
}

In this code, we can see a type called T, which simply means it can be used with any type within an array. The concat() method now works like its JavaScript counterpart.

Parametric polymorphism makes it possible to write generalized algorithms for composite types, which in some cases greatly reduces the amount of code. Sometimes, this comes at the expense of having a simple solution, but for most typical operations you won't see an increase in complexity. You can see that in the code above.

Dynamic languages don't need parametric polymorphism to implement generalized algorithms. Any collection can contain any type of data at any time. This eliminates the need to introduce additional language constructs and learn new concepts.

In the literature, the use of parametric polymorphism is often called generalized programming.


Hexlet Experts

Are there any more questions? Ask them in the Discussion section.

The Hexlet support team or other students will answer you.

About Hexlet learning process

For full access to the course you need a professional subscription.

A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.

Get access
130
courses
1000
exercises
2000+
hours of theory
3200
tests

Sign up

Programming courses for beginners and experienced developers. Start training for free

  • 130 courses, 2000+ hours of theory
  • 1000 practical tasks in a browser
  • 360 000 students
By sending this form, you agree to our Personal Policy and Service Conditions

Our graduates work in companies:

<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.bookmate">Bookmate</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.healthsamurai">Healthsamurai</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.dualboot">Dualboot</span>
<span class="translation_missing" title="translation missing: en.web.courses.lessons.registration.abbyy">Abbyy</span>
Suggested learning programs

From a novice to a developer. Get a job or your money back!

Frontend Developer icon
Profession
beginner
Development of front-end components for web applications
start anytime 10 months

Use Hexlet to the fullest extent!

  • Ask questions about the lesson
  • Test your knowledge in quizzes
  • Practice in your browser
  • Track your progress

Sign up or sign in

By sending this form, you agree to our Personal Policy and Service Conditions
Toto Image

Ask questions if you want to discuss a theory or an exercise. Hexlet Support Team and experienced community members can help find answers and solve a problem.