Generics in JavaScript

// As an example of a generic function, `slicesIndex` takes
// an array of any type and an element of that type and returns
// the index of the first occurrence of v in arr, or -1 if not present.
function slicesIndex(arr, v) {
    for (let i = 0; i < arr.length; i++) {
        if (v === arr[i]) {
            return i;
        }
    }
    return -1;
}

// As an example of a generic class, `List` is a
// singly-linked list with values of any type.
class List {
    constructor() {
        this.head = null;
        this.tail = null;
    }

    // We can define methods on generic types just like we
    // do on regular types in JavaScript.
    push(v) {
        const newElement = { val: v, next: null };
        if (this.tail === null) {
            this.head = newElement;
            this.tail = newElement;
        } else {
            this.tail.next = newElement;
            this.tail = newElement;
        }
    }

    // AllElements returns all the List elements as an array.
    allElements() {
        const elems = [];
        let current = this.head;
        while (current !== null) {
            elems.push(current.val);
            current = current.next;
        }
        return elems;
    }
}

// Main function to demonstrate the usage
function main() {
    const s = ["foo", "bar", "zoo"];

    // When invoking functions in JavaScript, we don't need
    // to specify types as JavaScript is dynamically typed.
    console.log("index of zoo:", slicesIndex(s, "zoo"));

    const lst = new List();
    lst.push(10);
    lst.push(13);
    lst.push(23);
    console.log("list:", lst.allElements());
}

main();

This JavaScript code demonstrates concepts similar to generics in languages with static typing. Here are some key points about the translation:

  1. JavaScript is dynamically typed, so we don’t need to declare type parameters explicitly. The slicesIndex function works with arrays of any type.

  2. The List class is implemented as a generic data structure in JavaScript. It can hold elements of any type.

  3. We don’t need to specify type constraints (like comparable in the original example) as JavaScript allows comparison of any types with ===.

  4. The push and allElements methods are defined directly on the List class, without needing to specify type parameters.

  5. In the main function, we can use these “generic” structures and functions without explicitly specifying types.

To run this JavaScript program:

$ node generics.js
index of zoo: 2
list: [ 10, 13, 23 ]

This example demonstrates how JavaScript’s dynamic typing naturally supports generic-like behavior, although it doesn’t have explicit generic syntax like statically-typed languages.