Lambda

Lambda sebagai Proc ketat: perbedaan aturan arity dan perilaku return dibanding proc.

Daftar isi

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.

ruby buat-lambda.rb
# 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)
text Keluaran
Salam, Dewi!
81
true

Kedua 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.

ruby arity-ketat.rb
# 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
end
text Keluaran
proc: 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.

ruby return-lambda.rb
# 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_lambda
text Keluaran
lambda berjalan
metode berlanjut, lambda mengembalikan 99
metode selesai

Metode 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.

ruby return-proc.rb
# 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_proc
text Keluaran
proc berjalan
99

Pada 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.

ruby lambda-check.rb
# lambda? membedakan lambda dari proc biasa
l = ->(x) { x }
pr = proc { |x| x }

puts l.lambda?
puts pr.lambda?
text Keluaran
true
false
Perilakuproclambda
Cara membuatProc.new { } atau proc { }lambda { } atau ->(n) { n * n }
Jumlah argumenLonggar, kekurangan diisi nil dan kelebihan dibuangKetat, pemanggilan yang menyimpang menimbulkan ArgumentError
return di dalam badannyaKeluar dari metode tempat proc dibuatKeluar dari lambda itu sendiri
lambda?falsetrue

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.

ruby return-proc-lain-tempat.rb
# 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
end
text Keluaran
LocalJumpError
unexpected return

Pesan 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.
  • return di dalam lambda mengakhiri lambda itu saja, sedangkan return di dalam proc mengakhiri metode tempat proc dibuat.
  • lambda? membedakan lambda dari proc biasa, dan tabel perbandingan proc dan lambda merangkum kontrak keduanya.

Referensi#