Saya hanya berpikir betapa lebih mudahnya membaca kode jika, ketika memanggil suatu fungsi, Anda dapat menulis:
doFunction(param1=something, param2=somethingElse);
Saya tidak bisa memikirkan kekurangan dan itu akan membuat kode lebih mudah dibaca. Saya tahu Anda bisa melewatkan array sebagai satu-satunya argumen dan memiliki kunci array sebagai nama parameter, namun itu masih belum bisa dibaca.
Apakah ada kerugian dari ini yang saya lewatkan? Jika tidak, mengapa banyak bahasa tidak mengizinkan ini?
Jawaban:
Menentukan nama parameter tidak selalu membuat kode lebih mudah dibaca: sebagai contoh, apakah Anda lebih suka membaca
min(first=0, second=1)
ataumin(0, 1)
?Jika Anda menerima argumen paragraf sebelumnya, maka cukup jelas bahwa menentukan nama parameter tidak harus wajib. Mengapa tidak semua bahasa membuat menentukan nama parameter sebagai opsi yang valid?
Saya dapat memikirkan setidaknya dua alasan:
Perhatikan bahwa saya tidak tahu bahasa apa pun yang mengimplementasikan parameter bernama tanpa juga menerapkan parameter opsional (yang memerlukan parameter bernama) - jadi Anda harus waspada terhadap terlalu tinggi manfaat keterbacaannya, yang dapat lebih konsisten diperoleh dengan definisi Antarmuka Fasih .
sumber
Parameter Yang Dinamai Membuat Kode Lebih Mudah Dibaca, Lebih Keras Untuk Menulis
Ketika saya membaca sepotong kode, parameter bernama dapat memperkenalkan konteks yang membuat kode lebih mudah dimengerti. Perhatikan misalnya konstruktor ini:
Color(1, 102, 205, 170)
. Apakah maksudnya itu? Memang,Color(alpha: 1, red: 102, green: 205, blue: 170)
akan jauh lebih mudah dibaca. Tapi sayangnya, Compiler mengatakan "tidak" - ia inginColor(a: 1, r: 102, g: 205, b: 170)
. Saat menulis kode menggunakan parameter bernama, Anda menghabiskan waktu yang tidak perlu mencari nama yang tepat - lebih mudah untuk melupakan nama-nama persis dari beberapa parameter daripada melupakan urutannya.Ini sekali menggigit saya ketika menggunakan
DateTime
API yang memiliki dua kelas saudara untuk poin dan durasi dengan antarmuka yang hampir sama. SementaraDateTime->new(...)
menerimasecond => 30
argumen, yangDateTime::Duration->new(...)
diinginkanseconds => 30
, dan serupa untuk unit lain. Ya, itu benar-benar masuk akal, tetapi ini menunjukkan kepada saya bahwa parameter bernama ≠ kemudahan penggunaan.Nama Buruk Bahkan Tidak Membuatnya Lebih Mudah Dibaca
Contoh lain bagaimana parameter bernama bisa jelek mungkin bahasa R. Sepotong kode ini menciptakan plot data:
Anda melihat dua argumen posisi untuk baris data x dan y , dan kemudian daftar parameter bernama. Ada banyak lagi opsi dengan standar, dan hanya yang terdaftar yang standarnya ingin saya ubah atau tetapkan secara eksplisit. Setelah kami mengabaikan bahwa kode ini menggunakan angka ajaib, dan dapat mengambil manfaat dari menggunakan enum (jika R punya!), Masalahnya adalah bahwa banyak dari nama parameter ini agak tidak dapat diuraikan.
pch
sebenarnya karakter plot, mesin terbang yang akan ditarik untuk setiap titik data.17
adalah lingkaran kosong, atau sesuatu seperti itu.lty
adalah tipe garis. Inilah1
garis yang kuat.bty
adalah tipe kotak. Mengaturnya untuk"n"
menghindari kotak yang ditarik di sekitar plot.ann
mengontrol tampilan anotasi sumbu.Untuk seseorang yang tidak tahu arti setiap singkatan, opsi ini agak membingungkan. Ini juga mengungkapkan mengapa R menggunakan label ini: Bukan sebagai kode yang mendokumentasikan diri, tetapi (menjadi bahasa yang diketik secara dinamis) sebagai kunci untuk memetakan nilai ke variabel yang benar.
Sifat Parameter Dan Tanda Tangan
Tanda tangan fungsi mungkin memiliki properti berikut:
Bahasa yang berbeda mendarat pada koordinat yang berbeda dari sistem ini. Dalam C, argumen diperintahkan, tidak disebutkan namanya, selalu diperlukan, dan dapat menjadi varargs. Di Jawa situasinya serupa, kecuali bahwa tanda tangan dapat kelebihan beban. Di Objective C, tanda tangan diperintahkan, dinamai, diperlukan, dan tidak dapat kelebihan karena itu hanya gula sintaksis sekitar C.
Bahasa yang diketik secara dinamis dengan varargs (antarmuka baris perintah, Perl, ...) dapat meniru parameter bernama opsional. Bahasa dengan ukuran tanda tangan berlebihan memiliki sesuatu seperti parameter opsional posisi.
Bagaimana Tidak Untuk Menerapkan Parameter Yang Bernama
Ketika memikirkan parameter bernama, kita biasanya mengasumsikan parameter bernama, opsional, tidak berurutan. Menerapkan ini sulit.
Parameter opsional dapat memiliki nilai default. Ini harus ditentukan oleh fungsi yang dipanggil dan tidak boleh dikompilasi ke dalam kode panggilan. Jika tidak, default tidak dapat diperbarui tanpa mengkompilasi ulang semua kode dependen.
Sekarang pertanyaan penting adalah bagaimana argumen sebenarnya diteruskan ke fungsi. Dengan parameter yang dipesan, args dapat dikirimkan dalam register, atau dalam urutan yang melekat pada stack. Ketika kami mengecualikan register untuk sesaat, masalahnya adalah bagaimana cara menempatkan argumen opsional yang tidak diurutkan ke dalam tumpukan.
Untuk itu, kita perlu beberapa urutan atas argumen opsional. Bagaimana jika kode deklarasi diubah? Karena urutannya tidak relevan, pemesanan ulang dalam deklarasi fungsi tidak boleh mengubah posisi nilai pada stack. Kami juga harus mempertimbangkan jika menambahkan parameter opsional baru dimungkinkan. Dari perspektif pengguna, ini kelihatannya demikian, karena kode yang tidak menggunakan parameter sebelumnya harus tetap bekerja dengan parameter baru. Jadi ini tidak termasuk pemesanan seperti menggunakan urutan dalam deklarasi atau menggunakan urutan alfabet.
Pertimbangkan ini juga dalam terang subtyping dan Prinsip Pergantian Liskov - dalam output yang dikompilasi, instruksi yang sama harus dapat memanggil metode pada subtipe dengan parameter yang mungkin baru bernama, dan pada supertipe.
Kemungkinan Implementasi
Jika kita tidak dapat memiliki urutan yang pasti, maka kita memerlukan beberapa struktur data yang tidak teratur.
Implementasi yang paling sederhana adalah dengan hanya memberikan nama parameter beserta nilainya. Ini adalah bagaimana params yang dinamai diemulasi dalam Perl atau dengan alat baris perintah. Ini menyelesaikan semua masalah ekstensi yang disebutkan di atas, tetapi bisa menjadi pemborosan ruang - bukan pilihan dalam kode kinerja-kritis. Juga, memproses params yang dinamai ini sekarang jauh lebih rumit daripada sekadar mengeluarkan nilai dari stack.
Sebenarnya, persyaratan ruang dapat dikurangi dengan menggunakan penggabungan string, yang dapat mengurangi perbandingan string di kemudian hari menjadi perbandingan pointer (kecuali jika tidak dapat dijamin bahwa string statis sebenarnya dikumpulkan, dalam hal ini kedua string harus dibandingkan dalam detail).
Sebagai gantinya, kami juga bisa meneruskan struktur data pintar yang berfungsi sebagai kamus argumen bernama. Ini murah di sisi penelepon, karena set kunci secara statis dikenal di lokasi panggilan. Ini akan memungkinkan untuk membuat fungsi hash yang sempurna atau untuk menghitung ulang sebuah trie. Callee masih harus menguji keberadaan semua nama parameter yang mungkin agak mahal. Sesuatu seperti ini digunakan oleh Python.
Jadi itu terlalu mahal dalam banyak kasus
Jika suatu fungsi dengan parameter bernama harus dapat diperluas dengan benar, pemesanan definitif tidak dapat diasumsikan. Jadi hanya ada dua solusi:
Perangkap Lainnya
Nama-nama variabel dalam deklarasi fungsi biasanya memiliki beberapa makna internal dan bukan bagian dari antarmuka - bahkan jika banyak alat dokumentasi masih akan menunjukkannya. Dalam banyak kasus Anda ingin nama yang berbeda untuk variabel internal dan argumen bernama yang sesuai. Bahasa yang tidak memungkinkan memilih nama yang terlihat secara eksternal dari parameter bernama tidak mendapatkan banyak dari mereka jika nama variabel tidak digunakan dengan konteks panggilan dalam pikiran.
Masalah dengan emulasi argumen bernama adalah kurangnya pemeriksaan statis pada sisi pemanggil. Ini sangat mudah untuk dilupakan ketika melewati kamus argumen (melihat Anda, Python). Hal ini penting karena lewat kamus adalah solusi umum, misalnya dalam JavaScript:
foo({bar: "baz", qux: 42})
. Di sini, baik jenis nilai maupun keberadaan atau ketiadaan nama-nama tertentu dapat diperiksa secara statis.Mengemulasi Parameter Bernama (Dalam Bahasa yang Diketik Secara Statis)
Cukup menggunakan string sebagai kunci, dan objek apa pun sebagai nilai tidak terlalu berguna di hadapan pemeriksa tipe statis. Namun, argumen bernama dapat ditiru dengan struct, atau objek literal:
sumber
it is easier to forget the exact names of some parameters than it is to forget their order
" ... itu pernyataan yang menarik.Untuk alasan yang sama bahwa Notasi Hongaria tidak lagi digunakan secara luas; Intellisense (atau yang setara secara moral dalam IDE non-Microsoft). Sebagian besar IDE modern akan memberi tahu Anda segala sesuatu yang perlu Anda ketahui tentang parameter dengan hanya mengarahkan referensi parameter.
Yang mengatakan, sejumlah bahasa mendukung parameter bernama, termasuk C # dan Delphi. Dalam C #, ini opsional, jadi Anda tidak perlu menggunakannya jika tidak mau, dan ada cara lain untuk secara khusus mendeklarasikan anggota, seperti inisialisasi objek.
Parameter Bernama sebagian besar berguna ketika Anda hanya ingin menentukan subset parameter opsional, dan tidak semuanya. Dalam C #, ini sangat berguna karena Anda tidak lagi memerlukan banyak metode kelebihan beban untuk memberikan fleksibilitas kepada programmer ini.
sumber
sin(radians=2)
, Anda tidak perlu "Intellisense".Bash tentu saja mendukung gaya pemrograman ini, dan baik Perl maupun Ruby mendukung lewatnya daftar parameter nama / nilai (seperti halnya bahasa apa pun dengan dukungan hash / peta asli). Tidak ada yang menghentikan Anda dari memilih untuk mendefinisikan struct / record atau hash / map yang melampirkan nama ke parameter.
Untuk bahasa yang menyertakan toko hash / map / keyvalue secara asli, Anda bisa mendapatkan fungsionalitas yang Anda inginkan, cukup dengan mengadopsi idiom untuk meneruskan hash / nilai hash ke fungsi / metode Anda. Setelah Anda mencobanya pada suatu proyek, Anda akan memiliki wawasan yang lebih baik tentang apakah Anda telah mendapatkan sesuatu, baik dari peningkatan produktivitas yang berasal dari kemudahan penggunaan, atau peningkatan kualitas melalui pengurangan cacat.
Perhatikan bahwa programmer berpengalaman telah merasa nyaman dengan melewati parameter berdasarkan urutan / slot. Anda juga dapat menemukan bahwa idiom ini hanya bernilai ketika Anda memiliki lebih dari beberapa argumen (katakan> 5/6). Dan karena sejumlah besar argumen sering menunjukkan metode yang terlalu kompleks, Anda mungkin menemukan bahwa ungkapan ini hanya bermanfaat untuk metode yang paling kompleks.
sumber
Saya pikir itu alasan yang sama mengapa c # lebih populer daripada VB.net. Sementara VB.NET lebih "dapat dibaca" misalnya Anda mengetik "end if" daripada braket penutup, itu hanya berakhir menjadi lebih banyak hal yang melengkapi kode dan akhirnya membuatnya lebih sulit untuk dipahami.
Ternyata apa yang membuat kode lebih mudah dipahami adalah keringkasan. Semakin sedikit semakin baik. Nama parameter fungsi biasanya cukup jelas, dan jangan terlalu jauh untuk membantu Anda memahami kode.
sumber
Parameter bernama adalah solusi untuk masalah dalam refactoring kode sumber dan tidak dimaksudkan untuk membuat kode sumber lebih mudah dibaca . Parameter bernama digunakan untuk membantu kompiler / pengurai dalam menyelesaikan nilai default untuk panggilan fungsi. Jika Anda ingin membuat kode lebih mudah dibaca, daripada menambahkan komentar yang bermakna.
Bahasa yang sulit untuk refactor sering mendukung parameter bernama, karena
foo(1)
akan rusak ketika tanda tanganfoo()
perubahan, tetapifoo(name:1)
lebih kecil kemungkinannya untuk istirahat yang membutuhkan lebih sedikit usaha dari programmer untuk melakukan perubahanfoo
.Apa yang Anda lakukan ketika Anda harus memperkenalkan parameter baru ke fungsi berikut, dan ada ratusan atau ribuan baris kode yang memanggil fungsi itu?
Sebagian besar programmer akan melakukan hal berikut.
Sekarang, tidak ada refactoring yang diperlukan dan fungsi dapat dijalankan dalam mode lawas saat
gender
nol.Untuk spesifik
gender
nilai sekarang HARDCODED menjadi panggilan untukage
. Seperti contoh ini:Programmer melihat definisi fungsi, melihat yang
age
memiliki nilai default0
dan menggunakan nilai itu.Sekarang nilai default untuk
age
definisi fungsi sama sekali tidak berguna.Parameter bernama memungkinkan Anda untuk menghindari masalah ini.
Parameter baru dapat ditambahkan ke
foo
dan Anda tidak perlu khawatir tentang urutan mereka ditambahkan dan Anda dapat mengubah nilai default mengetahui bahwa default yang Anda atur adalah benar-benar nilai default yang sebenarnya.sumber