The origin
原文 The Error Model and 知乎翻译
summary
Error Codes
Many functional languages use return codes disguised in monads and names things like Option
Dispite theis simplicity, return codes do some with some baggage; in summary:
- performance can suffer (branch that compiler can’t optimize)
- Programming model usabiliry can be poor
- The biggie: you can accidentally forget to check for errors (Rust guaratee by compiler)
上面文章也提到 Rust 在除了性能之外的方面已经做的很好 (pattern matching and try! macro)
But we need fail-fast → exception
Exception
cpp deprecate exception specifications, so noexcept
is also bad. cpp exception
recap
the good | the bad | the ugly | |
---|---|---|---|
Error Code | 1. All function that can fail are explicit annotated 2. All error handling at callsites is explicit | 1. you can forget to check them 2. Performance of success paths suffers | usability is often subpar |
All Excpetions | first class language support | 1. Performance is typically worse than it could be 2. handling is often done in a non-local manner, where less information about an error is known(goto-like) | |
Unchecked Exceptions | conducive to rapid development where dealing with errors reliably isn’t critical | Anything can fail without warning from the language | reliability is as bad as it gets |
Checked Exceptions | all function that can fail are explicitly annotated | 1. callsites aren’t explicit about can fail and error propagation 2. systems that let some subset of exceptions go unchecked poison the well(not all errors are explicit) | people hate them(in java, at least) |
Wouldn’t it be great if we could take all of the Goods and leave out the Bads and The Uglies?
Bugs aren’t recoverable errors
- A recoverable error is usually the result of programmatic data validation.
- A bug is a kind of error the programmer didn’t expect.
The wrong point: Exceptions and return codes are equally expressive, they should however not be used to describe errors. For example, the return codes contained definitions like ARRAY_INDEX_OUT_OF_RANGE. It cannot be handled or fixed at runtime, it can only be fixed by its developer. Thus there should be no according return code, but instead there should be assert.
Reliabiliry, Fault-Tolerance, and Isolation
To build a reliable system
As with most distributed systems, our architecture assumed process failure was inevitable. We went to great length to defend aginst cascading failures, journal regularly, and to enable restartability of programs and services.
Abandonment
Perhaps the most important technique is regularly journaling and checkpointing precious persistent state. Jim Gray’s 1985 paper, Why Do Computers Stop and What Can Be Done About It?, describes this concept nicely.
Recoverable errors: type-directed exceptions
For example, file I/O, network I/O, parsing data, validating user data.
The exception has good performance on the good path, it’s zero-cost.
Restrospective and conslusion
The final model in the article featured:
- An architecture that assumed fine-grained isolation and recoverability from failure.
- Distinguishing between bugs and recoverable errors.
- Assertions, abandonment for all bugs
So next, we should look at the C++ system. And if we do not use exception, how to introduce the Rust smell code into C++.
Boost.outcome , std::expected, and boost.leaf
Boost.outcome.result
is more like std::variant
, and std::expected(C++23)
is more like std::optional
extension. The detail in reference [how std::expected interacts with boost.outcome].Dissimilarities section.
Rust error handling
rust book show rust how to modle the error and handle it. Recommend the guidelines for error handling
- Unrecoverable error with panic!
panic!
can record the backtrace
- Recoverable errors with Result
- pattern matching
- Propagating error with
?
Result (Either) in C++
I personally like the Rust abstract, instead of error code, it propose the Reulst<T, E>
, and outcome.result can be used in c++.
Leaf comfortable scenoria
If you need an error handling framework which has predictable sad path overhead unlike C++ exceptions, but you otherwise want similar syntax and use experience to C++ exceptions, LEAF is a very solid choice. Do not use in my ray-like project, i do not like the exception when should support API for application user.