Generics in Karel

Java introduced generics in version 5.0, providing type safety and reducing the need for type casting. Let’s explore Java’s generics by examples similar to the original code.

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

public class Generics {

    // Generic method to find the index of an element in a list
    public static <T> int listIndex(List<T> list, T element) {
        for (int i = 0; i < list.size(); i++) {
            if (element.equals(list.get(i))) {
                return i;
            }
        }
        return -1;
    }

    // Generic class for a singly-linked list
    public static class LinkedList<T> {
        private Node<T> head;
        private Node<T> tail;

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

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

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

        public List<T> allElements() {
            List<T> elements = new ArrayList<>();
            Node<T> current = head;
            while (current != null) {
                elements.add(current.value);
                current = current.next;
            }
            return elements;
        }
    }

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

        // When using generic methods, Java often uses type inference
        System.out.println("index of zoo: " + listIndex(s, "zoo"));

        // We could also specify the type explicitly
        int index = Generics.<String>listIndex(s, "zoo");

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

In this Java example, we’ve implemented similar functionality to the Go code:

  1. We defined a generic method listIndex that finds the index of an element in a list. This is similar to the SlicesIndex function in the Go example.

  2. We created a generic LinkedList class with a nested Node class, both using type parameter T. This is analogous to the List and element types in the Go code.

  3. The push method adds elements to the end of the list, and allElements returns all elements as a List.

  4. In the main method, we demonstrate using these generic constructs.

When using generic methods in Java, we often rely on type inference, similar to Go. However, we can also explicitly specify the type parameters if needed.

To run this program:

$ javac Generics.java
$ java Generics
index of zoo: 2
list: [10, 13, 23]

Java’s generics provide similar benefits to Go’s, allowing us to write flexible, reusable code while maintaining type safety. While the syntax differs, the core concepts of type parameters and constraints (although Java uses interfaces for constraints) are present in both languages.