with adalah satu-satunya scope function yang bukan extension function. Function ini menerima objek sebagai parameter pertama dan menjalankan block dengan this merujuk ke objek tersebut. Pada chapter ini kita akan melihat kapan with lebih cocok dipakai daripada run, bagaimana with membantu mengelompokkan beberapa panggilan pada objek yang sama, dan kapan with lebih natural daripada extension scope function. Kita juga akan melihat perbandingan langsung dengan run.
Apa Itu with #
Signature with:
inline fun <T, R> with(receiver: T, block: T.() -> R): R- Bentuk: function biasa, BUKAN extension.
- Receiver: parameter pertama
receiver(tersedia sebagaithisdi block). - Return: hasil block.
- Use case utama: mengelompokkan beberapa panggilan pada objek yang sama.
Tabel Perbandingan with dengan Scope Lain #
| Aspek | with |
|---|---|
| Bentuk | function biasa with(obj) { ... } |
| Receiver | this (parameter pertama) |
| Return | lambda result |
| Idiomatic use | Mengelompokkan panggilan pada objek yang sama |
| Bisa safe-call | Tidak — with tidak extension |
Pola with di Kode Nyata #
Mari kita lihat empat pola with yang umum.
// with_example.kt
// with: BUKAN extension function.
// Menerima objek, mengembalikan lambda result. Receiver `this`.
data class Konfigurasi(
var host: String = "",
var port: Int = 0,
var timeoutMs: Int = 0,
var debug: Boolean = false
)
fun main() {
val config = Konfigurasi()
// Pola 1: dengan `with` kita mengelompokkan beberapa panggilan pada objek.
val ringkasan = with(config) {
host = "127.0.0.1"
port = 8080
timeoutMs = 5_000
debug = true
"Konfigurasi: $host:$port (timeout=${timeoutMs}ms, debug=$debug)"
}
println(ringkasan)
// Pola 2: `with` untuk menghitung sesuatu dari beberapa property.
val tugas = mutableListOf("Belajar", "Latihan", "Proyek")
val jumlahTugas = with(tugas) {
val total = size
val selesai = count { it.length > 7 }
"Total $total, selesai $selesai"
}
println(jumlahTugas)
// Pola 3: perbandingan dengan run.
val sb = StringBuilder()
val hasilWith = with(sb) {
append("Halo, ")
append("Budi!")
toString()
}
println("Dengan with: $hasilWith")
// Pola 4: return value bukan objek.
val angka = 42
val deskripsi = with(angka) {
when {
this % 2 == 0 -> "genap"
else -> "ganjil"
}
}
println("42 adalah $deskripsi")
}Output yang Dihasilkan:
Konfigurasi: 127.0.0.1:8080 (timeout=5000ms, debug=true)
Total 3, selesai 0
Dengan with: Halo, Budi!
42 adalah genapMari kita telaah baris-baris kode di atas:
- Baris 8-13 (
data class Konfigurasi(...)): data class dengan beberapa mutable property. Kondisi ideal untukwithkarena kita akan mengubah beberapa property sekaligus. - Baris 17-24 (
val ringkasan = with(config) { ... }): pola mengelompokkan konfigurasi.with(config)mengikatthiskeconfig. Di dalam block, kita mengubah empat property (host,port,timeoutMs,debug) tanpa prefix. Block ditutup dengan string ringkasan yang menjadi nilairingkasan. Tanpawith, kita menulisconfig.host = ...; config.port = ...— prefix berulang. - Baris 27-32 (
with(tugas) { ... }): pola menghitung dari beberapa property. Di dalam block,sizedancount { ... }dipanggil padatugas. Block mengembalikan string deskripsi. Variabeltotaldanselesaitidak bocor ke scope luar. - Baris 35-40 (
with(sb) { append(...); append(...); toString() }): pola build string. Di dalam block,appenddipanggil tanpa prefix. Block ditutup dengantoString()yang menghasilkan string. Pola ini sering muncul saat membuat dokumen HTML/XML/JSON. - Baris 43-49 (
with(angka) { when { ... } }): pola return non-objek. Block tidak harus mengembalikan objek receiver. Di sini block mengembalikan string"genap"atau"ganjil"berdasarkan kondisithis % 2 == 0.
Kapan with Lebih Cocok Daripada run #
with lebih cocok dipakai saat:
- Objek sudah non-null dan pasti tidak null.
- Kita ingin mengelompokkan beberapa panggilan pada objek yang sama.
- Sintaks function biasa terasa lebih alami (memanggil
with(obj) { ... }di awal statement).
// with — function biasa, terbaca natural untuk objek non-null
val ringkasan = with(config) {
host = "127.0.0.1"
port = 8080
"config: $host:$port"
}
// run — extension, cocok untuk nullable
val ringkasan2 = config?.run {
host = "127.0.0.1"
port = 8080
"config: $host:$port"
}with untuk Reduksi Pengulangan #
Saat kita memanggil banyak method pada objek yang sama dalam satu blok kode, with dapat mengurangi pengulangan prefix:
val sb = StringBuilder()
with(sb) {
append("Baris 1\n")
append("Baris 2\n")
append("Baris 3\n")
}
val hasil = sb.toString()Tanpa with, kita menulis sb.append(...) tiga kali. Dengan with, prefix sb. dihilangkan dari setiap panggilan.
Referensi Lanjutan #
- Scope functions
— panduan resmi
withuntuk pengelompokan operasi pada objek - Higher-order functions and lambdas
— dasar lambda receiver pada
with
Penutup #
with adalah scope function untuk mengelompokkan beberapa panggilan pada objek yang sama. Karena bukan extension function, with tidak dapat dipakai dengan safe-call — bila objek bisa null, gunakan run. Dengan with, kode yang mengubah banyak property pada satu objek menjadi lebih ringkas dan terfokus. Selanjutnya, kita akan mempelajari apply — scope function yang mengembalikan objek itu sendiri, sangat populer untuk konfigurasi builder.