Function yang baik seringkali pure — outputnya hanya bergantung pada input dan tidak mengubah apa pun di luar scope-nya. Function demikian mudah diuji, dapat diparalelkan, dan tidak menimbulkan kejutan saat dipanggil berulang. Sayangnya banyak tugas pemrograman memang memerlukan side effect: mencetak ke layar, menulis file, memperbarui database. Pada chapter penutup section Functions ini, kita akan membedakan pure dan impure function, lalu melihat kapan masing-masing layak dipakai.
Pure Function: Deterministik dan Tanpa Side Effect #
Sebuah function disebut pure bila memenuhi dua syarat: (1) untuk input yang sama, output selalu sama, dan (2) function tidak mengakibatkan side effect apa pun (tidak mengubah state global, tidak menulis ke file, tidak melakukan IO). Function matematika sederhana adalah contoh ideal.
import kotlin.random.Random
// Pure function: output hanya bergantung pada input, tanpa efek samping
fun tambah(a: Int, b: Int): Int = a + b
fun kuadrat(x: Int): Int = x * x
// Impure: memodifikasi state global
var jumlahPanggilan = 0
fun catatPanggilan(nama: String) {
jumlahPanggilan += 1
println("Memanggil $nama (total: $jumlahPanggilan)")
}
// Deterministik karena seed ditentukan; namun membaca Random
fun lemparDadu(seed: Long): Int {
val random = Random(seed)
return random.nextInt(1, 7)
}
// Impure: bergantung pada waktu dan menghasilkan output IO
fun capWaktu(): String {
val tahun = 2026
return "Log tahun $tahun"
}
fun main() {
println("2 + 3 = ${tambah(2, 3)}")
println("2 + 3 lagi = ${tambah(2, 3)}")
println("Kuadrat 6 = ${kuadrat(6)}")
catatPanggilan("tambah")
catatPanggilan("kuadrat")
catatPanggilan("tambah")
println("Lempar dadu (seed 42) pertama: ${lemparDadu(42)}")
println("Lempar dadu (seed 42) kedua: ${lemparDadu(42)}")
println(capWaktu())
}Output yang Dihasilkan:
2 + 3 = 5
2 + 3 lagi = 5
Kuadrat 6 = 36
Memanggil tambah (total: 1)
Memanggil kuadrat (total: 2)
Memanggil tambah (total: 3)
Lempar dadu (seed 42) pertama: 6
Lempar dadu (seed 42) kedua: 6
Log tahun 2026Mari kita bedah baris per baris:
fun tambah(a: Int, b: Int): Int = a + b: pure function. Output hanya bergantung padaadanb. Tidak ada state global yang berubah, tidak ada IO. Memanggiltambah(2, 3)seribu kali tetap menghasilkan5.var jumlahPanggilan = 0: variabel global yang dapat berubah. Variabel ini menjadi sumber side effect pada functioncatatPanggilan.fun catatPanggilan(nama: String): impure function. Selain mencetak ke layar (IO), function ini menambahjumlahPanggilan— state global berubah. Dua pemanggilan dengan argumen yang sama menghasilkan output yang berbeda.fun lemparDadu(seed: Long): Int: secara teknis tidak pure karena membaca sumber pseudo-random, tetapi dengan seed yang ditentukan, hasilnya deterministik. Ini disebut deterministic impure — berguna untuk pengujian.fun capWaktu(): String: impure karena output bergantung pada waktu dan dapat juga melakukan IO. Pemanggilan dengan argumen kosong di waktu berbeda menghasilkan output berbeda.
Karakteristik Pure Function #
Pure function memiliki empat ciri yang memudahkan pengujian dan analisis:
- Deterministik: input yang sama selalu menghasilkan output yang sama
- Tanpa side effect: tidak mengubah variabel global, tidak menulis file, tidak mencetak ke layar
- Transparan referensial: pemanggilan
tambah(2, 3)dapat diganti dengan literal5tanpa mengubah perilaku program - Mudah diparalelkan: karena tidak ada shared state, pure function aman dipanggil dari banyak thread
fun hitungDiskon(harga: Int, persen: Int): Int = harga * persen / 100
fun formatRupiah(nilai: Int): String = "Rp $nilai"Kedua function di atas pure. Memanggilnya dari banyak thread sekaligus aman karena tidak ada shared state. Konsep ini menjadi dasar pemrograman fungsional yang akan kita bahas tuntas pada section Lambdas dan Functional Programming.
Side Effect yang Umum #
Side effect tidak selalu buruk — banyak tugas program memang memerlukan side effect. Yang penting adalah kita menyadari side effect dan mengisolasi-nya agar mudah ditelusuri.
| Jenis Side Effect | Contoh | Catatan |
|---|---|---|
| Mutasi state global | var counter += 1 | Hindari bila bisa, ganti dengan return value |
| IO tulis | println(...), file write | Pisahkan ke lapisan terluar aplikasi |
| IO baca non-deterministik | Random.nextInt(), System.currentTimeMillis() | Suntikkan dependency agar dapat diuji |
| Mutasi parameter | list.add(...) pada parameter yang diterima | Hindari kecuali memang jelas dari nama function |
| Exception | throw IllegalStateException(...) | Function yang melempar exception tidak pure |
// Pure: logika bisnis
fun hitungTotal(items: List<Int>): Int {
var total = 0
for (n in items) total += n
return total
}
// Impure: lapisan IO
fun cetakTotal(items: List<Int>) {
val total = hitungTotal(items) // panggil pure function
println("Total: $total")
}Pola di atas memisahkan logika bisnis (pure) dari IO (impure). Logika bisnis dapat diuji tanpa memalsukan stdout. IO tetap berada di lapisan terluar.
Mengapa Pure Function Penting #
Pure function memberi tiga manfaat praktis:
- Pengujian mudah: tidak perlu menyiapkan state global atau memalsukan IO. Cukup panggil dengan input dan bandingkan output.
- Refactor aman: pure function dapat dipindahkan, diganti namanya, atau dipanggil ulang tanpa khawatir mengubah state di tempat lain.
- Konkurensi: pure function aman dipanggil dari banyak thread karena tidak ada shared state.
Referensi Lanjutan #
- Kotlin functions — rujukan function Kotlin sebagai pondasi penulisan pure function
- Kotlin coding conventions — konvensi penulisan Kotlin yang mendorong function murni dan minimal efek samping
Ringkasan Section Functions #
Pure function mengembalikan output yang hanya bergantung pada input tanpa side effect. Impure function mengakses state global, melakukan IO, atau membaca sumber non-deterministik. Target praktis adalah memisahkan logika bisnis yang pure dari lapisan IO yang impure. Sampai di sini, kita telah membahas deklarasi function, parameter, return type, default dan named arguments, vararg, infix, operator, local, extension, tailrec, higher-order, function types, references, inline, noinline/crossinline, hingga pure functions. Section berikutnya akan membahas Collections — struktur data yang sering dipakai bersama higher-order function untuk transformasi dan filter data.