They also force you to declare that an exception is thrown if you don't want to handle it in the current method. That's important as the signature of the method carries an important failure that can't be dismissed and is enforced by the compiler.
But importance of the failure is determined completely by the program, not the library.
Grep fails to open a file for reading -> message the user and exit
Nuclear reactor controller fails to read important a file -> initiate reactor shutdown or something.
If file read is critical, you have to handle failure no matter what the interface is. Because you know that disk can fail.
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?
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.
- read docs during lib version upgrades
I can choose to handle the error myself or let the shell script crash by having “set -e”.
Grep returns a non zero error code and it’s still up to me to decide how to handle it.
This can be solved with good documentation, but it can also be solved in the type system. Typically, if I can get my computer to do work for me (e.g. make sure that I've handled all possible error cases) then I'm much more confident in my code, hence why I see a lot of value in a well-designed checked exceptions system.
Exactly. I think this is the real crux about what's wrong with checked exceptions. It puts the responsibility to decide what exceptions are important on the library, where it doesn't belong. Only the user of the library knows that.
I'm not a friend of checked exceptions myself, but I still think it's the opposite.
¹ which leads to the real issue with checked exceptions: they propagate through dependencies, if one nested dependency adds another checked exception, all dependencies have to add the exception or handle it themselves.
I get a failure, what do I do?
I can throw an exception, but this is important how do I know the user of my API will actually do the cleanup after me. I can't do the cleanup since this is a part of an API not the actual usage of the API. How can I give the user of this API the right set of hint that "you need to pay attention to this" without worrying too much.
Checked exceptions are that. A large part of the problem is when people use them for things that aren't important, but when they are important I can just declare a "throws" and know that someone will handle the exception along the chain.
With runtime exceptions I have no guarantee.
My naive take on this would be “just use raii/closable”. (But easily and likely, I misunderstood)