3 ms·
> almost all of the time, not 99% of the time, or 99.9% of the time, but almost every single time--you call a function, you shouldn't care what errors it can ra
by Expurple 1y ago
> almost all of the time, not 99% of the time, or 99.9% of the time, but almost every single time--you call a function, you shouldn't care what errors it can raise
Sure, that's often the case. That's why dynamically-typed anyhow::Error is so popular.
But I really care whether a function can raise at all. This affects the control flow in my program and composability of things like `.map()`. `Result` is so good because it makes "raising" functions just as composable as "normal" functions. When you `.map()`, you need to make a decision whether you want it to stop on the first error or keep going and return you Results with all individual errors. Rust makes it very easy and explicit, and allows to reuse the same `.map()` abstraction for both cases.
> a language that forces people to deal with local error handling.
It does that for the reason above: explicit control flow. See the "Can you guess why I used an intermediate variable" toggle in the article.
It doesn't mean that you have to do full "local error handling" on every level. 99% of the time, `?` operator is used. Because, as you've said, 99% of the time you just want to propagate an error. That's understood in the Rust community and the language supports it well.
When you need to wrap the error for some reason, `?` can even do that automatically for you. That's what makes anyhow::Error so seamless and sweet. It automatically wraps all concrete library errors and you no longer need to deal with their types.
Basically, `Result<T, anyhow::Error>` is `throws Expection`. But, like, ergonomic, composable and actually useful.