5 ms·
remind me why they don’t work? because “throws Exception” propagates virally to every method in the codebase?
by dustingetz 2y ago
remind me why they don’t work? because “throws Exception” propagates virally to every method in the codebase?
- rad_gruchalski 2y agoWell, if you don’t handle them then… yes? What else can be done?
- karatinversion 2y agoThere's also the fact that common methods threw exception types that were not final, and in fact overly generic. If I call a method that declares itself to throw NoSuchFileException or DirectoryNotEmptyException, I can have a pretty good idea what I might do about it. If it throws IOException without elaboration, on the other hand...
- jkrejcha 2y agoWith regards to I/O, there are generally any number of weird errors you can run into, file not found, directory exists, host unreachable, permission denied, file corrupt, etc etc. Like anything file related will be able to throw any of those exceptions at almost any point in time. 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).
- bluGill 2y agoThere are fatal IO errors and non-fatal. Most of us don't care about the non-fatal case, but mainframes have the concept of "file isn't available now, load tape 12345", "file is being restored from backup, try again tomorrow" - things that your code could handle (if nothing else you should inform the user that this will take a while). There is also the "read off the end of the file" exception which in some languages is the idiomatic way to tell when you have read the whole file. 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.
- lmm 2y agoBecause you can't capture the evaluation of a function as a value, or write the type of it. E.g. try to write a generic function that takes a list and a callback, and applies the callback to every element of the list. Now what happens if your callback throws a checked exception? It doesn't work and there's no way to make it work, you just have to write another overload of your function and copy/paste your code. Now what happens if your callback throws two checked exceptions? It doesn't work and there's no way to make it work, you just have to write another overload of your function and copy/paste your code. And you'll never guess what happens if your callback throws three checked exceptions!
- dustingetz 2y agowhat is "it doesn't work" ? The exception is part of the type, so it doesn't typecheck unless all callbacks are of type "... throws Exception"? What's the problem with that? It's not generic enough, i.e. the problem is Java generics are too weak to write something like "throws <T extends Exception>"? (Forgive me, it's been 13 years since I wrote java and only briefly, the questions are earnest) edit, so like `@throws[T <: Exception] def effect[T](): Unit` or something, how is it supposed to work?
- lmm 2y agoYou can't be polymorphic between not throwing and throwing, or between throwing different numbers of exceptions. You have to write something like: <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.
- catlifeonmars 2y agoAh because there is no way to express E1 | E2 as a type parameter?
- 2y ago
- bluGill 2y agoBecause eventually someone will want to add another exception to a new leaf class and the proper place to handle it is 20 functions down the call tree and every single one of those 20 functions needs to now add that new exception to their signature even though only the handler function cares and you adjusted it. 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.
- zaphar 2y agoThe counter point here is that at least with Checked Exceptions you know only those 20 functions are part of the code path that can throw that exception. In the runtime exception case you are unaware about that 21'st function elsewhere that now throws it and it's not in the correct handling path anymore. 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.
- bluGill 2y agoLike I said, the implementation is wrong. Adding an exception to that 21st function, and then that whole call chain as well ends up being a lot of work. Sure you eventually find the place to handle it, but it was a lot of effort in the mean time. 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)