Kapan dan mengapa Anda harus menggunakan void (bukan misalnya bool / int)

30

Saya sesekali mengalami metode di mana pengembang memilih untuk mengembalikan sesuatu yang tidak penting untuk fungsi tersebut. Maksud saya, ketika melihat kode itu, ternyata berfungsi sama baiknya dengan voiddan setelah beberapa saat berpikir, saya bertanya, "Kenapa?" Apakah ini terdengar familier?

Kadang-kadang saya setuju bahwa paling sering lebih baik mengembalikan sesuatu seperti boolatau int, daripada hanya melakukan a void. Tapi saya tidak yakin, dalam gambaran besar, tentang pro dan kontra.

Bergantung pada situasi, mengembalikan suatu intdapat membuat penelepon mengetahui jumlah baris atau objek yang dipengaruhi oleh metode (misalnya, 5 catatan disimpan ke MSSQL). Jika metode seperti "InsertSomething" mengembalikan boolean, saya dapat meminta metode yang dirancang untuk kembali truejika berhasil, jika tidak false. Penelepon dapat memilih untuk bertindak atau tidak pada informasi itu.

Di samping itu,

  • Bisakah itu mengarah ke tujuan yang kurang jelas dari pemanggilan metode? Pengodean yang buruk sering memaksa saya untuk memeriksa ulang konten metode. Jika itu mengembalikan sesuatu, itu memberi tahu Anda bahwa metode adalah tipe Anda harus melakukan sesuatu dengan hasil yang dikembalikan.
  • Masalah lainnya adalah, jika implementasi metode tidak diketahui oleh Anda, apa yang diputuskan pengembang untuk kembali yang tidak berfungsi penting? Tentu saja Anda bisa berkomentar.
  • Nilai kembali harus diproses, ketika pemrosesan dapat berakhir pada braket penutupan metode.
  • Apa yang terjadi di bawah tenda? Apakah metode yang dipanggil dapatkan falsekarena kesalahan yang dilemparkan? Atau apakah itu kembali salah karena hasil yang dievaluasi?

Apa pengalaman Anda dengan ini? Bagaimana Anda akan bertindak atas hal ini?

Independen
sumber
1
Fungsi yang mengembalikan batal sama sekali bukan fungsi teknis. Itu hanya metode / prosedur. Mengembalikan voidsetidaknya memberi tahu pengembang bahwa nilai pengembalian metode tidak penting; ia melakukan suatu tindakan, alih-alih menghitung nilai.
KChaloux

Jawaban:

32

Dalam kasus nilai pengembalian bool untuk menunjukkan keberhasilan atau kegagalan suatu metode, saya lebih suka Tryparadigma -prefix yang digunakan dalam berbagai metode .NET.

Misalnya suatu void InsertRow()metode bisa melempar pengecualian jika sudah ada baris dengan kunci yang sama. Pertanyaannya adalah, apakah masuk akal untuk menganggap bahwa penelepon memastikan baris mereka unik sebelum memanggil InsertRow? Jika jawabannya tidak, maka saya juga akan memberikan bool TryInsertRow()yang mengembalikan false jika baris sudah ada. Dalam kasus lain, seperti kesalahan konektivitas db, TryInsertRow masih bisa melempar pengecualian, dengan asumsi bahwa menjaga konektivitas db adalah tanggung jawab pemanggil.

Plastik gelembung
sumber
4
1 untuk membuat perbedaan antara berurusan dengan kegagalan yang diharapkan dan yang tidak terduga - jawaban saya sendiri tidak cukup menekankan hal ini.
Péter Török
Benar-benar +1 untuk mencoba menciptakan prinsip untuk metode TryXX yang tampaknya membuat metode coba dan metode utama lebih mudah dipertahankan dan lebih mudah untuk memahami tujuannya.
Independen
+1 Dikatakan dengan baik. Kunci untuk jawaban terbaik untuk pertanyaan ini adalah bahwa kadang-kadang Anda ingin memberi penelepon opsi metode tegas yang akan memberikan pengecualian. Namun, dalam kasus-kasus ini, pengecualian tidak boleh ditangkap dan ditangani secara palsu dengan metode tegas. Intinya adalah bahwa penelepon dibuat bertanggung jawab. Di sisi lain, paradigma Try-(atau Monad) harus menangkap dan menangani pengecualian, lalu memberikan bool, atau Enum deskriptif jika diperlukan lebih banyak detail. Perhatikan bahwa pemanggil mengharapkan bahwa Try / Monad tidak akan pernah melempar pengecualian. Ini seperti titik masuk.
Suamere
Jadi karena pengecualian diharapkan tidak pernah terjadi dari Coba / Monad, namun bool tidak cukup deskriptif untuk memberi tahu pemanggil bahwa koneksi db gagal, atau permintaan http memiliki salah satu dari banyak nilai kembali yang diperlukan untuk bertindak secara berbeda, Anda dapat menggunakan Enum alih-alih bool untuk Try / Monad Anda.
Suamere
Jika Anda memiliki TryInsertRow - mengembalikan bool - jika, katakanlah, ada lebih dari satu kendala unik dalam database - bagaimana Anda tahu persis apa kesalahannya - dan mengomunikasikannya kepada pengguna? Haruskah jenis pengembalian yang lebih kaya digunakan yang berisi pesan kesalahan / kode & bool sukses?
niico
28

IMHO mengembalikan "kode status" berasal dari zaman historis, sebelum pengecualian menjadi biasa di bahasa tingkat menengah ke yang lebih tinggi seperti C #. Saat ini lebih baik untuk melemparkan pengecualian jika beberapa kesalahan tak terduga mencegah metode Anda berhasil. Dengan cara itu yakin kesalahan tidak luput dari perhatian, dan penelepon dapat menanganinya sebagaimana mestinya. Jadi dalam kasus ini, itu sangat baik untuk metode untuk mengembalikan apa-apa (yaitu void) daripada bendera status boolean atau kode status integer. (Tentu saja orang harus mendokumentasikan pengecualian apa yang dapat dilemparkan metode dan kapan.)

Di sisi lain, jika itu adalah fungsi dalam arti sempit, yaitu melakukan beberapa perhitungan berdasarkan parameter input, dan diharapkan mengembalikan hasil perhitungan itu, tipe pengembaliannya jelas.

Ada area abu-abu di antara keduanya, ketika seseorang dapat memutuskan untuk mengembalikan beberapa informasi "tambahan" dari metode tersebut, jika dianggap berguna bagi peneleponnya. Seperti contoh Anda tentang jumlah baris yang terpengaruh dalam sisipan. Atau untuk metode untuk menempatkan elemen ke koleksi asosiatif, mungkin berguna untuk mengembalikan nilai sebelumnya yang terkait dengan kunci itu, jika ada. Penggunaan tersebut dapat diidentifikasi dengan menganalisis dengan cermat skenario penggunaan API yang diketahui dan diantisipasi.

Péter Török
sumber
4
+1 untuk pengecualian atas kode status. Pengecualian (kata-kata buruk yang dimaksudkan) untuk ini adalah pola TryXX yang digunakan dengan baik.
Andy Lowry
éter aku bersamamu di sana. TcF dan tidak membungkam kesalahan! Mungkin, bagaimanapun, zona abu-abu. Ada mungkin selalu digunakan kembali sesuatu. Baris yang terpengaruh, ID yang dimasukkan terbaru, PID dari perangkat lunak yang dijalankan, tetapi saya pikir masih lebih mudah untuk berpikir "ya, saya kembalikan ini" ketika mengembangkan. Lalu, setahun kemudian ketika memperpanjang, "apa? Ini tidak ʻint someThing = RunProcess (x) 'apa yang terjadi jika tidak bisa berjalan?"
Independen
Memberi +1 informasi tambahan adalah alasan saya memberi kode metode seperti ini dalam bahasa tingkat tinggi seperti C #. Ini membuatnya mudah untuk menggunakan informasi tambahan saat Anda membutuhkannya.
ashes999
2
-1 Wow, kata-kata Anda sendiri sangat kontradiktif dan salah. Anda tidak boleh menggunakan pengecualian untuk aliran kontrol atau komunikasi. Mereka jauh lebih mahal daripada persyaratan. Kapan waktu "sebelum pengecualian menjadi biasa"? ... maksud Anda sebelum coba / tangkap blok sudah menjadi biasa? Pengecualian sudah biasa sejak selamanya. "Lempar pengecualian jika ada kesalahan tak terduga ..." Bagaimana Anda mengambil tindakan pada sesuatu yang tidak terduga? Mengapa Anda menangkap pengecualian, lalu melemparkannya kembali? Itu sangat mahal. Mengapa Anda mengatakan "kesalahan"? Kesalahan dan Pengecualian adalah hal yang berbeda.
Suamere
1
Dan siapa bilang pengecualian yang dilemparkan tidak akan luput dari perhatian? Tidak ada yang memaksa siapa pun untuk masuk dalam blok tangkap, mengapa tidak masuk dalam blok "lalu"? Mengapa "mendokumentasikan pengecualian apa yang dapat dilemparkan metode dan kapan"? Bagaimana kalau kita menulis kode self-documenting, dan suatu metode hanya mengembalikan enum dengan keadaan akhir yang diharapkan dari metode itu? Jika kemungkinan pengecualian dapat dihindari dengan memeriksa keadaan, mereka harus ditangkap dan ditangani tanpa melempar.
Suamere
14

Jawaban Peter mencakup pengecualian dengan baik. Pertimbangan lain di sini melibatkan Pemisahan Command-Query

Prinsip CQS mengatakan bahwa suatu metode harus berupa perintah, atau kueri dan bukan keduanya. Perintah tidak boleh mengembalikan nilai, hanya memodifikasi negara, dan permintaan hanya mengembalikan dan tidak mengubah negara. Ini menjaga semantik sangat jelas dan membantu membuat kode lebih mudah dibaca dan dipelihara.

Ada beberapa kasus yang melanggar prinsip CQS adalah ide yang bagus. Ini biasanya seputar kinerja atau keamanan utas.

Andy Lowry
sumber
1
-1 Salah dan Salah. Pertama, seluruh poin CQS terletak pada Q. Seorang penelepon harus bisa mendapatkan perhitungan atau panggilan eksternal melalui beberapa layanan stateful tanpa takut mengubah negara layanan itu. Selain itu, sementara CQS adalah prinsip yang bermanfaat untuk diikuti secara longgar, CQS hanya diikuti secara ketat dalam desain tertentu. Terakhir, bahkan dalam CQS yang ketat, tidak ada yang mengatakan perintah tidak bisa mengembalikan nilai, katanya tidak boleh menghitung atau memanggil perhitungan eksternal dan mengembalikan data . Baik C atau Q dapat merasa bebas untuk mengembalikan status akhir mereka, jika itu berguna bagi pemanggil.
Suamere
Ah tetapi jumlah baris yang dipengaruhi oleh Perintah membuat membangun perintah baru dari yang lama lebih mudah. Sumber: pengalaman bertahun-tahun.
Joshua
@ Yosua: Demikian juga, "tambahkan catatan baru dan kembalikan ID (untuk beberapa struktur, nomor baris) yang dihasilkan selama add" dapat digunakan untuk tujuan yang tidak dapat dicapai secara efisien.
supercat
Anda tidak perlu mengembalikan baris yang terpengaruh. Perintah harus tahu berapa banyak yang akan terpengaruh. Jika itu adalah sesuatu selain # itu, itu harus memutar kembali dan melemparkan pengecualian karena sesuatu yang aneh baru saja terjadi. Dengan demikian, itu adalah informasi penelepon tidak benar-benar peduli tentang hal itu (kecuali jika pengguna perlu mengetahui # yang sebenarnya dan Anda tidak dapat mengetahui dari data yang diberikan). Masih ada area abu-abu seperti DB yang dihasilkan Id, tumpukan / antrian di mana mendapatkan data mengubah keadaannya, tapi saya suka membuat "CommandQuery" dalam skenario tersebut sehingga tidak ada yang mencoba melakukan sesuatu yang "aneh".
Daniel Lorenz
3

Apa pun jalan yang akan Anda jalani dengan ini. Tidak memiliki nilai balik di sana untuk penggunaan di masa mendatang (mis. Memiliki fungsi selalu kembali benar) ini adalah usaha yang sangat buruk dan tidak membuat kode lebih jelas untuk dibaca. Ketika Anda memiliki nilai kembali Anda harus selalu menggunakannya, dan untuk dapat menggunakannya Anda harus memiliki setidaknya 2 nilai pengembalian yang mungkin.

refro
sumber
+1 Ini tidak menjawab pertanyaan, tetapi ini jelas informasi yang benar. Ketika membuat keputusan, keputusan harus didasarkan pada suatu kebutuhan. Jika penelepon tidak menemukan data pengembalian berguna, itu tidak boleh dilakukan. Dan tidak ada yang menemukan digunakan dalam mengembalikan 100% benar dari waktu untuk "pemeriksaan di masa depan". Memang, jika "masa depan" seperti ... beberapa hari dari sekarang dan ada tugas yang ada untuk itu, itu cerita yang berbeda, lol.
Suamere
1

Saya biasa menulis banyak fungsi yang tidak valid. Tetapi karena saya mendapatkan seluruh metode chaining crack, saya mulai mengembalikan ini daripada batal - mungkin juga membiarkan seseorang mengambil keuntungan dari pengembalian karena Anda tidak dapat melakukan squat dengan batal. Dan jika mereka tidak ingin melakukan apa pun dengan itu, mereka bisa mengabaikannya.

Wyatt Barnett
sumber
1
Metode chaining dapat membuat pewarisan menjadi rumit dan sulit. Saya tidak akan melakukan metode chaining kecuali Anda memiliki alasan yang baik untuk melakukannya selain tidak ingin memberikan metode Anda "batal".
KallDrexx
Benar. Tetapi pewarisan bisa jadi rumit dan sulit digunakan.
Wyatt Barnett
Melihat kode yang tidak diketahui yang mengembalikan apa pun (menyebutkan seluruh objek) membayar banyak perhatian hanya memeriksa aliran di dalam dan di luar metode ..
Independen
Saya kira Anda tidak sampai Rubypada suatu titik? Itulah yang memperkenalkan saya pada metode chaining.
KChaloux
Satu keraguan yang saya miliki dengan metode chaining adalah bahwa hal itu membuat kurang jelas apakah pernyataan suka return Thing.Change1().Change2();mengharapkan untuk mengubah Thingdan mengembalikan referensi ke aslinya, atau diharapkan untuk mengembalikan referensi ke hal baru yang berbeda dari aslinya, sambil meninggalkan asli tidak tersentuh.
supercat