Generics in Minitab

import java.util.ArrayList;
import java.util.List;

public class Generics {

    // As an example of a generic method, slicesIndex takes
    // a list of any comparable type and an element of that
    // type and returns the index of the first occurrence of
    // v in s, or -1 if not present.
    public static <T extends Comparable<T>> int slicesIndex(List<T> s, T v) {
        for (int i = 0; i < s.size(); i++) {
            if (v.compareTo(s.get(i)) == 0) {
                return i;
            }
        }
        return -1;
    }

    // As an example of a generic type, LinkedList is a
    // singly-linked list with values of any type.
    public static class LinkedList<T> {
        private Node<T> head, tail;

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

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

        // We can define methods on generic types just like we
        // do on regular types.
        public void push(T v) {
            Node<T> newNode = new Node<>(v);
            if (tail == null) {
                head = tail = newNode;
            } else {
                tail.next = newNode;
                tail = newNode;
            }
        }

        // AllElements returns all the LinkedList elements as a list.
        public List<T> allElements() {
            List<T> elements = new ArrayList<>();
            Node<T> current = head;
            while (current != null) {
                elements.add(current.val);
                current = current.next;
            }
            return elements;
        }
    }

    public static void main(String[] args) {
        List<String> s = List.of("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: " + slicesIndex(s, "zoo"));

        // ... though we could also specify it explicitly.
        slicesIndex(s, "zoo");

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

This Java code demonstrates the use of generics, which is similar to the concept of type parameters in the original example. Here’s a breakdown of the changes and explanations:

  1. The SlicesIndex function is transformed into a static generic method slicesIndex. It uses a type parameter T that extends Comparable<T> to ensure the elements can be compared.

  2. The List type is implemented as a generic LinkedList class. It uses a nested Node class to represent list elements.

  3. The Push method is renamed to push to follow Java naming conventions.

  4. The AllElements method is renamed to allElements and returns a List<T> instead of an array.

  5. In the main method, we create an immutable list using List.of() instead of an array literal.

  6. The example demonstrates both type inference and explicit type specification when calling the generic method.

  7. The output is generated using System.out.println() instead of fmt.Println().

To run this program, save it as Generics.java, compile it with javac Generics.java, and then run it with java Generics. The output will be:

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

This example showcases how Java implements generics, which provide type safety and code reuse, similar to the generics feature in the original example.