Ada banyak filosofi dalam berbagai disiplin ilmu rekayasa perangkat lunak tentang bagaimana perpustakaan harus mengatasi kesalahan atau kondisi luar biasa lainnya. Beberapa yang pernah saya lihat:
- Kembalikan kode kesalahan dengan hasil yang dikembalikan oleh argumen pointer. Inilah yang dilakukan PETSc.
- Kembalikan kesalahan dengan nilai sentinel. Misalnya, malloc mengembalikan NULL jika tidak dapat mengalokasikan memori,
sqrt
akan mengembalikan NaN jika Anda memasukkan angka negatif, dll. Pendekatan ini digunakan dalam banyak fungsi libc. - Melempar pengecualian. Digunakan dalam kesepakatan. II, Trilinos, dll.
- Kembalikan tipe varian; misalnya fungsi C ++ yang mengembalikan objek bertipe
Result
jika berjalan dengan benar dan menggunakan tipeError
untuk menggambarkan bagaimana ia gagal akan kembalistd::variant<Error, Result>
. - Gunakan assert dan crash. Digunakan di p4est dan beberapa bagian igraph.
Masalah dengan masing-masing pendekatan:
- Memeriksa setiap kesalahan memperkenalkan banyak kode tambahan. Nilai-nilai di mana hasil akan disimpan selalu harus dideklarasikan terlebih dahulu, memperkenalkan banyak variabel sementara yang mungkin hanya digunakan sekali. Pendekatan ini menjelaskan kesalahan apa yang terjadi tetapi sulit untuk menentukan mengapa atau, untuk tumpukan panggilan yang dalam, di mana.
- Kasing kesalahan mudah diabaikan. Selain itu, banyak fungsi bahkan tidak dapat memiliki nilai sentinel yang bermakna jika seluruh jajaran tipe output adalah hasil yang masuk akal. Banyak masalah yang sama dengan # 1.
- Hanya mungkin dalam C ++, Python, dll., Tidak dalam C atau Fortran. Dapat ditiru dalam C menggunakan setjmp / longjmp sihir atau libunwind .
- Hanya mungkin dalam C ++, Rust, OCaml, dll., Tidak dalam C atau Fortran. Dapat ditiru di C menggunakan sihir makro.
- Boleh dibilang yang paling informatif. Tetapi jika Anda mengadopsi pendekatan ini untuk, katakanlah, pustaka C yang kemudian Anda tulis pembungkus Python, kesalahan konyol seperti melewatkan indeks out-of-bounds ke array akan membuat crash interpreter Python.
Banyak saran di internet tentang penanganan kesalahan ditulis dari sudut pandang sistem operasi, pengembangan yang disematkan, atau aplikasi web. Gangguan tidak dapat diterima dan Anda harus khawatir tentang keamanan. Aplikasi ilmiah tidak memiliki masalah ini pada tingkat yang hampir sama, jika sama sekali.
Pertimbangan lain adalah jenis kesalahan apa yang dapat dipulihkan atau tidak. Gagal malloc tidak dapat dipulihkan dan, bagaimanapun, OS out-of-memory killer akan melakukannya sebelum Anda melakukannya. Indeks di luar batas untuk ukuran array juga tidak dapat dipulihkan. Bagi saya sebagai pengguna, hal terbaik yang dapat dilakukan perpustakaan adalah dengan crash dengan pesan kesalahan informatif. Di sisi lain, kegagalan, katakanlah, solver linear iteratif untuk konvergen dapat dipulihkan dari dengan menggunakan solver faktorisasi langsung.
Bagaimana seharusnya perpustakaan ilmiah melaporkan kesalahan dan mengharapkannya ditangani? Tentu saja saya menyadari bahwa itu tergantung pada bahasa apa perpustakaan diimplementasikan. Tapi sejauh yang saya tahu, untuk perpustakaan yang cukup bermanfaat, orang akan ingin menyebutnya dari beberapa bahasa selain yang diimplementasikan di dalamnya.
Sebagai tambahan, saya pikir pendekatan # 5 dapat ditingkatkan secara substansial untuk pustaka C jika ia mendefinisikan penunjuk fungsi penangan pernyataan global sebagai bagian dari API publik. Penangan pernyataan akan secara default melaporkan nomor file / baris dan macet. Binding C ++ untuk pustaka ini akan mendefinisikan penangan pernyataan baru yang sebagai gantinya melemparkan pengecualian C ++. Demikian juga, binding Python akan mendefinisikan penangan pernyataan yang menggunakan API CPython untuk melempar pengecualian Python. Tapi saya tidak tahu ada contoh yang mengambil pendekatan ini.