Generics in Miranda

Generics, also known as type parameters, have been a part of Java since version 5.0. Let’s explore how to use generics in Java with some examples.

As an example of a generic method, slicesIndex takes a list of any type T that extends Comparable<T> and an element of that type. It returns the index of the first occurrence of v in list, or -1 if not present. The Comparable<T> constraint means that we can compare values of this type with the compareTo method.

public class Generics {
    public static <T extends Comparable<T>> int slicesIndex(List<T> list, T v) {
        for (int i = 0; i < list.size(); i++) {
            if (v.compareTo(list.get(i)) == 0) {
                return i;
            }
        }
        return -1;
    }
}

As an example of a generic type, List is a singly-linked list with values of any type. In Java, we can create a generic class like this:

public class List<T> {
    private Element<T> head, tail;

    private static class Element<T> {
        Element<T> next;
        T val;

        Element(T val) {
            this.val = val;
        }
    }

    public void push(T v) {
        if (tail == null) {
            head = new Element<>(v);
            tail = head;
        } else {
            tail.next = new Element<>(v);
            tail = tail.next;
        }
    }

    public List<T> allElements() {
        List<T> elems = new ArrayList<>();
        for (Element<T> e = head; e != null; e = e.next) {
            elems.add(e.val);
        }
        return elems;
    }
}

Now let’s see how we can use these generic types and methods:

public class Main {
    public static void main(String[] args) {
        List<String> s = Arrays.asList("foo", "bar", "zoo");

        // When invoking generic methods, we can often rely on type inference.
        // Note that we don't have to specify the type for T when calling slicesIndex
        // - the compiler infers it automatically.
        System.out.println("index of zoo: " + Generics.slicesIndex(s, "zoo"));

        // We could also specify the type explicitly, though it's not necessary here.
        Generics.<String>slicesIndex(s, "zoo");

        List<Integer> lst = new List<>();
        lst.push(10);
        lst.push(13);
        lst.push(23);
        System.out.println("list: " + lst.allElements());
    }
}

When you run this program, you should see output similar to:

index of zoo: 2
list: [10, 13, 23]

In this example, we’ve demonstrated how to create and use generic methods and classes in Java. The slicesIndex method works with any type that implements Comparable, and the List class can hold elements of any type. This flexibility allows for code reuse and type safety at compile-time.