Inline function adalah function yang ditandai dengan keyword inline. Kompilator Kotlin akan menyisipkan body function langsung ke setiap pemanggil, menghilangkan overhead pembuatan objek lambda dan pemanggilan function. Pada chapter ini kita akan memahami cara kerja inline function, modifikator noinline dan crossinline untuk kasus khusus, dan bagaimana inline memungkinkan fitur reified type parameter yang tidak mungkin dilakukan function biasa. Kita juga akan melihat kapan inline memberi manfaat nyata dan kapan tidak.

Apa Itu Inline Function #

Function inline ditandai dengan keyword inline sebelum fun. Saat kompilasi, setiap pemanggilan function akan diganti dengan body function itu sendiri — termasuk lambda yang diteruskan. Hal ini mengurangi overhead alokasi lambda dan call stack.

kotlin Bentuk inline function
inline fun repotimes(n: Int, aksi: (Int) -> Unit) {
    for (i in 0 until n) aksi(i)
}

// Setiap pemanggilan repotimes(...) akan disalin penuh ke pemanggil
repotimes(3) { println(it) }

Contoh Inline Function #

Mari kita lihat inline function dalam berbagai variasi — inline, noinline, crossinline, dan kombinasi dengan reified.

kotlin
// inline_functions.kt
// Inline function: kompilator menyisipkan body ke setiap pemanggil.

// Higher-order function inline untuk menghindari alokasi lambda.
inline fun repotimes(n: Int, aksi: (Int) -> Unit) {
    for (i in 0 until n) aksi(i)
}

// noinline: parameter function tetap tidak di-inline.
inline fun prosesGabungan(
    nilai: Int,
    noinline a: (Int) -> Int,
    noinline b: (Int) -> Int
): Int {
    return a(b(nilai))
}

// crossinline: tidak boleh return non-local, biasanya untuk lambda
// yang dipanggil dari eksekusi lain.
inline fun jadwalTugas(crossinline tugas: () -> Unit) {
    val runner = Runnable { tugas() }
    runner.run()
}

// reified type parameter (memerlukan inline).
inline fun <reified T> namaTipe(): String = T::class.simpleName ?: "<anonim>"

fun main() {
    // Pemanggilan inline function — lambda digabung ke pemanggil.
    repotimes(3) { i -> println("  iterasi $i") }

    // noinline + inline.
    val hasil = prosesGabungan(
        nilai = 5,
        a = { it + 10 },
        b = { it * 2 }
    )
    println("prosesGabungan(5) = $hasil")

    // crossinline.
    jadwalTugas { println("  tugas dijadwalkan") }

    // reified.
    println("Tipe Int: ${namaTipe<Int>()}")
    println("Tipe String: ${namaTipe<String>()}")
}

Output yang Dihasilkan:

text
  iterasi 0
  iterasi 1
  iterasi 2
prosesGabungan(5) = 20
  tugas dijadwalkan
Tipe Int: Int
Tipe String: String

Mari kita telaah baris-baris kode di atas:

  1. Baris 5 (inline fun repotimes(n: Int, aksi: (Int) -> Unit)): function inline. Parameter aksi bertipe function type. Saat dipanggil, body repotimes dan lambda yang diteruskan akan digabungkan ke pemanggil — tidak ada objek lambda yang dibuat.
  2. Baris 11-12 (noinline a: (Int) -> Int, noinline b: (Int) -> Int): modifikator noinline memaksa parameter a dan b tetap tidak di-inline. Berguna saat kita ingin menyimpan lambda atau meneruskannya ke function lain.
  3. Baris 20 (inline fun jadwalTugas(crossinline tugas: () -> Unit)): modifikator crossinline melarang non-local return. Dipakai bila lambda akan dipanggil dari konteks lain (di sini dari dalam Runnable), di mana non-local return tidak masuk akal.
  4. Baris 28 (inline fun <reified T> namaTipe(): String = T::class.simpleName ?: "<anonim>"): function inline dengan reified T. Reified memungkinkan akses T::class saat runtime — sesuatu yang tidak bisa dilakukan function biasa karena type erasure.
  5. Baris 33 (repotimes(3) { i -> println(" iterasi $i") }): pemanggilan function inline. Lambda { i -> ... } akan digabung ke body repotimes di lokasi pemanggilan.
  6. Baris 37-41 (prosesGabungan(nilai = 5, a = { it + 10 }, b = { it * 2 })): pemanggilan dengan dua lambda noinline. Function prosesGabungan akan di-inline, tetapi lambda a dan b tetap dibuat sebagai objek karena noinline.
  7. Baris 45 (jadwalTugas { println(" tugas dijadwalkan") }): lambda crossinline dipanggil dari dalam Runnable. Bila lambda mencoba return, kompilator menolak karena crossinline melarang non-local return.
  8. Baris 48-49 (namaTipe<Int>() dan namaTipe<String>()): pemanggilan function reified. Kompilator mengganti T dengan tipe konkret (Int atau String) di setiap pemanggilan, sehingga T::class.simpleName menghasilkan "Int" atau "String".

Modifikator pada Parameter Function Type #

ModifikatorPerilakuKapan Dipakai
(default, inline)Lambda di-inline ke pemanggilMayoritas kasus
noinlineLambda tetap jadi objekIngin menyimpan atau meneruskan lambda
crossinlineLambda tidak boleh non-local returnLambda dipanggil dari context lain
reified TType parameter tersedia saat runtimePerlu cek is T atau T::class

Manfaat dan Biaya Inline #

Inline mengurangi overhead alokasi lambda, tetapi meningkatkan ukuran bytecode — setiap pemanggilan function inline menyisipkan salinan body. Untuk function yang dipanggil banyak atau berada di hot path, inline memberi manfaat nyata. Untuk function yang jarang dipanggil atau berbody besar, inline bisa membengkakkan ukuran binary.

Referensi Lanjutan #

Penutup #

Inline function adalah optimasi yang membuat Kotlin ringan untuk pemrograman fungsional. Dengan menyisipkan body ke pemanggilan, kompilator menghindari alokasi lambda dan membuka fitur seperti reified. Modifikator noinline dan crossinline memberi kontrol halus untuk kasus khusus. Selanjutnya, kita akan beralih ke topik yang berbeda namun saling melengkapi — callable references, yaitu cara merujuk ke function yang sudah ada tanpa membungkusnya dengan lambda.