Chapter 25: Advanced Topics & Real-World Kotlin
Advanced Topics & Real-World Kotlin — this is the grand finale of our Core Kotlin journey! 🎉☕
By now you’ve mastered the fundamentals — from basic syntax to coroutines and Flow. Now we’re going to look at the advanced, real-world features that make Kotlin the #1 choice for modern Android, backend, desktop, and multiplatform development in 2026.
We’ll cover:
- DSLs (Type-Safe Builders) — Kotlin’s killer feature for clean APIs
- Annotations & Reflection Basics
- Kotlin Multiplatform (KMP) Intro
- Compose Multiplatform Basics
- Best Practices, Code Style (ktlint), Testing (Kotest)
I’m going to explain everything super slowly, like we’re sitting together in a quiet Bandra café — with real-life analogies, complete runnable examples, step-by-step breakdowns, tables, common mistakes with fixes, and practical tips you can use immediately in your projects.
Let’s finish strong!
1. DSLs (Type-Safe Builders) – Kotlin’s Magic for Clean APIs
DSLs (Domain-Specific Languages) let you write code that reads like natural language while staying type-safe.
Kotlin’s type-safe builders are the most famous DSLs — you’ve already used them without knowing:
- listOf { … }
- buildList { add(…) }
- html { body { … } } (in kotlinx.html)
- compose { Text(“Hello”) } (Jetpack Compose)
Real-life analogy: Normal code = writing a letter with strict grammar rules. DSL = writing a friendly postcard: short, expressive, no boilerplate — but still correct!
Example 1 – Simple DSL for HTML (using type-safe builders)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
// Very simple DSL builder class HtmlBuilder { private val content = StringBuilder() fun body(block: BodyBuilder.() -> Unit) { content.append("<body>") BodyBuilder(content).block() content.append("</body>") } override fun toString() = "<html>$content</html>" } class BodyBuilder(private val sb: StringBuilder) { fun h1(text: String) { sb.append("<h1>$text</h1>") } fun p(text: String) { sb.append("<p>$text</p>") } } fun html(block: HtmlBuilder.() -> Unit): String { val builder = HtmlBuilder() builder.block() return builder.toString() } fun main() { val page = html { body { h1("Welcome to Kotlin DSLs!") p("This is type-safe HTML generated by Kotlin!") } } println(page) } |
Output:
|
0 1 2 3 4 5 6 |
<html><body><h1>Welcome to Kotlin DSLs!</h1><p>This is type-safe HTML generated by Kotlin!</p></body></html> |
How it works:
- html { … } → receiver is HtmlBuilder (via this)
- body { … } → receiver is BodyBuilder
- Inside body { } → h1(), p() are extension functions on BodyBuilder
Real-world DSLs you already use:
- Jetpack Compose:
Kotlin0123456789@Composablefun Greeting() {Text("Hello Webliance!")}
- Ktor routing:
Kotlin012345678routing {get("/hello") { call.respondText("Hi!") }}
- Gradle Kotlin DSL:
Kotlin012345678plugins {id("org.jetbrains.kotlin.jvm") version "1.9.0"}
2. Annotations & Reflection Basics
Annotations = metadata attached to code (classes, functions, properties).
Reflection = inspecting/modifying code at runtime.
Annotations in Kotlin — same as Java + nicer syntax
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) annotation class MyLog(val level: String = "INFO") @MyLog(level = "DEBUG") class ImportantService { @MyLog fun process() { ... } } |
Reading annotations with reflection
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import kotlin.reflect.full.* fun main() { val clazz = ImportantService::class // Class-level annotation val classLog = clazz.findAnnotation<MyLog>() println("Class log level: {classLog?.level}") // Function-level val method = clazz.declaredFunctions.first { it.name == "process" } val methodLog = method.findAnnotation<MyLog>() println("Method log level: ${methodLog?.level}") } |
Common use cases:
- @Composable (Jetpack Compose)
- @Serializable (kotlinx.serialization)
- @Entity, @Column (Room)
- @Test, @Before (Kotest, JUnit)
Reflection example – dynamic invocation
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
fun main() { val person = Person("Amit", 22) val nameProperty = Person::name // KProperty1 println(nameProperty.get(person)) // Amit val greetFunction = Person::greet greetFunction.call(person) // Calls greet() } |
Warning: Reflection is slow and breaks encapsulation — use only when necessary (frameworks, serialization, testing).
3. Kotlin Multiplatform (KMP) – Intro
Kotlin Multiplatform lets you share business logic, models, network, data layer across:
- Android
- iOS (via Kotlin/Native)
- Desktop (JVM, JS)
- Web (Kotlin/JS)
- Server (Kotlin/JVM)
Shared code example (common module):
|
0 1 2 3 4 5 6 7 8 9 10 11 |
// shared/src/commonMain/kotlin/com/webliance/shared/Greeting.kt expect class Platform() { val name: String } fun greet(): String = "Hello from ${Platform().name}!" |
Android implementation (androidMain):
|
0 1 2 3 4 5 6 7 8 |
actual class Platform { actual val name: String = "Android" } |
iOS implementation (iosMain):
|
0 1 2 3 4 5 6 7 8 |
actual class Platform { actual val name: String = "iOS" } |
Result: One shared greet() function works on Android, iOS, Desktop — no duplication!
Popular KMP libraries (2026):
- Ktor (network)
- SQLDelight / Realm (database)
- Koin / Kodein (DI)
- Kamel (images)
- Compose Multiplatform (UI – next topic)
4. Compose Multiplatform Basics – Shared UI
Compose Multiplatform lets you write UI once and run it on:
- Android (Jetpack Compose)
- Desktop (JVM)
- iOS (via SwiftUI bridge)
- Web (Wasm)
Example – Simple shared Compose UI
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// shared/src/commonMain/kotlin/com/webliance/ui/App.kt import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.window.Window @Composable fun App() { var count by remember { mutableStateOf(0) } MaterialTheme { Column { Text("नमस्ते Webliance! Count: $count") Button(onClick = { count++ }) { Text("Click me!") } } } } |
Run on Desktop (desktopMain):
|
0 1 2 3 4 5 6 7 8 9 10 |
fun main() = application { Window(onCloseRequest = ::exitApplication) { App() } } |
Run on Android (androidMain):
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { App() } } } |
Run on iOS (with Compose Multiplatform plugin) — shared UI code works!
5. Best Practices, Code Style (ktlint), Testing (Kotest)
A. Best Practices (2026 Kotlin Style)
- Prefer val over var
- Prefer read-only collections (List, Set, Map)
- Use trailing lambdas & scope functions (let, run, apply, also)
- Use extension functions for clean APIs
- Use data classes for models
- Use sealed classes/interfaces for state/result handling
- Avoid !! — use safe calls / Elvis
- Use context receivers (Kotlin 1.6.20+) for clean DSLs
B. Code Style – ktlint
ktlint = official Kotlin linter (like ktfmt + detekt)
Add to build.gradle.kts:
|
0 1 2 3 4 5 6 7 8 |
plugins { id("org.jlleitschuh.gradle.ktlint") version "12.1.0" } |
Run: ./gradlew ktlintCheck or ktlintFormat
Popular rules:
- No semicolons
- Consistent indentation (4 spaces)
- Trailing commas in lists
- No wildcard imports
C. Testing with Kotest
Kotest = modern Kotlin test framework (BDD, property-based, coroutine support)
Add to build.gradle.kts:
|
0 1 2 3 4 5 6 7 8 9 |
dependencies { testImplementation("io.kotest:kotest-runner-junit5:5.9.0") testImplementation("io.kotest:kotest-assertions-core:5.9.0") } |
Example – Kotest spec
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe class CalculatorTest : FunSpec({ test("addition works") { (2 + 3) shouldBe 5 } context("multiplication") { test("positive numbers") { (4 * 5) shouldBe 20 } } }) |
Property-based testing:
|
0 1 2 3 4 5 6 7 8 9 10 |
test("addition is commutative") { checkAll { a: Int, b: Int -> (a + b) shouldBe (b + a) } } |
Coroutine testing:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
test("suspend function") { runTest { val result = someSuspendFunction() result shouldBe expected } } |
Final Thoughts
You’ve now completed the full Core Kotlin journey — from Hello World to advanced coroutines, Flow, delegation, DSLs, and multiplatform!
You’re ready for:
- Android development (Jetpack Compose + KMP)
- Backend (Ktor, Spring Boot 3+ with Kotlin)
- Multiplatform projects
- Job interviews (you’ll crush questions on coroutines, null safety, DSLs)
What would you like next?
- Deep dive into Jetpack Compose?
- Ktor backend?
- Kotlin Multiplatform Mobile (KMM)?
- Spring Boot with Kotlin?
- Interview questions & coding challenges?
- Or review any chapter with more examples?
Just tell me — I’m right here with another cup of cutting chai! ☕🚀
