| While I agree exceptions should not be used for control flow except in the rarest of circumstances (every rule has exceptions — pun fully intended), I think checked exceptions are very useful. I wrote a whole article about this, way back when: https://norswap.com/checked-exceptions/ But for the tl;dr: checked exceptions represent somewhat expected issues, things like IO errors. There are two okay ways to handle those: checked exceptions and result types, and one bad way: unchecked exceptions. Unchecked exceptions end up being undocumented in the API, and people forget to handle them. Result types add a lot of ceremony, as you have to unwrap them at every level of the call stack. I've seen code dominated by error checking logic many times in C and Go (and the frequent alternative is to ignore error, which is easy in C). Checked exceptions are much less verbose, you just let the exception pass through and annotate the function signature with the checked exception. It's type-safe, self-documenting and easy. Unchecked exceptions "leak", checked exceptions propagate at the type-level, which is exactly what you want — making sure every caller is aware of what exceptions might occur and letting them make an explicit decision to handle or pass the buck upwards. By the way, checked exceptions are coming back in favour with "effects" which are basically a generalization of checked exceptions beyond the realm of errors, trying to encode things into the type system. |
I'll take a different tack - look at the empirical evidence. If checked exceptions were a good/useful/helpful language feature, then the feature would have been adopted by other languages, especially new ones. But this simply hasn't happened. Java is unique in having checked exceptions.
Wouldn't you think that there would have been proposals to introduce checked exceptions for C++, Python, JavaScript, C#, and Rust, Kotlin, etc. if they were a useful software engineering tool?