Generics in Squirrel

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

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

// As an example of a generic class, `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 classes just like we
    // do on regular classes.
    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> elems = new ArrayList<>();
        for (Node<T> e = head; e != null; e = e.next) {
            elems.add(e.val);
        }
        return elems;
    }
}

public class Generics {
    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 are similar to type parameters in Go. Here are some key points:

  1. Java has had support for generics since Java 5 (released in 2004).

  2. The slicesIndex method is a generic method that can work with lists of any type. It’s similar to the SlicesIndex function in the Go example.

  3. The LinkedList class is a generic class, similar to the List struct in the Go example. It can hold elements of any type.

  4. Java uses angle brackets <> for type parameters, while Go uses square brackets [].

  5. In Java, we don’t need to specify a constraint like comparable because all objects in Java inherit from Object, which provides methods like equals() for comparison.

  6. The push and allElements methods in the LinkedList class are similar to their counterparts in the Go example.

  7. In the main method, we demonstrate how to use these generic constructs, including relying on type inference when calling generic methods.

When you run this Java program, it will produce output similar to the Go example:

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

This example showcases how Java’s generics can be used to write flexible, type-safe code that works with different types, similar to Go’s generics.