iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Examples

Five idiomatic Kotlin snippets: data classes, sealed classes, scope functions, coroutines, and DSL builders.

Five Kotlin recipes

EXAMPLE
// 1) Data class with copy + destructuring
data class Order(val id: String, val customer: String, val totalCents: Long, val status: String)

val o = Order("o1", "alice", 4995, "new")
val paid = o.copy(status = "paid")               // immutable update
val (id, customer) = paid                          // destructuring

// 2) Sealed class for UI state
sealed interface UiState
data object Loading : UiState
data class Loaded(val orders: List<Order>) : UiState
data class Failed(val message: String) : UiState

fun render(state: UiState) = when (state) {        // exhaustive match
    Loading -> "Loading..."
    is Loaded -> "${state.orders.size} orders"
    is Failed -> "Error: ${state.message}"
}

// 3) Scope functions — let / apply / run / with / also
val url = "https://example.com"
val response = url.let {
    if (it.startsWith("https")) it.uppercase() else null
}

val sb = StringBuilder().apply {
    append("Hello, ")
    append("world")
}.toString()

val firstWord = "hello world".run {
    split(" ").firstOrNull()
}

// 4) Coroutines with Flow
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

suspend fun fetchOrders(): List<Order> {
    delay(50)                                       // simulate IO
    return listOf(o)
}

fun ordersStream(): Flow<List<Order>> = flow {
    while (currentCoroutineContext().isActive) {
        emit(fetchOrders())
        delay(5000)
    }
}.flowOn(Dispatchers.IO)

// Usage:
// scope.launch {
//   ordersStream().collect { orders -> println(orders) }
// }

// 5) Tiny type-safe DSL (Kotlin builder)
class HtmlElement(val tag: String) {
    private val children = mutableListOf<HtmlElement>()
    private var text: String = ""

    fun text(t: String) { text = t }

    operator fun String.unaryPlus() { text += this }

    fun child(tag: String, init: HtmlElement.() -> Unit) {
        val c = HtmlElement(tag).apply(init)
        children += c
    }

    override fun toString(): String =
        "<$tag>${text}${children.joinToString("")}</$tag>"
}

fun html(init: HtmlElement.() -> Unit): HtmlElement =
    HtmlElement("html").apply(init)

val doc = html {
    child("body") {
        child("h1") { +"Hello" }
        child("p")  { +"World" }
    }
}
println(doc)

// ===== Patterns to internalise =====
// - Data classes for value types
// - Sealed classes / interfaces for exhaustive state
// - Scope functions to chain transforms cleanly
// - Flow for streams; suspend fun for single-value async
// - DSL for builders; .apply { } for fluent setup

// ===== Pitfalls =====
// - Overusing scope functions (let / apply / with) makes code unreadable
// - Forgetting .flowOn(Dispatchers.IO) on a Flow doing blocking IO
// - data class equality with floats / nested mutable state
// - DSLs without @DslMarker -> nested receivers leak across scopes

Why it matters

Data class + sealed class + scope functions are the trio that makes Kotlin "Java without the noise". Reach for them by reflex: data class for any value type, sealed when "this can only be one of these N shapes", and scope functions for chained transforms — the resulting code is hard to read in two ways: too much OR too little use.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Pure Kotlin CLI → Compose app → Ktor backend.
Try it Yourself »

Discussion

Loading…