Mengapa Opsi / Mungkin dianggap ide yang bagus dan pengecualian yang diperiksa bukan?

23

Beberapa bahasa pemrograman seperti misalnya Scala memiliki konsep Optiontipe (juga disebut Maybe), yang dapat mengandung nilai atau tidak.

Dari apa yang saya baca tentang mereka, mereka dianggap secara luas sebagai cara terbaik untuk menangani masalah ini daripada null, karena mereka secara eksplisit memaksa programmer untuk mempertimbangkan kasus-kasus di mana mungkin tidak ada nilai daripada hanya meledak saat runtime.

Pengecualian yang diperiksa di Jawa di sisi lain tampaknya dianggap ide yang buruk, dan Jawa tampaknya menjadi satu-satunya bahasa yang digunakan secara luas yang mengimplementasikannya. Tetapi ide di balik mereka tampaknya agak mirip dengan Optiontipe, untuk secara eksplisit memaksa programmer untuk berurusan dengan fakta bahwa pengecualian mungkin dilemparkan.

Apakah ada beberapa masalah tambahan dengan Pengecualian yang diperiksa yang Optiontidak dimiliki tipe? Atau apakah ide-ide ini tidak sama dengan yang saya pikirkan, dan ada alasan bagus untuk memaksa penanganan eksplisit untuk Opsi dan bukan untuk Pengecualian?

Ilmuwan gila
sumber
Lihat juga Either e atipe data.
4
Tentang pengecualian yang diperiksa: sebagai pengguna banyak open source dan Java lib internal dengan basis kode yang berkembang dan dokumen yang hilang / ketinggalan jaman, saya ngeri membayangkan bahwa Java tidak akan memaksakan pengecualian tertentu untuk dinyatakan secara eksplisit. Ini akan menjadi mimpi buruk dari kesalahan runtime yang tidak tertangani yang muncul di tempat-tempat yang buruk, secara tak terduga. Dan Java7 akhirnya membuat pengecualian penanganan hampir waras, menyingkirkan banyak kekacauan try-catch lama.
hyde

Jawaban:

24

Karena Options adalah komposer. Ada banyak metode yang berguna pada Optionyang memungkinkan Anda untuk menulis kode ringkas, sementara masih memungkinkan kontrol yang tepat pada aliran: map, flatMap, toList, flattendan banyak lagi. Ini disebabkan oleh fakta bahwa itu Optionadalah sejenis monad tertentu, beberapa benda yang kita tahu betul bagaimana menyusunnya. Jika Anda tidak memiliki metode ini dan harus selalu mencocokkan pola Option, atau isDefinedsering menelepon , mereka tidak akan berguna.

Sebaliknya, sementara pengecualian yang diperiksa menambah keamanan, tidak banyak yang dapat Anda lakukan selain menangkapnya atau membiarkannya menggelembungkan tumpukan (dengan pelat tambahan dalam deklarasi tipe).

Andrea
sumber
1
Pengecualian diperiksa terdiri lebih atau kurang dengan cara yang sama ... Perbedaan antara try {/* bunch of complex code involving calls to 50 different methods that may throw SomeCheckedException */} catch(SomeCheckedException e) {/* operation failed, do something */}dan fromMaybe someDefaultValue (something >>= otherThing >>= ...50 other functions that may return Nothing...)apa sebenarnya? Selain fakta bahwa mantan memberi Anda rincian lebih lanjut tentang apa yang salah.
user253751
14

Sementara terkait, objek pengecualian dan Mungkin tidak berurusan dengan jenis masalah yang sama.

Pengecualian

Pengecualian benar-benar bersinar ketika Anda harus berurusan dengan non-lokal dengan situasi luar biasa (yang dalam beberapa kasus terjadi kesalahan). Misalnya Anda mengurai csv, dan ingin melindungi diri sendiri dari garis dengan pemformatan yang salah. Tempat di mana Anda menemukan ada sesuatu yang salah mungkin beberapa panggilan fungsi menjauh dari iterasi garis. Jika Anda melempar pengecualian pada level terdalam (di mana Anda mengetahui tentang masalah format), Anda bisa menangkapnya dalam loop, mencatat kesalahan, dan melanjutkan ke baris berikutnya. Anda tidak perlu mengubah apa pun di sisa kode.

Pengecualian yang diperiksa menambah banyak rasa sakit karena semua fungsi antara harus menyatakan tipe yang bisa dibuang. Fitur ini mengalahkan tujuan awal, itulah sebabnya mereka tidak populer saat ini.

Mungkin benda

Mungkin objek harus dipilih ketika Anda dapat menangani "kegagalan" secara lokal. Dalam hal itu, mereka adalah pengganti untuk kode pengembalian + lulus dengan referensi api atau jenis yang dapat dibatalkan.

Keuntungan dari objek Maybe adalah Anda secara eksplisit menyatakan bahwa ada sesuatu yang salah. Dalam haskell, objek non mungkin harus memiliki nilai, atau program tidak akan dikompilasi.

Masalah dengan tipe nullable adalah Anda harus memeriksa null setiap saat agar benar-benar aman. Status "sesuatu mungkin salah" adalah yang standar.

Masalah dengan kode pengembalian + lewat ref apis adalah bahwa mereka kurang dapat dibaca oleh kebanyakan orang.

Simon Bergot
sumber
1
@MattFenwick terima kasih atas umpan baliknya. Menurut Anda mengapa contoh csv tidak masuk akal? OP tidak benar-benar meminta teknik penghindaran boilerplate, dan saya merasa bahwa kosa kata seperti functor & monads yang berlaku mungkin terlalu teknis untuk pertanyaan ini.
Simon Bergot
1
Saya ingin menunjukkan, bahwa dengan Java (tidak yakin dengan bahasa lain dengan pengecualian yang dicek) IDE menangani penambahan dan pemangkasan lemparan dan memperbarui komentar javadoc bagian boilerplate. Jadi setidaknya bagian itu tidak mengganggu dan tentu saja tidak ada rasa sakit. Apakah itu menyakitkan atau anugerah atau sesuatu di antaranya ketika melakukan desain API, itu masalah lain ...
hyde
5
@ Hyde: Hanya karena sebuah IDE dapat mengotomatiskan pembuatan boilerplate yang tidak berarti, tidak berarti bahwa boilerplate yang tidak berguna bukanlah suatu masalah.
Michael Shaw
2
@ Hyde: Tapi sakitnya tidak hilang. The boilerplate sia-sia masih ada di sana, mengacaukan kode tanpa alasan. Jika ada alasan untuk pelat baja, apakah itu?
Michael Shaw
2
@MichaelShaw Jika pengecualian tidak ada gunanya, hapus saja: abaikan situasi atau kembalikan nilai kesalahan. Jika itu adalah bug atau situasi yang tidak dapat dipulihkan: gunakan pengecualian yang tidak dicentang. Apa yang tersisa sama pentingnya dengan misalnya jenis parameter, bukan boilerplate tidak berguna. Jika API buruk di lib yang ada, pertimbangkan metode / kelas wrapper, menggunakan lib lain, atau hanya menderita API buruk.
hyde
1

karena dengan MaybeAnda dapat menunda menangani kesalahan sampai Anda benar-benar membutuhkan nilai (yang mungkin beberapa metode panggilan)

sedangkan pengecualian yang diperiksa perlu ditangani di lokasi panggilan

satu-satunya terbalik dari pengecualian adalah bahwa lebih banyak informasi dapat disampaikan tentang mengapa itu gagal (kecuali seseorang mengembangkan bidang MaybeErrordengan throwable ketika itu kesalahan)

ratchet freak
sumber
2
Tapi saya bisa menunda penanganan pengecualian diperiksa dengan menyatakan bahwa metode saya melempar pengecualian ini.
Mad Scientist
1
@MadScientist yang hanya naik tumpukan panggilan, sementara Mungkin bisa pergi ke segala arah
ratchet freak
5
Saya pikir Anda tidak harus membingungkan Maybejenis dengan penanganan kesalahan. Pengecualian digunakan untuk melaporkan kesalahan, jenis opsi digunakan untuk mewakili hasil dari fungsi parsial. Fungsi sebagian yang dikembalikan Nothingbukanlah kesalahan.
Giorgio
@ MadScientist: Jika panggilan metode mengembalikan indikasi "Nilai tidak valid", pernyataan itu segera setelah itu dapat dieksekusi. Sebaliknya, jika metode melempar pengecualian yang tidak segera ditangkap, pernyataan setelah panggilan akan dilewati. Membiarkan pengecualian yang diperiksa meresap ke tumpukan panggilan pada umumnya jahat (dan seharusnya tidak menjadi cara 'termudah' untuk menanganinya) karena tidak ada cara bagi penelepon untuk mengetahui apakah kondisi memiliki makna yang diharapkan oleh metode yang dipanggilnya, atau apakah itu mewakili suatu kondisi yang tidak terduga dimana metode yang disebut membiarkan gelembung naik.
supercat