> Sometimes it's better to call throwing functions and get needed data before modifying the private data
Haha! Here we go back to the topic of unchecked exceptions and "the lesser evil". With unchecked exceptions, every function is throwing! Even if it shouldn't throw today according to the docs:
1. The docs could be simply wrong.
2. It isn't a semver breaking change to start throwing in a future version. The compiler won't warn you when this happens. You won't manually audit all your dependencies when updating them [1].
We come back to the need to properly reflect errors in the type system. Without returning them by value, the only popular alternative is checked exceptions. But, as I mentioned in the updated version of the post [2], checked exceptions in Java are unfriendly to generic code. This is important and will come up right now:
> Imagine you need to call f(h1()) and f(h2()) where h1() and h2() return the same data type for valid data but different types of errors. What do you do?
This depends on the context. A general answer: `f` can be generic over the error type.
fn f<E>(result: Result<_, E>)
If it needs to do something more specific with E, like logging it, it can also have a more specific bound on E:
use std::fmt::Display;
fn f<E: Display>(result: Result<_, E>)
If it has to be a concrete function, it can use runtime polymorphism instead:
use std::fmt::Display;
fn f(result: Result<_, Box<dyn Display>>)
// in this case, the caller has to explicitly box the error
f(h1().map_err(Box::new))
---
[1] Unless you operate on a really serious level where you should strive to use a more reliable language anyway.
[2] https://home.expurple.me/posts/rust-solves-the-issues-with-e...