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