Receiver function type adalah bentuk khusus function type di mana lambda memiliki receiver — sebuah objek yang menjadi this di dalam body lambda. Sintaksnya ditulis A.() -> B dan dibaca “function dengan receiver A yang mengembalikan B”. Pada chapter ini kita akan memahami cara kerja receiver function type, bagaimana this otomatis terikat ke receiver, dan mengapa pola ini menjadi dasar DSL Kotlin seperti buildString, apply, dan HTML builder. Kita juga akan membandingkan receiver function type dengan lambda biasa yang menerima receiver sebagai parameter eksplisit.

Apa Itu Receiver Function Type #

Receiver function type memiliki bentuk ReceiverType.() -> ReturnType. Di dalam body lambda, this otomatis merujuk ke instance receiver. Kita dapat memanggil member receiver tanpa prefix this. (sama seperti di dalam method class).

kotlin Bentuk receiver function type
// Lambda biasa: parameter eksplisit
val a: (String) -> String = { s -> "Halo, $s!" }

// Receiver function type: `this` adalah String
val b: String.() -> String = { "Halo, $this!" }

// Pemanggilan:
a("Budi")        // parameter biasa
"Budi".b()       // dipanggil pada receiver

Contoh Receiver Function Type #

Mari kita lihat penerapan receiver function type dalam beberapa skenario nyata.

kotlin
// receiver_function_types.kt
// Function type dengan receiver: Int.() -> String.
// Di dalam lambda, `this` adalah receiver.

// Lambda dengan receiver — di dalam body, `this` adalah String.
val pesanHalo: String.() -> String = {
    "Halo, $this! Panjang nama ${this.length} karakter."
}

// Receiver type dengan parameter tambahan.
val ulang: String.(Int) -> String = { n ->
    this.repeat(n)
}

// Higher-order function yang menerima receiver lambda.
// Receiver adalah StringBuilder sehingga `this` di dalam block adalah StringBuilder.
fun bangunHtml(block: StringBuilder.() -> Unit): String {
    val sb = StringBuilder("<html>")
    sb.block()
    sb.append("</html>")
    return sb.toString()
}

// Function yang menerima receiver lambda untuk konfigurasi.
fun konfigurasiPesan(block: StringBuilder.() -> Unit): String {
    val sb = StringBuilder("PESAN: ")
    sb.block()
    return sb.toString()
}

fun main() {
    // Memanggil receiver lambda langsung pada instance.
    val hasil = "Budi".pesanHalo()
    println(hasil)

    // Memanggil dengan parameter tambahan.
    val ulangan = "Ha".ulang(3)
    println("Ulang: $ulangan")

    // Memakai bangunHtml — `this` di dalam block adalah StringBuilder.
    val html = bangunHtml {
        append("<head><title>Halo</title></head>")
        append("<body>Selamat datang</body>")
    }
    println("HTML: $html")

    // Memakai konfigurasiPesan.
    val pesan = konfigurasiPesan {
        append("Belajar Kotlin ")
        append("di tahun 2026")
    }
    println(pesan)

    // Receiver lambda vs lambda biasa.
    val lambdaBiasa: (String) -> String = { s -> "Halo, $s!" }
    val lambdaReceiver: String.() -> String = { "Halo, $this!" }
    println("Lambda biasa: ${lambdaBiasa("Budi")}")
    println("Lambda receiver: ${"Budi".lambdaReceiver()}")
}

Output yang Dihasilkan:

text
Halo, Budi! Panjang nama 4 karakter.
Ulang: HaHaHa
HTML: <html><head><title>Halo</title></head><body>Selamat datang</body></html>
PESAN: Belajar Kotlin di tahun 2026
Lambda biasa: Halo, Budi!
Lambda receiver: Halo, Budi!

Mari kita telaah baris-baris kode di atas:

  1. Baris 6 (val pesanHalo: String.() -> String): receiver function type dengan receiver String. Di dalam body, this merujuk ke instance String yang menjadi receiver.
  2. Baris 7 ("Halo, $this! Panjang nama ${this.length} karakter."): pemanggilan this di dalam body mengakses receiver String. Kita bisa pakai this eksplisit atau memanggil member tanpa prefix.
  3. Baris 11 (val ulang: String.(Int) -> String): receiver function type dengan satu parameter tambahan. Di dalam body, this adalah String dan n adalah parameter Int. Body memanggil this.repeat(n).
  4. Baris 16 (fun bangunHtml(block: StringBuilder.() -> Unit)): higher-order function yang menerima receiver lambda. Parameter block bertipe StringBuilder.() -> Unit, sehingga di dalam body block, this adalah StringBuilder.
  5. Baris 17-21: implementasi membuat StringBuilder, memanggil block pada sb sehingga append di dalam block menambah ke sb, lalu mengembalikan hasil toString().
  6. Baris 32 (val hasil = "Budi".pesanHalo()): pemanggilan receiver lambda langsung pada instance "Budi". String "Budi" menjadi this di dalam lambda.
  7. Baris 36 ("Ha".ulang(3)): pemanggilan receiver lambda dengan argumen parameter tambahan 3. Hasilnya "HaHaHa".
  8. Baris 39-43 (bangunHtml { append(...) }): pemanggilan dengan trailing lambda. Di dalam block, append merujuk ke method StringBuilder.append tanpa prefix this. — persis seperti di dalam method class.
  9. Baris 53-55: perbandingan langsung antara lambda biasa (String) -> String dan receiver lambda String.() -> String. Keduanya menghasilkan output yang sama, tetapi cara pemanggilan berbeda.

Perbandingan Lambda Biasa vs Receiver Lambda #

AspekLambda Biasa (A) -> BReceiver Lambda A.() -> B
ParameterEksplisit a -> ...Implisit this
Pemanggilan membera.foo()foo() atau this.foo()
Cara panggillambda(a)a.lambda() atau a.lambda() via extension
Konteks idiomatikTransformasiDSL, builder, scope function

Mengapa Receiver Function Type Penting #

Receiver function type memungkinkan kita menulis DSL yang terbaca seperti blok konfigurasi alami. Standard library Kotlin memanfaatkan pola ini di banyak tempat:

  • buildString { append(...) } — this adalah StringBuilder.
  • apply { ... } — this adalah objek yang dikonfigurasi.
  • with(obj) { ... } — this adalah obj.
  • run { ... } — this adalah receiver.

Tanpa receiver function type, kode DSL akan terlihat berantakan dengan prefix eksplisit di setiap baris.

Referensi Lanjutan #

Penutup #

Receiver function type adalah kunci yang membuat Kotlin cocok untuk membangun DSL. Dengan this otomatis terikat ke receiver, kode di dalam block terbaca seperti method class — ringkas dan terfokus. Selanjutnya, kita akan melihat bagaimana receiver function type dipadukan dengan konsep extension function menjadi extension lambda yang dapat disimpan dalam variabel dan dipanggil pada instance kapan saja.