| The general issue, as I see it: One function is too general and handles all inputs. Some inputs are wrong and code returns error. Some languages forces you to handle that error. Another code snippet uses that function with very specific inputs which must not cause errors, but was forced to handle error, because of language rules. This error handling is essentially useless. I saw this issue with Java. There's constructor `new URI(String) throws URISyntaxException`. URISyntaxException is checked exception which must be handled at invocation site or propagated to the caller. But you might need to write code like `var uri = new URI("https://example.com/")` and any error handling code will only be to please the compiler, essentially wasted work. Java solved it using `public static URI create(String str)` which does not throw checked exceptions and you're supposed to choose either constructor or factory method, depending in the circumstances. Using Rust analogy, may be it would be useful for Java to write something like `var uri = unchecked new URI("https://example.com/");`, so with minimal syntax overhead you would signal that checked exceptions are not supposed to occur here (and if they did occur, then some unchecked UnexpectedCheckedException would throw here). It's actually possible to implement method `static T unchecked(CheckedSupplier<T, E> supplier)`, though syntax would be ugly: `var uri = unchecked(() -> new URI("https://example.com/"))`. I think that this is general issue for programming languages. There's only one way to validate input parameters and report error. But whether those input parameters are trusted or not - only the caller knows. So nothing wrong about using `unwrap()` to signify the fact, that caller already made sure that error does not happen. The only important nuance is that error must not be swallowed if it happened. |
The biggest robustness gains often come from making the right architectural decisions. That also applies to error handling as you described.