Generics in CLIPS

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.
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;
        }
    }

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

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.getAllElements());
    }
}

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 translation:

  1. The SlicesIndex function is translated to a static generic method slicesIndex. It works with List<T> instead of slices, as Java doesn’t have a direct equivalent to Go’s slices.

  2. The List type is translated to a LinkedList class. Java already has a LinkedList class in its standard library, but we’ve implemented our own here to stay close to the original example.

  3. The element type is translated to a private static nested class Node within LinkedList.

  4. The Push method is translated to a push method in the LinkedList class.

  5. The AllElements method is translated to getAllElements.

  6. In the main method, we create a List<String> using List.of() instead of a slice literal.

  7. We demonstrate type inference when calling slicesIndex, and also show how to call it with explicit type parameters (though in Java, this is rarely necessary).

  8. We create and use a LinkedList<Integer> to demonstrate the generic class.

Note that Java’s type system is slightly different from Go’s. For example, Java doesn’t have a direct equivalent to Go’s comparable constraint. In Java, all objects can be compared using equals(), so we don’t need a special constraint for this.

When you run this program, it will output:

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

This demonstrates that the generic functions and classes are working as expected, similar to the Go version.