Lambda adalah objek Proc yang menegakkan aturan pemanggilannya dengan lebih ketat. Seperti proc, lambda menyimpan kode menjadi objek yang dipanggil dengan .call, tetapi lambda menolak jumlah argumen yang tidak sesuai dan menangani return sebagaimana metode biasa. Topik ini membahas dua bentuk sintaks pembuatan lambda, yaitu lambda dan panah ->, perbandingan pemeriksaan jumlah argumen antara lambda dan proc, perilaku return di dalam keduanya, metode lambda?, serta tabel perbandingan proc dan lambda sebagai penutup.
Membuat lambda dengan lambda dan ->#
Kernel#lambda menerima blok (block) dan mengembalikan objek Proc yang bertanda lambda. Bentuk kedua adalah literal panah ->, yaitu sintaks ringkas yang setara dengan lambda dan menjadi gaya yang paling umum pada kode modern. Daftar parameter lambda ditulis dalam tanda kurung tepat setelah panah, sedangkan isi kodenya ditulis di antara kurung kurawal. Karena lambda adalah objek Proc, lambda dipanggil dengan .call dan dapat disimpan sebagaimana proc pada umumnya.
# Lambda dibuat dengan lambda atau panah ->
salam = lambda { |nama| "Salam, #{nama}!" }
kuadrat = ->(n) { n * n }
puts salam.call("Dewi")
puts kuadrat.call(9)
puts salam.is_a?(Proc)Salam, Dewi!
81
trueKedua lambda pada contoh menghasilkan objek kelas Proc, sehingga salam.is_a?(Proc) bernilai true. Perbedaan lambda dengan proc tidak terletak pada jenis objeknya, melainkan pada aturan pemanggilannya yang ditegakkan ketika lambda dipanggil. Dua aturan itu menyangkut jumlah argumen dan perilaku return, dan keduanya dibahas berikut ini.
Arity yang ketat#
Proc mengisi parameter yang kekurangan nilai dengan nil dan membuang nilai yang berlebih, sehingga pemanggilannya nyaris tidak pernah gagal. Lambda berperilaku sebaliknya, yaitu menolak setiap pemanggilan yang jumlah argumennya tidak sesuai dengan parameternya. Pemanggilan yang menyimpang menimbulkan ArgumentError dengan pesan yang menyebutkan jumlah yang diberikan dan jumlah yang diharapkan. Pemeriksaan ini ditegakkan pada saat lambda dipanggil, bukan pada saat lambda dibuat, dan berlaku sama pada lambda yang dibuat dengan panah -> karena keduanya menghasilkan objek yang identik.
# proc bersikap longgar, lambda menegakkan jumlah argumen
proc_fleksibel = proc { |a, b| "proc: a=#{a.inspect}, b=#{b.inspect}" }
lambda_ketat = lambda { |a, b| "lambda: a=#{a.inspect}, b=#{b.inspect}" }
puts proc_fleksibel.call(1)
puts proc_fleksibel.call(1, 2, 3)
puts lambda_ketat.call(1, 2)
begin
lambda_ketat.call(1)
rescue => e
puts e.class
puts e.message
endproc: a=1, b=nil
proc: a=1, b=2
lambda: a=1, b=2
ArgumentError
wrong number of arguments (given 1, expected 2)Dua pemanggilan pertama menunjukkan sifat longgar proc, yaitu mengisi b dengan nil ketika nilai kurang dan membuang nilai ketiga ketika argumen berlebih. Lambda dengan parameter yang sama menerima pemanggilan dengan dua argumen tanpa masalah, tetapi menolak pemanggilan satu argumen dengan ArgumentError. Kontrak yang ketat semacam ini berguna ketika kode pemanggil lambda memang wajib menyerahkan jumlah argumen yang benar, karena kesalahan hitung langsung terlihat dan tidak berlanjut sebagai nilai nil tanpa peringatan.
Perilaku return#
Perbedaan kedua menyangkut kata kunci return. Di dalam lambda, return hanya mengakhiri lambda itu sendiri dan mengembalikan nilainya kepada pemanggilnya, sehingga metode yang memanggilnya terus berjalan. Di dalam proc, return melompat keluar dari metode tempat proc itu dibuat, sehingga sisa badan metode tidak pernah dijalankan.
# return di dalam lambda hanya keluar dari lambda itu sendiri
def uji_lambda
langkah = lambda do
puts "lambda berjalan"
return 99
end
hasil = langkah.call
puts "metode berlanjut, lambda mengembalikan #{hasil}"
"metode selesai"
end
puts uji_lambdalambda berjalan
metode berlanjut, lambda mengembalikan 99
metode selesaiMetode uji_lambda membuat lambda yang memanggil return 99 di tengah badannya. Nilai 99 dikembalikan kepada baris pemanggilnya, kemudian eksekusi metode berlanjut dan mencetak laporannya hingga selesai. Dari sudut pandang metode, pemanggilan lambda yang berisi return tidak berbeda dengan pemanggilan yang mengembalikan nilai secara normal.
# return di dalam proc keluar dari metode pembungkusnya
def uji_proc
langkah = proc do
puts "proc berjalan"
return 99
end
hasil = langkah.call
puts "baris ini tidak pernah tercapai"
"metode selesai"
end
puts uji_procproc berjalan
99Pada metode uji_proc, return 99 di dalam proc tidak mengakhiri proc saja, melainkan langsung mengakhiri metode uji_proc dengan nilai 99. Baris yang mencetak baris ini tidak pernah tercapai tidak pernah dijalankan, dan puts uji_proc menampilkan 99 sebagai nilai kembalian metode. Sifat ini menjadikan proc mirip dengan perpanjangan badan metode tempatnya dibuat, sedangkan lambda merupakan unit kode yang berdiri sendiri.
lambda? dan perbandingan proc dengan lambda#
Metode lambda? mengembalikan true apabila objek Proc yang memanggilnya adalah lambda dan false apabila proc biasa. Metode ini berguna ketika kode menerima objek Proc dari luar dan perlu mengetahui aturan pemanggilannya sebelum mengeksekusinya. Tabel berikut merangkum perbedaan proc dan lambda sebagai acuan ringkas.
# lambda? membedakan lambda dari proc biasa
l = ->(x) { x }
pr = proc { |x| x }
puts l.lambda?
puts pr.lambda?true
false| Perilaku | proc | lambda |
|---|---|---|
| Cara membuat | Proc.new { } atau proc { } | lambda { } atau ->(n) { n * n } |
| Jumlah argumen | Longgar, kekurangan diisi nil dan kelebihan dibuang | Ketat, pemanggilan yang menyimpang menimbulkan ArgumentError |
return di dalam badannya | Keluar dari metode tempat proc dibuat | Keluar dari lambda itu sendiri |
lambda? | false | true |
Kedua objek berbagi kelas yang sama, sehingga keduanya dapat disimpan, diteruskan dengan tanda &, dan dipanggil dengan .call. Pilihan di antara keduanya ditentukan oleh kontrak yang diinginkan. Lambda dipilih ketika jumlah argumen harus dijaga dan alur return harus tetap berada di dalam unit kodenya, sedangkan proc dipilih ketika kelenturan itu diutamakan atau return memang tidak digunakan di dalam badannya.
Kesalahan umum#
Sifat return pada proc menimbulkan error yang sulit dilacak apabila proc dipanggil jauh dari tempat pembuatannya. Proc yang dibuat di dalam metode dan dipanggil setelah metode itu selesai sudah tidak memiliki metode pembungkus yang masih berjalan, sehingga return di dalam proc tidak lagi memiliki sasaran. Situasi ini sering muncul ketika proc disimpan untuk dipanggil nanti, misalnya dari struktur data atau dari kode yang berjalan pada peristiwa lain, karena metode pembuatnya tentu sudah selesai saat itu. Kasus berikut diperagakan dengan pernyataan begin ... rescue yang menangkap error di dalam kode.
# return di dalam proc dipanggil setelah metodenya selesai
def buat_langkah
proc { return 99 }
end
langkah = buat_langkah
begin
langkah.call
rescue => e
puts e.class
puts e.message
endLocalJumpError
unexpected returnPesan unexpected return menyatakan bahwa return di dalam proc tidak menemukan metode pembungkus yang dapat diakhirinya, karena metode buat_langkah sudah selesai jauh sebelum proc dipanggil. Perbaikannya adalah menghindari return pada proc yang akan dipanggil di luar metode pembuatnya dan menggantinya dengan nilai akhir badan proc, atau memastikan proc selalu dipanggil selagi metode pembuatnya masih berjalan. Lambda tidak terkena masalah ini karena return pada lambda selalu berhenti di dalam lambda itu sendiri.
Ringkasan#
- Lambda dibuat dengan
lambda { }atau->, dan keduanya menghasilkan objek Proc yang bertanda lambda. - Lambda menegakkan jumlah argumen, dan pemanggilan yang menyimpang menimbulkan
ArgumentError. returndi dalam lambda mengakhiri lambda itu saja, sedangkanreturndi dalam proc mengakhiri metode tempat proc dibuat.lambda?membedakan lambda dari proc biasa, dan tabel perbandingan proc dan lambda merangkum kontrak keduanya.
Referensi#
- Proc — Dokumentasi Ruby 3.4
— Dokumentasi kelas Proc mencakup
lambda?, perilaku arity, dan pembedaan lambda dengan proc. - Kernel#lambda — Dokumentasi Ruby 3.4 — Mengembalikan objek Proc yang jumlah argumennya diperiksa secara ketat.