Retiring Checked Exceptions Was: Throwing Functions

Brian Goetz brian.goetz at oracle.com
Sat Nov 12 22:50:17 UTC 2022


I appreciate John's points here.  I don't necessarily agree with all of 
them (there's a spectrum of opinions, and that's fine, though I find #3 
especially compelling), but I think this illustrates something about the 
exceptions debate that is easy to miss: the people who hate checked 
exceptions are much noisier about it than those who don't, and so they 
are likely to be fooled by confirmation bias since all the other loud 
voices seem to agree with them.  But I've found that there are a lot of 
people out there who quietly think checked exceptions are ... pretty 
OK.  Maybe even a majority.  They just don't want to engage in a big 
debate, they'd rather get their work done.




On 11/12/2022 11:16 AM, John Hendrikx wrote:
> I very much disagree with this position, so I will make a case for 
> checked exceptions:
>
> 1) Without checked exceptions, using exceptions for alternative 
> outcomes as part of the contract of an API would no longer be 
> possible. This is because adding a new exception to the API would no 
> longer be a breaking change. Documentation is not going to save you 
> here.  Effectively, exceptions would have only two uses left (like in 
> other languages): fatal JVM breaking errors and to signal mistakes 
> that could have been prevented by the programmer.  Using them to 
> signal unpreventable errors would be highly suspect and likely quickly 
> be considered a bad practice.
>
> In other languages (but also in some Java API's that use runtime 
> exception to signal unpreventable errors) the compiler cannot help you 
> with these alternative outcomes as it isn't even required to specify 
> them as part of your API. It helps you with the return value, but not 
> for any other outcomes. These other outcomes will now have to guessed, 
> gleaned from the documentation (if it is up to date), or by doing 
> manual code mining (of the called function and all the functions it 
> calls).  Worse, these outcomes can change in later releases without 
> any warning as they're non-breaking changes.
>
> 2) API's without checked exceptions will necessarily become more 
> cluttered than their counterparts with checked exceptions. They would 
> have to return wrappers or unions or special values to enforce proper 
> use. API design like this prevents easily deferring the handling of 
> rare occurrences higher up the call chain with standard idioms to keep 
> the current code path clean and to the point.
>
> 3) Removing checked exceptions now would break the **design** of many 
> current API's, making them dangerous to use without the checks and 
> balances that were present when they were designed.
>
> 4) Earlier design decisions to exclude checked exceptions from new 
> idioms and API's were a mistake that should be rectified not doubled 
> down upon. A large part of the momentum against checked exceptions 
> comes from the clumsy way that checked exceptions must be handled 
> while using these new features that were essentially incompatible with 
> existing Java.  Even with the current status quo, it is possible to 
> design API's that do allow checked exceptions in combination with 
> functional programming, it is just cumbersome to design these API's 
> without a dedicated union type (for exceptions).  They either support 
> only one checked exception or some limited number.  Their use is 
> however as transparent as API's that do not support checked exceptions.
>
> 5) The fact that the value of checked exceptions is hard to recognize 
> or cumbersome for beginners or non-Java developers should not have any 
> bearing on language design.
>
> Checked exceptions differentiate between the common preventable 
> programming errors and essential business logic. The difference 
> between a runtime exception (leaving out Error) and a checked 
> exception is that one can only occur in incorrect code, while the 
> other can occur even in correct code. One indicates a preventable 
> programming mistake and the other a missed path in your logic.  
> Throwing these on the same heap will effectively reduce the usefulness 
> of all exceptions to programming mistakes (and fatal errors) only.
>
> 6) If anything, I think there should be way to promote runtime 
> exceptions to checked exceptions within certain modules.  This would 
> allow API / library designers the option to have the compiler check 
> their code for missed documentation and missing logic even for what 
> externally would be a runtime exception.  This would be especially 
> useful during initial design and also later refactoring as the 
> incredibly useful compiler checks for checked exceptions could be 
> extended to proper use and propagation of runtime exceptions within 
> that module.
>
> --John
>
>
> ------ Original Message ------
> From "Remi Forax" <forax at univ-mlv.fr>
> To "Nathan Reynolds" <numeralnathan at gmail.com>
> Cc "amber-dev" <amber-dev at openjdk.org>; "amber-spec-experts" 
> <amber-spec-experts at openjdk.java.net>; "Ron Pressler" 
> <ron.pressler at oracle.com>
> Date 12/11/2022 08:58:57
> Subject Retiring Checked Exceptions Was: Throwing Functions
>
>> [promoted to amber-spec-experts]
>>
>> I think we should tackle this problem at its core and retire the 
>> notion of checked exceptions
>>
>> The written are on the wall since quite some time, but we have not 
>> yet acknowledge it.
>>
>> Let's recap the issue and the clues pointing in that direction.
>>
>> I believe the first straw can be tracked back to the inability of the 
>> type system to create a type variable containing the union of 
>> exceptions when generics where introduced in Java 5.
>> It's the reason why there is no ThrowableConsumer, as an example, 
>> imagine that a stream can declare a checked exception Stream<T, E> 
>> and a user call map() that takes a ThrowableFunction,
>> we need a way to express that the resulting stream is that combine 
>> the exceptions of the original stream and the exceptions that may be 
>> raised by calling the function of map.
>>
>>   Stream<T, E extends Exception>  --> map(ThrowableFunction<T, R, F 
>> extends Exception>) -->  Stream<R, E | F>
>>
>> Or perhaps from the beginning of Java, adding a checked exception to 
>> a "throws" colors the function the same way the keyword async or Rust 
>> lifetime type information color a function [1]. Adding a checked 
>> exception to a function is not a backward compatible change.
>>
>> So we have some of idioms that beginners need to internalize to try 
>> workaround checked exceptions,
>> - The oldest is i think, Thread.currentThread().interrupt() which 
>> allows to silence an InterruptedException at the price of continuing 
>> to execute the code until the next blocking call
>> - UncheckedIOException and IOError that both wrap an IOException into 
>> an unchecked exception allowing tunneling of checked exceptions ; 
>> wrapping an IOException and unbundle it later.
>> - Unsafe.rethrow (this one was retired)
>> - the unfamous rethrow using erasure to see a checked exception as an 
>> unchecked exception
>>    static <T extends Throwable> AssertionError rethrow(Throwable 
>> cause) throws T {
>>       throw (T) cause;
>>    }
>> - IntelliJ has changed the default try/catch snippet to instead of 
>> calling printStackTrace() to throw a RuntimeException wrapping the 
>> exception.
>>   This simple change is i believe the best change to Java in the 
>> recent years (perhaps toes to toes with records), at least now the 
>> code of my students does not print the stack trace and resume its 
>> course when an exception occurs.
>>     try {
>>      ...
>>     } catch(FooException e) {
>>       throw new RuntimeException(e);
>>     }
>>
>> Also no language presented as potential successor of Java, neither 
>> Scala nor Kotlin have checked exceptions, because functions with 
>> checked exceptions do not compose.
>> If Java wants to be the next Java, we will have to drop checked 
>> exceptions at some point.
> I don't see the relevance of what other languages are doing with their 
> own agenda's. There is no need to drop checked exceptions, they just 
> need to be an integral part of the whole. Removing them doesn't make 
> Java the next Java, it just makes it yet another language with 
> slightly different syntax that succumbed to a vocal minority that 
> values simplicity over safety.
>
>> The good news is that seeing all exceptions as unchecked exceptions 
>> is a backward compatible change, "throws" can still be supported for 
>> documentation purpose, the compiler can emit a warning instead of an 
>> error if there is no catch corresponding to a checked exception and 
>> allow everyone to catch any exceptions in the code.
>
>>
>>
>> I think we should recognize that the idea of checked exceptions was a 
>> good idea on paper but not a good one in practice and work to retire 
>> the concept of checked exceptions from Java.
>>
>> Rémi
>>
>> [1] 
>> https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/
>>
>> ------------------------------------------------------------------------
>>
>>     *From: *"Nathan Reynolds" <numeralnathan at gmail.com>
>>     *To: *"amber-dev" <amber-dev at openjdk.org>
>>     *Sent: *Saturday, November 12, 2022 5:47:10 AM
>>     *Subject: *Throwing Functions
>>
>>     I am sorry if I am very late to the discussion. Consumer,
>>     Function, Predicate, and Supplier don't allow for throwing
>>     checked exceptions.  This feature is needed in many cases.  What
>>     about adding a variant that allows for throwing checked
>>     exceptions?  For example, a ThrowableConsumer could be defined as
>>     such...
>>
>>     public interface ThrowableConsumer<T, E extends Throwable>
>>     {
>>        void accept(T t) throws E;
>>     }
>>
>>     A method that receives this as a parameter could be defined as
>>     such...
>>
>>     public <E extends Throwable> void process(ThrowableConsumer<T, E>
>>     consume) throws E
>>     {
>>        ...
>>     }
>>
>>     The compiler takes care of ensuring the checked exception is
>>     dealt with in the caller to process().
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20221112/b542b31a/attachment-0001.htm>


More information about the amber-dev mailing list