[idea] introduce try/catch expressions (in addition to current try/catch statements)

Brian Goetz brian.goetz at oracle.com
Mon May 24 15:44:15 UTC 2021


> Recently I've come up with an idea (perhaps common one) to improve

Yes, this is a very old idea, which gets dusted off once in a while and admired.

It’s not a _bad_ idea; the question is whether it is _good enough_ (given the very high bar for “good enough to be added to the Java language.”)  But, I think the underlying goal you’re aiming at — totalizing computation — is not something you can easily morph Java into, and the cost is high.  

> Let's say there are a few ways to fetch the same data, so I want to
> start with the fastest way first and then try other ways. To avoid
> nested identations I want to have a local variable that keeps the
> result. In current Java I can have:
> 
> Optional<String> result = null;
> try {
>  result = Optional.of(readFileAsString(cachePath));
> } catch (IOException e) {
>  result = Optional.empty();
> }
> 
> With try/catch expression it could be shortened - let's say that
> insead of "try" there's "try ->" that turn try/catch from statement to
> expression:
> 
> var result = try -> {
>  Optional.of(readFileAsString(cachePath))
> } catch (IOException e) {
>  Optional.empty()
> }

You are already speeding down a slippery slope here towards “block expressions everywhere.”  Switch expressions dipped a very cautious toe into that water, but there’s a powerful syntactic indicator — such blocks are always preceded by -> , suggesting that they must yield a value.  This formulation basically goes whole-hog on block expressions, because the catch block can now either be interpreted as a statement block or an expression.  It would be pretty hard to keep that for catch blocks, and not have that want to infect if, while, and other block forms.  

More importantly, this form of try expression (which I think of as being related to the ternary expression) isn’t really all that helpful.  It’s not all that much more concise, nor is the “swallow exception and return a default value instead” all that common (because its information-destroying), and its something you can easily write as a single generic method that takes a lambda. 

> Second argument is that short syntax for try/catch expressions would

> encourage people to represent failures as data

Without some sort of Either monad, this approach to computation-totalization is intrinsically information-destroying.  I’m not sure that this is what we want to encourage.  

Where people really want help with exceptions is in their interaction with lambdas.  But this form of try-expression doesn’t help at all for that; the incremental concision isn’t enough.  

> Third argument is that there are already switch expressions, added
> decades after switch statements. Therefore introduction of try/catch
> expressions could be thought of as something like introduction of
> switch expressions - both are somewhat limited in scope (at  least at
> first, without potential later additions).

This is not so much an argument for, as much as an argument against the argument against :)   

> When put this way, this
> could be more likely to be accepted without extending the scope of the
> change (e.g. into a complete redesign of exceptions handling in
> javac). To make things even more focused on turning  statements into
> expressions, there could be a simultaneous sibling proposal to
> introduce if/else expressions in addition to current if/else
> statements.


You can build a language to be expressions-all-the-way-down, and that is a pretty good design principle.  It is not, however, the design principle Java is founded on, so the intrusiveness here (especially to what blocks mean) is pretty significant.  

Totalizing computation is a noble goal, but I think you’re trying to roll back time and change some fundamental language design decisions.  I don’t fault your motivations, but I don’t see this as being successful in the end.




More information about the amber-dev mailing list