Có nhiều triết lý trong các ngành kỹ thuật phần mềm khác nhau về cách các thư viện nên đối phó với các lỗi hoặc các điều kiện đặc biệt khác. Một vài trong số những cái tôi đã thấy:
- Trả về mã lỗi với kết quả được trả về bởi một đối số con trỏ. Đây là những gì PETSc làm.
- Trả về lỗi bằng một giá trị sentinel. Ví dụ, malloc trả về NULL nếu không thể cấp phát bộ nhớ,
sqrt
sẽ trả về NaN nếu bạn chuyển số âm, v.v ... Cách tiếp cận này được sử dụng trong nhiều hàm libc. - Ném ngoại lệ. Được sử dụng trong deal.II, Trilinos, v.v.
- Trả về một loại biến thể; ví dụ, hàm C ++ trả về một đối tượng kiểu
Result
nếu nó chạy chính xác và sử dụng một kiểuError
để mô tả cách nó thất bại sẽ trả vềstd::variant<Error, Result>
. - Sử dụng khẳng định và sụp đổ. Được sử dụng trong p4est và một số phần của igraph.
Vấn đề với từng phương pháp:
- Kiểm tra cho mọi lỗi giới thiệu rất nhiều mã bổ sung. Các giá trị mà kết quả sẽ được lưu trữ luôn phải được khai báo trước, đưa ra nhiều biến tạm thời chỉ có thể được sử dụng một lần. Cách tiếp cận này giải thích những gì đã xảy ra lỗi nhưng có thể khó xác định lý do tại sao hoặc, đối với ngăn xếp cuộc gọi sâu, ở đâu.
- Các trường hợp lỗi là dễ dàng để bỏ qua. Trên hết, nhiều hàm thậm chí không thể có giá trị sentinel có ý nghĩa nếu toàn bộ phạm vi của các loại đầu ra là kết quả chính đáng. Nhiều vấn đề tương tự như # 1.
- Chỉ có thể có trong C ++, Python, v.v., không có trong C hoặc Fortran. Có thể được bắt chước trong C bằng cách sử dụng phép thuật setjmp / longjmp hoặc libunwind .
- Chỉ có thể có trong C ++, Rust, OCaml, v.v., không có trong C hoặc Fortran. Có thể được bắt chước trong C bằng cách sử dụng phép thuật vĩ mô.
- Có thể cho rằng nhiều thông tin nhất. Nhưng nếu bạn áp dụng cách tiếp cận này, giả sử, một thư viện C mà sau đó bạn viết một trình bao bọc Python cho, một lỗi ngớ ngẩn như chuyển một chỉ mục ngoài giới hạn cho một mảng sẽ làm hỏng trình thông dịch Python.
Phần lớn lời khuyên trên internet về xử lý lỗi được viết từ quan điểm của hệ điều hành, phát triển nhúng hoặc ứng dụng web. Sự cố là không thể chấp nhận và bạn phải lo lắng về bảo mật. Các ứng dụng khoa học không có những vấn đề này ở mức độ gần như nhau, nếu có.
Một xem xét khác là những loại lỗi có thể phục hồi hay không. Một thất bại malloc là không thể phục hồi và, trong mọi trường hợp, kẻ giết người hết bộ nhớ hệ điều hành sẽ nhận được nó trước khi bạn làm. Một chỉ mục nằm ngoài giới hạn cho kích thước mảng cũng không thể phục hồi được. Đối với tôi là người dùng, điều tốt nhất mà thư viện có thể làm là gặp sự cố với thông báo lỗi thông tin. Mặt khác, sự thất bại của bộ giải tuyến tính lặp để hội tụ có thể được phục hồi bằng cách sử dụng bộ giải nhân tố trực tiếp.
Làm thế nào các thư viện khoa học báo cáo lỗi và mong đợi chúng sẽ được xử lý? Tất nhiên tôi nhận ra rằng nó phụ thuộc vào ngôn ngữ mà thư viện được triển khai. Nhưng theo như tôi có thể nói, đối với bất kỳ thư viện đủ hữu ích nào, mọi người sẽ muốn gọi nó từ một ngôn ngữ khác ngoài ngôn ngữ mà nó được triển khai.
Bên cạnh đó, tôi nghĩ rằng cách tiếp cận số 5 có thể được cải thiện đáng kể cho thư viện C nếu nó xác định con trỏ hàm xử lý xác nhận toàn cầu là một phần của API công khai. Trình xử lý xác nhận sẽ mặc định báo cáo số tập tin / số dòng và sự cố. Các ràng buộc C ++ cho thư viện này sẽ xác định một trình xử lý xác nhận mới thay vào đó ném một ngoại lệ C ++. Tương tự, các ràng buộc Python sẽ xác định một trình xử lý xác nhận sử dụng API CPython để ném ngoại lệ Python. Nhưng tôi không biết bất kỳ ví dụ nào áp dụng phương pháp này.