Alright @claudiameadows, I've read through the list of articles you've provided and tried to extract out all of the arguments against checked exceptions. I'm going to point them out and see how they could have been addressed in Java (when it was first designed). This will let us know how we can avoid these same pitfalls when designing an exception system.
Arguments against checked exceptions and how to deal with them.
1. Checked exceptions integrate poorly with higher-order functions.
I've certainly run into this before. I've wanted to use Java's fancy stream API, which contains useful functions such as a map function for arrays. However, while mapping elements, I needed to be able to throw a certain exception. This unfortunately was not possible because the map function does not declare in its "throws" clause that I might be throwing my custom exception.
This should be solvable by providing to the map function with a list of exceptions you expect it to propagate when calling it, similar to how you might provide type information to a generic function. As far as I can tell, this issue is mostly an annoyance because Java has yet to provide the language-level features to make exception handling work with higher-order functions.
I've also found this article about "anchored exceptions" that I understand is supposed to fix this issue in Java. It's a dense read, and I'm not sure how much I understood from it, but it's still interesting.
2. Adding a new exception to a type signature is a breaking change, and all client code has to update.
There are potentially two reasons why you might want to cause your function to throw a new exception:
A. What used to be a fatal error is now being treated as an exception (because you found that people actually wanted to recover from that scenario). This is probably the most common scenario, and one reason people get annoyed with Java's checked exceptions. This should not be treated as a breaking change to client code, and client's should not be forced to update their own code just to indicate that they still want to treat that exception as a fatal error.
B. What used to be working code is now being treated as an exception. This is a breaking change, and each user of your API should be forced to decide how to handle it.
There are a few ways this could be fixed. I'll point out a couple (this first one isn't necessarily the best idea, but it shows that this doesn't have to be an issue with checked exceptions). Make it so there are two types of exceptions you declare in the function signature - exceptions that you require the end-user to explicitly handle, and exceptions that you don't care if they handle or not (if they don't handle it, it'll auto-escalate). Another option is to loosen things up a bit and not force changes in thrown exceptions to be a breaking change in client code (the "A" scenario is more common anyway) - this also means you can't force a client to explicitly acknowledge each type of exception that might be thrown when calling a function.
3. Checked exceptions may force users to handle an exception they know shouldn't ever happen.
For example, right before indexing into an array, you might first check if your index is within bounds. When you actually index into an array, it might throw IndexOutOfBounds, which you then have to catch and handle, even though you know that exception should never happen (thus, this exception is really a fatal error in this specific scenario). This is a lot of extra annoying boilerplate.
This can be solved by providing terser syntax to automatically escalate exceptions as fatal errors. Right now, Java users have to do an entire try-catch, catch the specific exception, and rethrow it as an instance of RuntimeException.
4. Checked exceptions are verbose
With each solution we decide, there's always going to be a balance with how verbose it is to use, and how secure it makes us. Different syntax, etc, can help out, but there's always going to be a verbosity cost, and it's something we'll have to keep in mind.
These are the main issues I saw while reading through the articles. If I missed any important ones, please feel free to speak up and we can address it. But, I think the takeaway here is best described by the Anders Hejlsberg from @claudiameadows's last article: "checked exceptions are a wonderful feature. It's just that particular implementations can be problematic". In other words, with some tweaking, all of these things that people hate about checked exceptions can be solved. We just need to keep in mind the places where Java failed in our own design.
I'll start of by naming a few:
Problems the new exception system should solve:
- Provide a way to self-document what exceptions a particular function can throw/give.
- Provide a way to easily escalate exception into fatal errors when you know that particular exception should never happen. (This solves issue #3 with checked exceptions)
- It should be difficult to accidentally ignore important exceptions
Features the new exception system should provide:
- It should be possible to throw/give a new exception without forcing all users of your API to update their code (because it was a none-breaking change - this solves issue #2 with checked exceptions)
- When an unexpected exception occurs, it should be difficult to forget to escalate it (thus, letting it slip through, and potentially getting inappropriately caught and handled)
- It should integrate well with higher-order functions (This solves issue #1 with checked exceptions)
Feel free to suggest other points you feel an exception system should provide.