Generics in Groovy

import groovy.transform.CompileStatic

// As an example of a generic function, `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.
@CompileStatic
static <E> int slicesIndex(List<E> s, E v) {
    for (int i = 0; i < s.size(); i++) {
        if (v == s[i]) {
            return i
        }
    }
    return -1
}

// As an example of a generic type, `List` is a
// singly-linked list with values of any type.
class LinkedList<T> {
    private class Node<T> {
        T value
        Node<T> next
    }

    private Node<T> head
    private Node<T> tail

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

    // AllElements returns all the List elements as a list.
    List<T> allElements() {
        def elems = []
        for (def e = head; e != null; e = e.next) {
            elems << e.value
        }
        return elems
    }
}

// Main function to demonstrate the usage
static void main(String[] args) {
    def s = ["foo", "bar", "zoo"]

    // When invoking generic functions, we can often rely
    // on type inference. Note that we don't have to
    // specify the types when calling `slicesIndex` - 
    // the compiler infers them automatically.
    println "index of zoo: ${slicesIndex(s, "zoo")}"

    // … though we could also specify them explicitly.
    slicesIndex(s as List<String>, "zoo")

    def lst = new LinkedList<Integer>()
    lst.push(10)
    lst.push(13)
    lst.push(23)
    println "list: ${lst.allElements()}"
}

This Groovy code demonstrates the concept of generics, which is similar to Go’s generics. Here are some key points about the translation:

  1. Groovy has built-in support for generics, so we don’t need to implement a custom List type. Instead, we use Groovy’s List interface.

  2. We’ve implemented a LinkedList class to demonstrate a generic type, similar to the List type in the Go example.

  3. The slicesIndex function is implemented as a generic static method, which is similar to Go’s generic function.

  4. Groovy uses angle brackets <> for type parameters, similar to Java, instead of square brackets [] used in Go.

  5. We’ve used the @CompileStatic annotation to enable static type checking, which is similar to Go’s static typing.

  6. The comparable constraint in Go doesn’t have a direct equivalent in Groovy, so we’ve omitted it. Groovy will use the equals method for comparison.

  7. Groovy’s type inference is quite powerful, so we can often omit explicit type declarations, similar to Go’s type inference.

To run this Groovy script, save it as generics.groovy and execute it using the Groovy command:

$ groovy generics.groovy
index of zoo: 2
list: [10, 13, 23]

This demonstrates how Groovy supports generic programming, allowing for type-safe and reusable code similar to Go’s generics feature.