Language feature to improve checked exceptions

Red IO redio.development at gmail.com
Sun Mar 5 06:58:54 UTC 2023


This looks to target a similar problem as my suggestion to treat every java
control flow element as an expression potentially returning a result.

Your first example would look like this with my concept:

String text = try {

                yield Files.readString(somePath);

} catch(IOException ex) {

                throw new UncheckedIOException(ex);

};

It would stay true to the try catch finally syntax and would reuse the
already existing expression yielding syntax from switch expressions while
still removing the unsound partial initialized field.


Great regards

RedIODev

On Sun, Mar 5, 2023, 00:49 Tom L <tom_l64 at hotmail.com> wrote:

> Hello, it's the first time I send an email here, I have no idea how things
> work, so I hope I am doing things somewhat correctly.
>
>
>
> I wanted to make a suggestion about exceptions :
>
> Checked exceptions are used as a meant of a second return type, which
> shouldn't happen in most cases, and then, depending of what the caller
> wants to do, it will handle it in a certain way. So in some sort, a checked
> exception is like part of the return type, like you would have a
> Result<Success, Failure>, compared to unchecked exception in java which are
> just supposed to be bugs.
>
> But this feature causes some burden, so much so that some languages, even
> languages compiling to java (ie kotlin) got rid of checked exceptions, and
> other languages like Rust use a Result<Success, Failure> which, which, with
> enough language constructs, can be quite good.
>
> While I agree that not having checked exceptions nor Result but instead
> only unchecked ones would be a bad idea, because it would mean that a part
> of the return type is unknown, which we wouldn't want in a strongly typed
> language, I believe some action needs to be taken.
>
>
>
> In my opinion, one of its burdens is caused by the try-catch language
> feature :
>
> String text;
>
> try {
>
>                 text = Files.readString(somePath);
>
> } catch(IOException ex) {
>
>                 throw new UncheckedIOException(ex);
>
> }
>
> //do something with text
>
> This is a common example, of how you would use it : you want to read a
> string, and an IO error shouldn't happen, so you fail-fast
>
> The reason why I didn't use text inside the catch, is because the catch
> should only be for this specific exception, and also it would add another
> level of nesting, which would start to hurt when other ifs or try-catches
> appear.
>
> This code is boilerplate and is error-prone, since you always have to
> repeat the same lines, it is also weird for any non java programmer.
>
> And this is far from being the worst, because another common example is
> with streams, since you can't throw checked exception, you have to handle
> each time, in each stream operation, and even if you wrap this code in
> methods and use method references, it's still far less readable than having
> a short lambda where you see exactly what the stream is doing.
>
> If checked exceptions were instead a Result type, a solution to this
> problem would be to make a unwrap() method (like in Rust, or like with
> Java's Optional#orElseThrow())
>
> String text = Files.readString(somePath).unwrap();
>
>
>
> So my suggestion is that, since catching is a language feature, it can
> only be dealt with another language feature :
>
> String text = Files.readString(somePath) throw IOException ex as new
> UncheckedIOException(ex);
>
> If this method throws an IOException, it will rethrow it as an
> UncheckedIOException.
>
> About the syntax, I used "throw" since it's an already used keyword, but
> depending of the meaning, it could be "catch" or whatever, and "as" could
> be "->" if using a contextual keyword is too much.
>
> This code could even be simplied as the following with new methods or
> language features, in the future :
>
> String text = Files.readString(somePath) throw IOException ex as
> ex.unchecked();
>
> String text = Files.readString(somePath) throw IOException as unchecked;
>
> etc.
>
> Unchecked part could either be the same exception except the compiler
> ignores it (I know this is possible since it's possible to throw a checked
> exception as an unchecked), the idea is that since you are telling the
> compiler that if an exception happens, then it should fail-fast, then the
> compiler should be able to say "ok, I trust you".
>
> An alternative would be that the unchecked simply wrap it in a
> RuntimeException or a specific unchecked exception.
>
>
>
> So, what's the point of this, does it only serve this use case ?
>
> So first, is it important to note that it isn't just for checked ->
> fail-fast, but also checked -> some other checked, when exception
> conversion is needed, which can be useful, and also unchecked ->
> checked/unchecked, for example if an API only provides an unchecked like
> Integer#parseInt.
>
> Now about the use case : this syntax, isn't just a compressed try-catch,
> it's also an expression, which is very important, because not only you can
> very clearly handle this kind of cases, but it can provide easy to read,
> concise code in lambdas  and assignments, for example :
>
> try (var files = Files.list(path) {
>
>                 return files.filter(this::matcher)
>
>                                                .map(p ->
> Files.readString(p) throw IOException as unchecked)//Possible syntax
> Files::readString throw IOException as unchecked ?
>
>                                                .toList();
>
> }
>
> And in the future, a new method could be added for streams called
> .continueOnFailure(IOExcepion.class) (or UncheckedIOException if the
> unchecked wraps the exception instead of marking it as unchecked) for
> example, which would continue even if there is an exception.
>
> An additional syntax could also be provided for cases where catching is
> used as an if else :
>
> OptionalInt parseInt(String s) {
>
>                 return OptionalInt.of(Integer.parseInt(s)) catch
> NumberFormatException -> OptionalInt.empty();            // Using -> syntax
> here instead of "as" to show that it can also make sense
>
> }
>
>
>
> I hope it can fix this unholy war of checked exceptions which never seem
> to advance.
>
>
>
> Sincerely.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20230305/ee1e807d/attachment.htm>


More information about the amber-dev mailing list