4 ms·
I think checked exceptions are backwards. If you use a `throws` declaration the caller must catch it. It quickly becomes quite onerous. (Especially if you come
by captainmuon 6y ago
I think checked exceptions are backwards. If you use a `throws` declaration the caller must catch it. It quickly becomes quite onerous. (Especially if you come from the philosophy that an exception often means "abort this program - unless somebody catches this". In small programs you might just want it to crash early.) And even worse, it is not exhaustive. You can always get a RuntimeException or a NullPointerException from nowhere.
It would be great if they worked the other way around. Instead of forcing the caller to catch an exception, they would guarantee that no exception leaves a certain block.
So you would have a function
void MyFunc() onlythrows IOException {
first();
second();
}
And the compiler would statically guarantee that no other exception can leak out of it - because first and second have been marked `onlythrows IOException` or are "pure" and cannot throw at all.
For sure you'd need an escape hatch, like Rust's "unsafe". And it would not be very useful around legacy libraries. But it would be tremendously useful if you could drop a block like
neverthrows NullPointerError { ... }
in your code and be sure that everything inside is null safe! I asked about this a few years ago on StackExchange [1] but so far I never heard about it anywhere else.
[1] https://softwareengineering.stackexchange.com/questions/349775/different-kind-of-checked-exceptions-guarantee-to-only-throw-x https://softwareengineering.stackexchange.com/questions/3497...
- Nursie 6y agoYou shouldn't be getting NPEs at random. And if you want to protect against them, just catch them. Your "neverthrows" looks to me just like a different way of expressing try/catch
- captainmuon 6y agoIf you use try/catch, you can either swallow the exception, deal with it, or rethrow. But sometimes you don't know how to handle or rethrow an exception. Maybe you don't even know that the library code you are calling is going to throw! A "neverthrows" block would not compile if there is anything inside that can throw (even a runtime exception). Its a way of drawing a line. A library author could use it to make sure no unexpected exceptions can bubble up. And yeah, if you get NPEs at random you are making a mistake. If I could just choose to not make mistakes, I would :-D. But until then, I'd prefer the compiler to check my work. (And catching them is not an option. What do you do then? Terminate the program? Ignore them? They need to be found at compile time, not at runtime.)
- sirmarksalot 6y agoIt's an interesting idea. My only issue is that if you decide to call an existing function from your "neverthrows" function, there's no way to tell whether it's okay to call that function without actually running the compiler. And if you want to take that opportunity to do an audit of null correctness, you're at the mercy of the compiler's error message to hopefully tell you where the offending code is.
- lultimouomo 6y ago> I think checked exceptions are backwards. If you use a `throws` declaration the caller must catch it. I'm not sure I I'm reading your comment right, but this is plainly false. Caller can add a throws declaration themselves and catch anything. It seems to me that what you're advocating bears no difference at all with checked exceptions. The "unsafe" escape hatch is called RuntimeException. "throws" behaves exactly like your advocated "onlythrows". The only actual difference you're proposing, AFAICS, is that you'd like java to handle nulls differently - and I think we can all agree on that.
- captainmuon 6y ago> Caller can add a throws declaration themselves and catch anything. You are right. I meant someone in the call stack has to catch, not the immediate caller. That I mentioned null pointers is a red herring. I want to add a block that tells the compiler "prove that no exceptions (checked or unchecked, not even NPE)" can escape outside of this block!". The escape hatch is about this: imagine you have a function that throws if the argument is odd, but you know you will only call it with an even number: void myFunc(int i) never_throws { swear_never_throws(NumberOddException) { throwsIfOdd(i*2); } } (Apologies for the pseudo-code, I haven't made up a nice syntax.) If you mark your function that no exception can escape (not even an unchecked exception!), but the compiler sees that throwsIfOdd can throw NumberOddException, you must of course assert that what you are doing is OK.