> the program cannot connect to its database;
> the program cannot write output to disk because the disk is full;
> the program was not started with valid configuration.
I'd prefer Result over exceptions even in these cases. The only case where I think exceptions should be used is when the type system of the language is not powerful enough to prove the validity of some operation. For example in Rust:
let v = vec![1, 2, 3];
let n = v.pop().unwrap();
The `pop` method returns `Option`, but I as a programmer know for sure that the collection isn't empty, I just can't prove it to the compiler. So I use `unwrap` to get the value and panic in the case I'm actually wrong and made a stupid mistake.Another example is division by zero. Using a `Result` as a return value of the division operator would be extremely inefficient and unergonomic. Panic/exception is the best way to handle this situation.
I believe dependent types can solve both of the problems above so we can get rid of exceptions completely. Unfortunately, there is no a single mainstream language that has them.