I haven't done java in decades, but I imagine this would get really nasty if you are passing a callback to a third party library and now your callback throws the new exception.
Checked exceptions seem like a great idea, but what java did is wrong. I'm not sure if other implementations are better.
You have no way to assert that the error is always correctly handled in the codebase. You are basically crossing your fingers and hoping that over the life of the codebase you don't break the invariant.
What was missing was a good way to convert checked exceptions from code you don't own into your own error domain. So instead java devs just avoided them because it was more work to do the proper error domain modeling.
It gets worse. Sometimes we can prove that the 21st function because of the way it is calling your function can never trigger that exception, but still it will need code to handle it. If that handler code if the 21st function changes to trigger the exception now should be propagated back down but since you handled the exception before checked exceptions won't tell you that you handled it in the wrong place.
I don't know how to implement checked exceptions right. On paper they have a lot of great arguments for them. However in practice they don't work well in large projects (at least for java)
You could imagine something similar with Exceptions where there is simple and ergonomic way to rethrow the exception into your own error domain with little to no extra work on the part of the developer.
edit, so like `@throws[T <: Exception] def effect[T](): Unit` or something, how is it supposed to work?
<R> List<R> map(Function<? super T,? extends R> mapper) { ... }
<R, E1 extends Throwable> List<R> map(FunctionThrows1<? super T,? extends R, E1> mapper) throws E1 { ... }
<R, E1 extends Throwable, E2 extends Throwable> List<R> map(FunctionThrows2<? super T,? extends R, E1, E2> mapper) throws E1, E2 { ... }
and so on until you get bored.(Except that then you have to decide what your generic function is going to do if the callback throws an exception...)
> (Except that then you have to decide what your generic function is going to do if the callback throws an exception...)
Exactly. Presumably you don't want to handle them and want to throw them up to the caller. But now your function has to be "throws Throwable" rather than throwing the specific exception types that the callback throws.
Of course in general the manual effort to do that in a large code base ends up too hard and so in the real world nobody does that. Still the ideal is good, just the implementation is flawed.
I think IOException (or maybe FileSystemException) is probably the best you can do in a lot of I/O cases unless you can dedicate time to handling each of those specially (and there's often not a lot much more you can do except for saying "Access is denied" or "File not found" to the user or by logging it somewhere).
But most IO errors are fatal. It doesn't matter if the filename is not found, or the controller had too many errors talking to the drive and gave up - either way your code can do nothing.