3 ms·
If your error domain has only one useful category why not just create an error type with a useful message and be done with it. Why use anyhow at all? You are es
by zaphar 10mo ago
If your error domain has only one useful category why not just create an error type with a useful message and be done with it. Why use anyhow at all? You are essentially saying the error domain is small so the work is tiny anyway.
anyhow seems useful in the very top layers where you basically just want bubble the useful errors modeled elsewhere to a top layer that can appropriately handle them. I don't think a crate should abdicate from modeling the error domain any more than they should abdicate from modeling the other types.
- athrowaway3z 10mo agoI'm trying to describe a rather large spectrum of situations, and how most of them are favorable (or not unfavorable) to anyhow. I'm not saying the error domain is small per se. Instead, one argument I'm making: what you're describing about errors bubbling up to the top layer, is what happens with the overwhelming majority of errors in my experience. Whether the error space is large or small, just wait until you have an immediate need to treat one error different from the rest. It happens, it's just not common. I didn't steelman the case for when to use enums, but in short: In a tiny error space or as valuable documentation. (The doc value is undermined somewhat when projects use 1-big-error and functions that eg only returns 3 of the 6 possible errors) I'm not advocating removing an Error enum. Just that writing one can and should be postponed, saving a lot of maintenance edits.
- zaphar 10mo agowhat you're describing about errors bubbling up to the top layer, is what happens with the overwhelming majority of errors in my experience. I agree that this is what happens in practice for most code that I read and have to interact with. I think where I differ from you is that I don't think this is good and do not advise people to do this for their own code. I think it's a pervasive but bad practice in our line of work.
- fauigerzigerk 10mo ago>I don't think a crate should abdicate from modeling the error domain any more than they should abdicate from modeling the other types. Yes, it's just harder. We usually have a pretty good idea what callers want from the happy path, but the range of things that callers may or may not want to do in case of an error is very broad.
- zaphar 10mo agoThis is an interesting perspective. I usually don't try to imagine how someone should handle the error. Instead I try to indicate the different types of errors that could occur and what type of information needs to be included to be useful to the caller. I can leave the question of what to do with that information to the caller since it's highly situational and the context necessary to make that decision lives outside of the code where I am modeling the error.
- burntsushi 10mo agoThat can be tricky because there may be a trade-off between error message quality and something else. Like, perhaps, the size of an error, code size or even runtime performance. Another trade-off with too-detailed errors---especially when those details are part of the library API---is that they become an extensibility hazard. Unless you're extremely certain about the line that divides a specific implementation from the logical domain of errors for a particular operation, you might get that wrong. And changing the implementation in the future might want a change in the error details. This is very hand-wavy, but I think we're talking at a very high level of abstraction here. My main point is to suggest that there is more of a balancing act here than perhaps your words suggest.
- zaphar 10mo agoI agree that it's a balancing act. I just don't think you get to abdicate from doing that balancing act and getting the balance wrong has consequences just like getting the balancing act wrong in your non error data model.
- fauigerzigerk 10mo ago>I usually don't try to imagine how someone should handle the error. But that's exactly what you do when you... >... try to indicate the different types of errors that could occur and what type of information needs to be included to be useful to the caller. Modelling the error domain means to decide which possible distinctions matter and which don't. This is not self evident. It's you imagining what users may want to do with your errors. Is it enough for the caller to know that some string you're parsing is invalid or do they need to know what it is exactly that makes it invalid? If you decide to just pass on everything you happen to know based on your current implementation then you are putting restrictions on future changes to that implementation, potentially including the use of third party libraries. What if you find a shortcut or a library that makes your parser 10 times faster but doesn't provide this detailed information? What I see a lot in Rust is that massive amounts of implementation details are leaked via errors. thiserror actually encourages this sort of implementation leak: #[derive(Error, Debug)] pub enum MyError { Io(#[from] io::Error), Glob(#[from] globset::Error), } https://docs.rs/thiserror/latest/thiserror/ https://docs.rs/thiserror/latest/thiserror/