Advanced Kotlin Features
Estimated reading: 4 minutes 56 views

🧬 Kotlin – Generics: Write Reusable and Type-Safe Code

🧲 Introduction – Why Learn Kotlin Generics?

Generics in Kotlin let you write flexible and type-safe code without sacrificing readability. Instead of creating separate classes or functions for every data type, generics let you define a blueprint that works with any type. This is widely used in collections, APIs, utility classes, and custom data structures.

🎯 In this guide, you’ll learn:

  • What generics are and why they matter
  • How to define and use generic functions and classes
  • The role of variance (in, out) and type constraints
  • Best practices and real-world use cases

🔣 What Are Generics in Kotlin?

Generics allow you to write type-agnostic code. You define a placeholder (like T) instead of a specific type.

✅ Without Generics:

fun printIntList(list: List<Int>) { ... }

✅ With Generics:

fun <T> printList(list: List<T>) {
    for (item in list) println(item)
}

✔️ Now you can pass a list of any type (Int, String, Double, etc.).


🧱 Generic Classes – Define Once, Use for All Types

class Box<T>(val value: T) {
    fun getValue(): T = value
}

🔹 Usage:

val intBox = Box(100)
val strBox = Box("Kotlin")
println(intBox.getValue())  // Output: 100
println(strBox.getValue())  // Output: Kotlin

✔️ Box<T> can wrap any type!


🧰 Generic Functions

fun <T> display(item: T) {
    println("Item: $item")
}

🔹 Usage:

display("Hello")
display(42)

✔️ Define once, use for all types.


🧬 Variance in Kotlin Generics

Kotlin uses variance modifiers to control how subtyping works with generics.

🔹 out – Covariance (Producer)

class Source<out T>(val data: T)

fun read(source: Source<Any>) { ... }

val stringSource: Source<String> = Source("Text")
read(stringSource)  // ✅ Works because of `out`

✔️ Use out when a type only produces data (read-only).


🔹 in – Contravariance (Consumer)

class Sink<in T> {
    fun accept(item: T) { println("Accepted: $item") }
}

val sink: Sink<Number> = Sink<Int>()  // ✅ OK because of `in`

✔️ Use in when a type only consumes data (write-only).


🔒 Type Constraints with where or :

Restrict generics to specific types using constraints:

fun <T : Number> doubleValue(value: T): Double {
    return value.toDouble() * 2
}

✔️ T must be a subtype of Number.


🔁 Multiple Type Parameters

class Pair<A, B>(val first: A, val second: B)

val pair = Pair("Age", 30)
println("${pair.first} = ${pair.second}")  // Age = 30

✔️ You can define multiple placeholders for multi-type data structures.


🧪 Generic Extension Functions

fun <T> List<T>.second(): T = this[1]

val nums = listOf(10, 20, 30)
println(nums.second())  // Output: 20

✔️ Extend built-in types generically!


🚫 Common Mistakes

❌ Mistake✅ Fix
Forgetting <T> in function headerAlways declare generic before return type
Misusing in/outUse out for producing, in for consuming
Ignoring constraintsUse : Type to restrict generic usage
Using star-projection (*) too muchUse variance properly instead of fallback wildcards

✅ Best Practices for Kotlin Generics

PracticeWhy It Matters
Keep generics simple and readableAvoid overly abstract or complex type setups
Use variance modifiers where applicablePrevent unsafe type casting and enhance safety
Add type constraints to clarify usageMakes the contract of your function/class obvious
Combine generics with inline and reifiedEnables smart casting and reflection for T

📌 Summary – Recap & Next Steps

Kotlin Generics let you build type-safe, reusable, and maintainable code across classes, functions, and APIs. Mastering variance, constraints, and usage patterns helps you design flexible systems.

🔍 Key Takeaways:

  • Use <T> to define generics in classes and functions
  • Use in and out for type-safe inheritance scenarios
  • Apply constraints with : Type or where clauses
  • Keep generic logic simple and predictable

⚙️ Practical Use:
Used heavily in collections, custom data containers, repository patterns, utility libraries, and API response models in Kotlin apps.


❓ FAQs – Kotlin Generics

What is a generic in Kotlin?
✅ A generic is a type placeholder (like T) that allows classes and functions to operate on different types without rewriting them.


What is out in Kotlin generics?
✅ It’s a covariance modifier meaning the class is read-only and can produce values of type T.


How do I restrict a generic to certain types?
✅ Use type constraints:

fun <T : Number> process(value: T) { ... }

Can I use generics in extension functions?
✅ Yes. You can write powerful and reusable generic extensions:

fun <T> List<T>.lastIndex(): Int = this.size - 1

What’s the difference between in and out?
in is for consuming types, out is for producing types. Use in when you write to a generic type, and out when you read from it.


Share Now :

Leave a Reply

Your email address will not be published. Required fields are marked *

Share

Kotlin – Generics

Or Copy Link

CONTENTS
Scroll to Top