Advanced Kotlin Concepts
This document covers advanced Kotlin programming concepts in detail,
with explanations, diagrams (conceptual), and example code snippets for
each section.
Generics & Variance
Generics allow you to write type-safe and reusable code. Variance
determines how subtyping between more complex types relates to subtyping
between their components.
• Covariant (out): You can read from the generic type but not write
to it.
• Contravariant (in): You can write to the generic type but not read
from it.
• Invariant: No subtyping allowed.
• Star Projection (*): Used when the type argument is unknown.
Example:
fun printList(list: List<out Number>) {
list.forEach { println(it) }
}
fun addNumber(list: MutableList<in Int>) {
list.add(42)
}
Delegation
Delegation is a design pattern where one object handles a request by
delegating it to another object. Kotlin supports class and property
delegation natively.
• Class Delegation: Use 'by' keyword to delegate implementation.
• Property Delegation: Built-in delegates like lazy, observable, and
map-based.
• Helps to reduce boilerplate code and improve maintainability.
Example:
interface Base { fun printMessage() }
class BaseImpl(val x: Int) : Base {
override fun printMessage() = println(x)
}
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl(10)
Derived(b).printMessage() // Delegated call
}
Extension & Higher-Order Functions
Extension functions let you add new functions to existing classes
without modifying them. Higher-order functions take functions as
parameters or return them.
• Extensions improve readability and maintainability.
• Higher-order functions enable functional programming patterns.
• Common with lambdas, inline functions, and scope functions.
Example:
fun String.lastChar(): Char = this[length - 1]
fun operate(x: Int, y: Int, op: (Int, Int) -> Int): Int = op(x, y)
fun main() {
println("Kotlin".lastChar())
println(operate(3, 4) { a, b -> a + b })
}
Coroutines
Coroutines are Kotlin's way of handling asynchronous programming. They
are lightweight threads that enable structured concurrency.
• launch: Starts a coroutine without returning a result.
• async: Starts a coroutine and returns a Deferred result.
• runBlocking: Bridges regular and suspending code.
• Structured concurrency ensures predictable lifecycle management.
Example:
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
delay(1000L)
println("World!")
}
println("Hello,")
job.join()
}
Sealed Classes & Interfaces
Sealed classes restrict class hierarchies, ensuring all subclasses are
known at compile time.
• Used for representing restricted sets of types.
• Often used in 'when' expressions for exhaustive checking.
• Can be extended in the same file only.
Example:
sealed class Result
class Success(val data: String) : Result()
class Error(val exception: Exception) : Result()
fun handle(result: Result) = when(result) {
is Success -> println("Data: ${result.data}")
is Error -> println("Error: ${result.exception.message}")
}
Inline & Reified Types
Inline functions allow the compiler to insert the function's body at the
call site, reducing overhead. Reified types allow you to access the type
argument at runtime in inline functions.
• Improves performance by avoiding function object allocation.
• Reified types remove the need to pass Class<T> explicitly.
Example:
inline fun <reified T> Gson.fromJson(json: String): T =
this.fromJson(json, T::class.java)
Reflection & Annotations
Reflection lets you inspect or modify code at runtime. Annotations add
metadata that can be processed at compile or runtime.
• Kotlin reflection API allows accessing properties, functions, and
constructors.
• Annotations can be used by libraries and frameworks.
Example:
@Target(AnnotationTarget.CLASS)
annotation class MyAnnotation(val name: String)
@MyAnnotation("ExampleClass")
class Example
Kotlin DSLs
DSLs (Domain Specific Languages) are mini-languages built with Kotlin
syntax to simplify specific tasks.
• Gradle build scripts use Kotlin DSL.
• Custom DSLs can be created using lambdas with receivers.
Example:
fun html(init: HTML.() -> Unit): HTML { ... }
html {
body {
+"Hello DSL"
}
}
Multiplatform Project Structure
Kotlin Multiplatform allows sharing common code between different
platforms.
• commonMain: shared code.
• platform-specific source sets like androidMain, iosMain.
• Gradle configurations define targets.
Example:
kotlin {
android()
ios()
sourceSets {
val commonMain by getting
}
}
Best Practices & Patterns
Following best practices ensures maintainable, efficient, and robust
Kotlin code.
• Prefer immutability for thread-safety.
• Use coroutines for asynchronous tasks.
• Leverage extension functions and sealed classes.
• Apply functional programming techniques when beneficial.
Example: