Fungsi Ekspresi Tunggal

Gaya fungsi satu ekspresi dan batasan inferensi tipenya.

Daftar isi

Fungsi ekspresi tunggal (single-expression function) adalah fungsi yang isinya hanya satu ekspresi dan ditulis setelah tanda sama dengan, tanpa kurung kurawal maupun pernyataan return. Bentuk ini memperpendek deklarasi fungsi sederhana, dan compiler Kotlin dapat menginferensi tipe kembaliannya secara langsung. Topik ini membahas bentuk tersebut, perilaku inferensi tipenya, serta kasus yang menuntut penulisan tipe secara eksplisit.

Bentuk satu ekspresi#

Bentuk umumnya memasangkan nama fungsi, daftar parameter, tanda sama dengan, lalu satu ekspresi yang nilainya menjadi hasil fungsi. Kurung kurawal, pernyataan return, dan tipe kembalian semuanya dihilangkan. Bentuk yang sama bila ditulis dengan isi blok memerlukan tambahan kurung kurawal, pernyataan return, dan tipe kembalian, sehingga untuk fungsi sesederhana ini bentuk satu ekspresi lebih ringkas tanpa mengurangi kejelasan. Program berikut memuat tiga fungsi dengan bentuk tersebut, yang masing-masing menghasilkan nilai Int, String, dan Unit.

kotlin main.kt
fun duaKali(x: Int) = x * 2

fun sapa(nama: String) = "Halo, $nama!"

fun cetakJudul(teks: String) = println("== $teks ==")

fun main() {
    cetakJudul("Statistik")
    println(duaKali(24))
    println(sapa("Ali"))
}
bash
# compiler Kotlin dan pustaka standar yang dipakai jalur ini
export PATH=/home/kal/my-project/tools/kotlinc/bin:/home/kal/my-project/tools/jdk-merged/bin:$PATH
export STDLIB=/home/kal/my-project/tools/kotlinc/lib/kotlin-stdlib.jar
# kompilasi berkas main.kt menjadi out.jar, lalu jalankan programnya
kotlinc main.kt -d out.jar && java -cp "out.jar:$STDLIB" MainKt
text Keluaran
== Statistik ==
48
Halo, Ali!

Fungsi duaKali menghasilkan x * 2, sehingga tipe kembaliannya diinferensi sebagai Int. Fungsi sapa menghasilkan sebuah string yang disusun dengan string template, sedangkan cetakJudul menghasilkan Unit karena pemanggilan println tidak mengirim nilai yang berguna. Pada fungsi ketiga, tipe Unit tetap diperoleh melalui inferensi meskipun tidak ditulis, dan hasil pemanggilannya pun tidak membawa nilai yang dapat dipakai.

Inferensi tipe dan batasannya#

Compiler menentukan tipe kembalian dari ekspresi yang ditulis, sehingga tipe yang diperoleh selalu tipe paling spesifik dari ekspresi tersebut. Inferensi ini hanya berlaku pada bentuk satu ekspresi, sedangkan fungsi berisi blok tetap menuntut tipe kembalian eksplisit. Batas lainnya muncul pada fungsi rekursif. Compiler perlu mengetahui tipe kembalian untuk memeriksa pemanggilan rekursifnya, tetapi tipe itu justru baru diketahui dari ekspresi yang sedang diperiksa, sehingga pemeriksaan berputar tanpa titik awal. Berkas berikut memuat fungsi faktorial bentuk satu ekspresi tanpa tipe kembalian.

kotlin inferensi.kt
fun faktorial(n: Int) = if (n <= 1) 1 else n * faktorial(n - 1)
bash
# kompilasi berkas inferensi.kt untuk melihat pesan error dari compiler
kotlinc inferensi.kt -d inferensi.jar
text Keluaran
inferensi.kt:1:48: error: type checking has run into a recursive problem. Easiest workaround: specify the types of your declarations explicitly.
fun faktorial(n: Int) = if (n <= 1) 1 else n * faktorial(n - 1)
                                               ^^^^^^^^^^^^^^^^

Pesan error type checking has run into a recursive problem menyatakan masalahnya secara langsung, dan saran perbaikannya adalah menuliskan tipe deklarasi secara eksplisit. Dengan menambahkan : Int pada deklarasi, fungsi yang sama langsung lolos kompilasi karena pemanggilan rekursifnya kini dapat diperiksa terhadap tipe yang sudah diketahui. Aturan yang sama berlaku untuk sekelompok fungsi yang saling memanggil secara berbalik.

Kapan tipe eksplisit dituliskan#

Selain fungsi rekursif, tipe kembalian perlu dituliskan ketika tipe yang diinginkan lebih umum daripada hasil inferensi. Compiler selalu memilih tipe paling spesifik, sehingga pada fun satu(): Number = 1 tipe eksplisit wajib ditulis untuk menyatakan kembalian Number, sedangkan tanpa tipe, inferensinya menjadi Int. Dokumentasi resmi Kotlin menyarankan pemeriksaan hasil inferensi karena compiler dapat memperoleh tipe yang lebih spesifik daripada yang dimaksudkan penulisnya.

Fungsi yang menjadi bagian dari library publik juga diuntungkan oleh tipe eksplisit, karena tipe kembalian yang tertulis pada deklarasi berfungsi sebagai kontrak bagi pemakai fungsi tersebut. Untuk fungsi privat dengan ekspresi yang jelas, inferensi mengurangi kebisingan tanpa menimbulkan risiko. Konvensi penulisan Kotlin menyarankan bentuk satu ekspresi untuk fungsi pendek, sedangkan fungsi dengan alur yang lebih kompleks tetap ditulis dengan isi blok.

Ringkasan#

  • Fungsi ekspresi tunggal menuliskan satu ekspresi setelah tanda sama dengan, tanpa return maupun kurung kurawal.
  • Compiler menginferensi tipe kembaliannya, termasuk Unit untuk ekspresi yang tidak mengirim nilai berguna.
  • Fungsi rekursif dan fungsi yang saling memanggil wajib menuliskan tipe kembalian secara eksplisit.
  • Tipe eksplisit dituliskan pula bila kembalian yang diinginkan lebih umum daripada hasil inferensi.

Referensi#