Generics in Kotlin

Kotlin has supported generics since its inception, which allows for writing flexible and reusable code that can work with different types.

import kotlin.collections.List

// As an example of a generic function, `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.
fun <T> slicesIndex(s: List<T>, v: T): Int {
    return s.indexOf(v)
}

// As an example of a generic class, `List` is a
// singly-linked list with values of any type.
class LinkedList<T> {
    private data class Node<T>(var value: T, var next: Node<T>? = null)
    
    private var head: Node<T>? = null
    private var tail: Node<T>? = null

    // We can define methods on generic types just like we
    // do on regular types.
    fun push(v: T) {
        val newNode = Node(v)
        if (tail == null) {
            head = newNode
            tail = newNode
        } else {
            tail?.next = newNode
            tail = newNode
        }
    }

    // allElements returns all the List elements as a list.
    fun allElements(): List<T> {
        val elements = mutableListOf<T>()
        var current = head
        while (current != null) {
            elements.add(current.value)
            current = current.next
        }
        return elements
    }
}

fun main() {
    val s = listOf("foo", "bar", "zoo")

    // When invoking generic functions, 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.
    println("index of zoo: ${slicesIndex(s, "zoo")}")

    // ... though we could also specify it explicitly.
    val _ = slicesIndex<String>(s, "zoo")

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

When you run this program, you should see:

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

In this Kotlin version:

  1. We’ve replaced the SlicesIndex function with a simpler implementation using Kotlin’s built-in indexOf method.

  2. We’ve implemented a LinkedList class to demonstrate generic classes, which is similar to the List struct in the original Go code.

  3. The Push method is implemented as push in Kotlin style.

  4. The AllElements method is implemented as allElements in Kotlin style.

  5. In the main function, we demonstrate the use of these generic constructs.

Kotlin’s type inference is generally more powerful than Go’s, so we don’t need to explicitly specify type parameters as often. However, we can still do so when needed, as shown in the example.

Kotlin’s generics system is similar to Java’s, with some additional features. It supports declaration-site variance and use-site variance, which provide more flexibility in how generic types can be used.