Generic Functions in Kotlin

Home » Kotlin » Generic Functions in Kotlin

The generic functions allow developers to write reusable, type-safe code, enhancing maintainability and reducing redundancy in their projects. In this Kotlin tutorial, we will explore generic functions in Kotlin with fruitful examples.

The Kotlin generic functions enables us to write functions that can work with a variety of data types, without sacrificing type safety. Instead of writing separate functions for each data type, we can encapsulate common logic within a single function and allow it to handle different data types bases on the context.

Generic Functions in Kotlin

The syntax of generic functions in Kotlin involves using angle brackets (“<” and “>”) with a placeholder type, often denoted by the letter ‘T’ by convention. The placeholder type serves as a reference to the actual data type that will be provided when the function is called.


fun <T: Comparable<T>> maxOf(a: T, b: T) :T
{
    return  if (a>b) a else b
}

In this example, we use the placeholder type ‘T’ to represent a comparable data type. By specifying the constraint ‘T : Comparable’, we ensure that the function can only accept data types that implement the ‘Comparable’ interface, guaranteeing that we can perform the comparison operation safely.

The beauty of generic functions lies in their reusability. Regardless of whether we pass two integers, two strings, or any other comparable data types, the ‘maxOf’ function will work seamlessly with all of them.

val max = maxOf(a = 10, b = 67)
println(max)

val maxString = maxOf(a= "dx2", b= "dx3")
println(maxString)

Generic Functions in Kotlin : A simple example

fun <T: Comparable<T>> maxOf(a: T, b: T) :T
{
    return  if (a>b) a else b
}

fun main()
{
    val max = maxOf(a = 10, b = 67)
    println(max)

    val maxString = maxOf(a= "dx2", b= "dx3")
    println(maxString)
}

Output

67
dx3

Moreover, generic functions also contribute to more concise and readable code. By reducing the number of overloaded functions, the codebase becomes less cluttered and easier to maintain. Developers can focus on writing logic once and applying it across multiple contexts, leading to more efficient software development.

In addition to single-type generics, Kotlin also supports multiple generics, allowing developers to create highly adaptable functions that cater to a variety of scenarios.

Additionally, functions can be generified if their logic is independent of a specific type. For example, you can create a utility function to generate mutable stacks.

package Generics

class MutableStack<E>(vararg elements: E) {
    private val items = elements.toMutableList()

    fun push(element: E) {
        items.add(element)
    }

    fun pop(): E? {
        if (isEmpty()) return null
        return items.removeAt(items.size - 1)
    }

    fun peek(): E? {
        if (isEmpty()) return null
        return items[items.size - 1]
    }

    fun isEmpty(): Boolean {
        return items.isEmpty()
    }

    override fun toString(): String {
        return items.toString()
    }
}

fun <E> mutableStackOf(vararg elements: E) = MutableStack(*elements)

fun main() {
    val stack = mutableStackOf(0.62, 3.14, 2.7)

    // Print the initial stack
    println("Initial stack: $stack")

    // Check if the stack is empty
    println("Is the stack empty? ${stack.isEmpty()}")

    // Peek at the top element without removing it
    val topElement = stack.peek()
    if (topElement != null) {
        println("Top element: $topElement")
    } else {
        println("Stack is empty. No top element.")
    }

    // Push new element onto the stack
    stack.push(1.618)
    println("Stack after pushing 1.618: $stack")

    // Peek at the top element again after pushing
    val newTopElement = stack.peek()
    if (newTopElement != null) {
        println("Top element after pushing: $newTopElement")
    } else {
        println("Stack is empty. No top element.")
    }

    // Pop elements from the stack
    val poppedElement1 = stack.pop()
    val poppedElement2 = stack.pop()
    println("Popped elements: $poppedElement1, $poppedElement2")

    // Print the stack after popping
    println("Stack after popping: $stack")

    // Check if the stack is empty again
    println("Is the stack empty now? ${stack.isEmpty()}")
}

Output

Initial stack: [0.62, 3.14, 2.7]
Is the stack empty? false
Top element: 2.7
Stack after pushing 1.618: [0.62, 3.14, 2.7, 1.618]
Top element after pushing: 1.618
Popped elements: 1.618, 2.7
Stack after popping: [0.62, 3.14]
Is the stack empty now? false

The class has methods like push, pop, peek, and isEmpty to manipulate and access the stack’s elements. The toString method has also been overridden to provide a meaningful representation when the stack is printed using println. The mutableStackOf function now creates and returns an instance of the MutableStack class with the provided elements, maintaining the same functionality as the original code snippet.

The generic functions in Kotlin empower developers to create versatile and type-safe code, promoting code reuse and enhancing productivity.

You may also like...