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.

kotlin
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:

text
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 2026

Mari kita bedah baris per baris:

  1. fun tambah(a: Int, b: Int): Int = a + b: pure function. Output hanya bergantung pada a dan b. Tidak ada state global yang berubah, tidak ada IO. Memanggil tambah(2, 3) seribu kali tetap menghasilkan 5.
  2. var jumlahPanggilan = 0: variabel global yang dapat berubah. Variabel ini menjadi sumber side effect pada function catatPanggilan.
  3. fun catatPanggilan(nama: String): impure function. Selain mencetak ke layar (IO), function ini menambah jumlahPanggilan — state global berubah. Dua pemanggilan dengan argumen yang sama menghasilkan output yang berbeda.
  4. 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.
  5. 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 literal 5 tanpa mengubah perilaku program
  • Mudah diparalelkan: karena tidak ada shared state, pure function aman dipanggil dari banyak thread
kotlin Contoh: pure function yang dapat diparalelkan
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 EffectContohCatatan
Mutasi state globalvar counter += 1Hindari bila bisa, ganti dengan return value
IO tulisprintln(...), file writePisahkan ke lapisan terluar aplikasi
IO baca non-deterministikRandom.nextInt(), System.currentTimeMillis()Suntikkan dependency agar dapat diuji
Mutasi parameterlist.add(...) pada parameter yang diterimaHindari kecuali memang jelas dari nama function
Exceptionthrow IllegalStateException(...)Function yang melempar exception tidak pure
kotlin Contoh: isolasi side effect
// 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 #

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.