[Closed, with a new one] Checked exception simulation in Rust( 2nd version )

Thanks for your response. I still think "exception handling" is itself not in the spirit of Rust at all. Error handling with Result is nice because there is nothing "exceptional" to it from the point of view of the language. It's just a type implementing a trait for an operator, and its usage has got solid conventions around it. Consequently, it doesn't need special handling, and that's exactly where its beauty comes from.

For example, no "generics" (for the lack of a better word) around "throws/rethrows" are necessary when accepting functions as arguments in higher-order functions. That is a massive pain point in languages with checked exceptions (Swift comes to mind), and it either discourages people from writing higher-order functions at all (which is a sad regression from modern, functional programming practice), or the less experienced, forgetting to add "rethrows" annotations, write higher-order functions that are impossible to use with arguments throwing exceptions.

I don't get what's wrong with a type alias for Result; personally, I find it perfectly convenient to write and just as easy to read.

The readme of CeX reads:

The error types are not accurate

Again, since ? calls From::from(), if you don't like an enum of all possible errors, this is almost trivially resolved by always returning the exactly accurate error type and implementing From (or just propagating the same type up the call chain). Even so, personally, I do like an enum of all possible errors. For one, it means that functions continue to be allowed to return any error, or, more precisely, to extend the set of errors they return, without a change in the signature. This saves users precious backward compatibility budget (and some complexity for the author of the code, although that's not nearly as important).

Furthermore, errors from the same unit of code (say, from the same crate) tend to be somehow related, after all, and consumers can think of them as a group. In fact, I've seen and written lots of code that goes like this:

  1. Call high-level API of crate Foo
  2. High-level function in Foo's API calls into lower-level functions, accumulates any errors through a single error type
  3. The caller switches on the result's error type once, to find out what kind of error, if any, happened.

Although read_u32() does not do calculating at all, we need to deal with the Error::Calc branch and write unreachable!() code.

No, we don't need to write an unreachable!(). In fact, I would consider that poor style. If there is an error that you don't want to handle yourself, you should propagate it rather than optimistically asserting that it can't happen. This also helps the "extend the set of errors to return after the fact" approach work nicely.


However, I still do appreciate the effort you put into the implementation of CeX. It does seem well-fleshed out based on your ideas. I think those who prefer exception-style error handling should definitely check it out. I just don't believe it should be the standard, idiomatic way of error handling in Rust.

7 Likes