10 ms·
The rule of thumb for me is `thiserror` for libraries, `anyhow` for executables. Seems to work well enough in the vast majority of cases. I do agree that the Ru
by jgilias 6y ago
The rule of thumb for me is `thiserror` for libraries, `anyhow` for executables. Seems to work well enough in the vast majority of cases. I do agree that the Rust way can be frustrating at first. But then, at some point it becomes clear that being forced to keep your error conditions in mind at all times is actually a healthy thing. Then going back to languages where code may fail anywhere seems less than optimal. Sort of like the difference between securing your ropes and just crossing fingers.
As a side note, I've found that getting used to `Result` actually gives an added benefit of getting comfortable with the idea of such computational contexts in general. Be it Options, Maybes, Futures, Promises, Haskell IO, or anything of that kind.
- da-x 6y agoWhy not `thiserror` for executables as well? It happened to me a few times that I started to write an executable program, but then realized I want to embed its functionality in a library. Converting from `anyhow` to `thiserror` at that stage would be extra work that can be avoided.
- jgilias 6y agoI guess this depends somewhat on the situation. If the design is pretty clear upfront with a part that can be implemented as a core library, I'd make the library use `thiserror` from the beginning. However, if it's not really clear and I have to start with exploratory coding, then keeping track of error types that may come and go feels like unnecessary overhead, when I can just use `anyhow`. But! To each their own!
- status_quo69 6y agoI've used `thiserror` with great success in small side web projects since you can create a new enum of Errors that can be converted from a class of underling library errors. Then, inside of my regular application code, I sprinkle in `anyhow` to make my life easier. For example, if I wanted to say, return a 500 status code for all diesel database errors, I can convert the diesel error into my custom error type, then throw it back up the stack using `anyhow`. This works _really_ well in conjunction with Rocket's Responder impl. EDIT: This is pretty close to what TFA is saying as well, I should have read more in the article, heh
- masklinn 6y ago> Why not `thiserror` for executables as well? You can absolutely do that if you want, it's just that usually when writing an executable you don't care about creating the precise error types thiserror provides (especially doing so executable-wide), you'd handle the errors you get from reqwest or sqlx or whatever when you get them, and those you don't handle you just want to bubble up to an executable-wide handler.
- marcosdumay 6y agoUsually, you don't have any good thing to do with the error, so keeping it around just makes your code worse.
- TheCoelacanth 6y agothiserror is quite a bit more work to use. There's nothing wrong with using it for applications, but it's often overkill for that use case
- zvrba 6y ago> The rule of thumb for me is `thiserror` for libraries, `anyhow` for executables. And as the executable gets larger and refactored, some of the "executable" code will inevitably become "library" code. What then?
- lpghatguy 6y agoThere's nothing stopping you from continuing to use anyhow in a library, it just doesn't produce error types with much structure. You can continue returning `anyhow::Error`, wrap it into a newtype error for your library, or refactor to use thiserror. Thanks to the `?` operator and Rust's type aliases, you can get away with very few code changes to switch between these!
- masklinn 6y ago> And as the executable gets larger and refactored, some of the "executable" code will inevitably become "library" code. What then? Then that is migrated to `thiserror` (or something bespoke) at the same time as it's migrated to the library context. The library / executable is the delineation between providing a Rust-level API for third parties versus consuming such APIs. If you're providing a Rust API, you want to provide precise error so that the user is able to precisely target and handle errors if they need to. If you're only consuming Rust APIs, then you want to precisely handle some of the errors you get, and just chuck the rest over the side.
- Floegipoky 6y agoI'm imagining a sort of "wax on, wax off" moment but with monads.