3 ms·
Error handling is not supposed to be fun. It is hard. It doesn't stop being hard because you decided to hide it in the type signature. Point by point: > I w
by Jweb_Guru 11y ago
Error handling is not supposed to be fun. It is hard. It doesn't stop being hard because you decided to hide it in the type signature. Point by point:
> I wrote an RSS reader in Rust, and all the code required to compose all the error types (I/O, HTTP, XML, RSS, date formats) into a custom error type is as bulky as the modest amount of code that does the useful work....
If the errors are internal implementation details that you don't want to expose (or you just don't feel like writing wrappers), and you don't want to handle them either, you can return `Result<T, Box<Error>`, as noted in the article. This requires all of no work on your part as long as other libraries are also returning instances of `Error` (and in general, they are), while also ensuring that your library returns an instance of `Error`.
If your library defines its own meaningful errors, and you want to expose those to the user, then you will need to create a type and define `Error` for them, but you would also have to do the equivalent in any typed language with exceptions. If you additionally want them to be "top level" errors, but want to wrap other types of errors as the ultimate cause, you'll also need a single `From<Error>` implementation (from generic errors to your type) which in my experience is not even more code than a single catch-and-rethrow-as-another-type in a language with exceptions.
(I bring this up mostly for the benefit of others, as it has been explained to you before. Perhaps when you wrote your library `Error` hadn't been stabilized yet, but all of what I said above has been possible in Rust for many months now).
> Having to write all that error handling code up front is going to be a big problem for the Agile crowd. This may be a major drag on Rust adoption.
The "Agile" approach to error handling is `unwrap()`. It's not recommended in libraries because they violate the contracts the libraries expose, a problem they share with unchecked exceptions in other languages.
> All this error machinery is in Rust to avoid exceptions. That may have been a mistake.
Preferring sum types is not just true in Rust, where one might speculate that it's because it lacks `catch`: my impression is that in all three of Haskell, Scala, and OCaml, which support both, public opinion has moved steadily away from exceptions and towards `Either` for error handling. This is quite striking given that there are good reasons to believe that exceptions would be popular in those languages: in Haskell because pure code suffers from relatively fewer exception safety issues, in OCaml because the exception implementation is highly optimized, in Scala because the prevailing ecosystem (where most of the employees are drawn from) uses exceptions for error handling. The fact that all of these communities, given both options, tend to use sum types, suggests to me that the theoretical benefits of this approach (many of which you covered) are also practical for many people.
> Exceptions have the good property that they can't be ignored - if they're not handled, you get a reasonable program termination.
In a recent paper, the following three things were found to have led to 35% catastrophic production failures: https://www.usenix.org/system/files/conference/osdi14/osdi14-paper-yuan.pdf https://www.usenix.org/system/files/conference/osdi14/osdi14...:
> (i)the error handler ignores explicit errors; (ii) the error handler over-catches an exception and aborts the system; and(iii) the error handler contains “TODO” or “FIXME” in the comment.
It sounds like people do a fine job of ignoring exceptions. Moreover, it seems to me like what you are advocating (catching `RuntimeError` or something equally generic, where you can't possibly take an explicit corrective action, but not terminating the program) is precisely what ended up causing a lot of these bugs.
In any case, it's not likely that you'll out and out forget to handle a `Result` in Rust. You can't even try to access the inner value without handling errors, and if you just don't use it (because you don't care about the value) Rust generates a warning (people generally pay attention to Rust warnings, since there are relatively few of them). If you `unwrap()` it, it's even easier to find where you aren't handling your errors properly--you just grep for `unwrap()`.
In my experience, people ignore errors far less in Rust than in any other language I've worked with, because it actually makes them explicit when they happen, rather than propagating them down to a consumer who has no idea what to do with the error.
> If there's a reasonable exception hierarchy, you can catch an exception near the root of the tree and get all subsidiary exceptions.
I also am interested to hear why you believe that hierarchical error types make sense: errors seem to me to be one of the absolute worst fits for the classical inheritance model. They very rarely have any shared behavior or state that isn't also on `Error`, and trying to fit them into a hierarchy is an exercise in frustration that is undertaken for the sole purpose of avoiding multiple catch clauses--they very rarely compose and are even more rarely extensible. More often, people just give up and use a single type with a String, or--equally commonly--simply `catch Exception` whenever they expect an exceptional condition to be raised without bothering to check the type at all.
> you have to combine error types yourself.
And coming full circle... no, you don't :)
> I really want Rust to succeed, but I think they took a wrong turn with error handling.
You have repeated both this sentiment and the bulk of your comment in many, many posts now. I believe that you are sincere in your desire for exceptions (even if I disagree with it), but I don't think you or anyone else seriously believes that not making catchable exceptions the default error handling technique is going to make or break Rust adoption, especially when its primary target audience is known for routinely disabling exceptions to avoid dealing with exception safety and performance issues.