kotlinadvanced

Inline Functions and Reified Generics

Use inline functions for zero-overhead abstractions: reified type parameters, crossinline, and noinline.

kotlin
import kotlin.time.measureTimedValue
import kotlin.time.Duration

// Reified type parameter — access type info at runtime
inline fun <reified T> String.parseAs(): T? = when (T::class) {
    Int::class -> toIntOrNull() as? T
    Long::class -> toLongOrNull() as? T
    Double::class -> toDoubleOrNull() as? T
    Boolean::class -> toBooleanStrictOrNull() as? T
    String::class -> this as T
    else -> null
}

// Type-safe JSON-like casting
inline fun <reified T> Any?.safeCast(): T? = this as? T

// Reified type checking
inline fun <reified T> List<*>.filterIsType(): List<T> =
    filterIsInstance<T>()

// Inline for performance — lambda inlined at call site
inline fun <T> retry(
    times: Int = 3,
    delay: Long = 100,
    block: (attempt: Int) -> T
): T {
    var lastException: Exception? = null
    repeat(times) { attempt ->
        try {
            return block(attempt)
        } catch (e: Exception) {
            lastException = e
            Thread.sleep(delay * (attempt + 1))
        }
    }
    throw lastException!!
}

// crossinline — can't return from enclosing function
inline fun transaction(crossinline block: () -> Unit) {
    println("BEGIN")
    try {
        block()
        println("COMMIT")
    } catch (e: Exception) {
        println("ROLLBACK: ${e.message}")
    }
}

// noinline — prevent inlining specific lambda
inline fun measured(
    label: String,
    noinline onComplete: ((Duration) -> Unit)? = null,
    block: () -> Unit
) {
    val (_, duration) = measureTimedValue { block() }
    println("$label took: $duration")
    onComplete?.invoke(duration)
}

// Inline class (value class) — zero overhead wrapper
@JvmInline
value class Email(val value: String) {
    init {
        require(value.contains("@")) { "Invalid email" }
    }
    val domain get() = value.substringAfter("@")
}

@JvmInline
value class UserId(val value: Long)

@JvmInline
value class Meters(val value: Double) {
    operator fun plus(other: Meters) = Meters(value + other.value)
    operator fun times(factor: Double) = Meters(value * factor)
    fun toKilometers() = value / 1000.0
}

fun main() {
    // Reified parsing
    val port = "8080".parseAs<Int>()
    val rate = "3.14".parseAs<Double>()
    val flag = "true".parseAs<Boolean>()
    println("port=$port, rate=$rate, flag=$flag")

    // Type filtering
    val mixed: List<Any> = listOf(1, "hello", 2.0, "world", 3)
    val strings: List<String> = mixed.filterIsType()
    val ints: List<Int> = mixed.filterIsType()
    println("Strings: $strings, Ints: $ints")

    // Retry
    var attempts = 0
    val result = retry(times = 3) { attempt ->
        attempts++
        if (attempt < 2) throw RuntimeException("Fail $attempt")
        "Success on attempt $attempt"
    }
    println("$result (tried $attempts times)")

    // Transaction
    transaction {
        println("Doing work...")
        // return  // crossinline prevents non-local return
    }

    // Value classes — zero overhead
    val email = Email("alice@test.com")
    println("Domain: ${email.domain}")

    val distance = Meters(1500.0) + Meters(500.0)
    println("${distance.value}m = ${distance.toKilometers()}km")
}

Use Cases

  • Type-safe parsing and casting utilities
  • Zero-overhead wrapper types
  • Performance-critical higher-order functions

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.