Grep isn't a library. It's a program. Some things are important in the library level e.g. an SQL exception must have proper cleanup. However, in some cases you don't want to cleanup. You might want to try a different approach so generic cleanup code isn't necessarily the right thing.
E.g. in the case of grep. Say I wrote grep and want it to be generic. I wrote a library that implements grep. Then I write a grep GUI tool. OOps. It exits if the file isn't found instead of showing an error dialog. With exceptions this is communicated up the layers. That's their purpose.
If I'm writing generic code and that code is used in a nuclear reactor I would very much not like my failure code to decide what to do. That's why we have exceptions, they punt the responsibility to the next person up the chain. I have no idea how to initiate a nuclear reactor shutdown etc.
But as API authors how can we make sure the person who writes the code up the chain knows that this is something crucial?
Yes, grep and nuclear reactor controller, and your gui grep are applications.
They all use library for file reading.
As author of file reading library you don’t know how critical is the failure to open a file or how it should be handled. My point was that You know those things only at application level.
So it feels a bit misguided to decide at library level which failures are important. (I.e. which are checked vs which are unchecked)
> But as API authors how can we make sure
First thought: documentation. (which is required for both, checked and unchecked exceptions).
But overall, it’s not library author’s responsibility or ability to “ensure”. You can’t force correct handling of exception. At best one can make it a bit more annoying to ignore, and convenient to do the right thing.
My view:
- all exceptions should be unchecked
- assume all code throws
- if “log and exit/continue” is not enough and you need to know exact exception types, dig into the docs.
The library knows which are crucial issues that warrant your attention. A checked exception is a regular exception, it's just one that you can't miss and must either handle or propagate.
As a library author if you don't feel you need it then don't use it. It's optional. That's the beauty of it.
> First thought: documentation. (which is required for both, checked and unchecked exceptions).
Documentation < compiler checks.
> But overall, it’s not library author’s responsibility or ability to “ensure”.
Here we differ. Part of that is the domain we spend most of our time in. If you're giving me the example of grep then great, I see your point. Notice I'm giving an example of a high availability huge enterprise app.
Assuming all code throws forces overly defensive code which can cause a lot of problems. Yes, there's always a "catch all" but that's not a valid case for these sorts of apps.
Exit or continue are never enough for these sorts of applications.
We have dozens of dependencies and sometimes more. Some of them have mountains of documentations. Often we delay updates since these are enterprises. Going over 3 years of diffs in docs is just not a feasible option. Just the diffs in Spring Boot alone and all its dependencies would take several years.
Indeed. For most applications, an out-of-memory exception is typically one that's not necessary to handle and just let it bubble to the top, as there's not much sensible you can do if you can't allocate a few hundred bytes for a new object.
However I've written several pieces of code where allocating a large buffer could fail but where this failure was not crucial. So I handled the out-of-memory exception and just moved on.
If you're unsure then make it a runtime exception. I agree that a lot of the problems people have with checked exceptions is that people over use them.
You don't want to handle the checked exception wrap it with a runtime exception. But as an author if there's something important, I want to give the user of the library as much help as I can.
You're still ignoring other people's point in this thread: you (the author of a library/package) cannot decide what is important for the users of your library. You can guess, but your guess will always be wrong for a subset of your downstream users.
And speaking from the other side, as an application developer: for most of my code, an ArrayIndexOutOfBoundsException is a pretty serious exception. How do I go about making it a checked exception?
That's your point of view. It's up to you. My experience is different and often deals with handles very large projects with serious continuous uptime. When you have dozens of developers committing to a project and using the APIs exiting with an error just isn't an option.
That's not a practical strategy in a large system. That's why we have exception handling.
When we write generic library code we have no way of knowing how to handle an error in the full system. We want to concentrate some of the error handling while still making localized decisions in various places.
E.g. I want metrics and observability details updated, yet I want locally to retry some behavior. Doing this every time there's an error would force every library and every part that can fail in my code to know how I plan to handle the error.
E.g. in the case of grep. Say I wrote grep and want it to be generic. I wrote a library that implements grep. Then I write a grep GUI tool. OOps. It exits if the file isn't found instead of showing an error dialog. With exceptions this is communicated up the layers. That's their purpose.
If I'm writing generic code and that code is used in a nuclear reactor I would very much not like my failure code to decide what to do. That's why we have exceptions, they punt the responsibility to the next person up the chain. I have no idea how to initiate a nuclear reactor shutdown etc.
But as API authors how can we make sure the person who writes the code up the chain knows that this is something crucial?