Remove Curly-braces in try, catch, finnaly blocks

A simple try catch block can looks like this:

fun readMessage(reader: () -> String): String =
        try {
            reader()
        } catch (e: Exception) {
            e.message ?: "error"
        }

Why not doing it like this for single instruction :

fun readMessage(reader: () -> String): String = 
        try reader() catch (e: Exception) e.message ?: "error" 

Like if/else blocks does

4 Likes

Really like this idea. I think it would be even more useful when assigning values.

val a = try evaluate() catch (e: Exception) someErrorHandling(e)

Curly braces removal for various cases was discussed multiple times here (I am personally completely opposed to the idea).

As for your example, it usually leads to performance problems to catch errors from single operation. Catch and re throw exceptions is very slow on JVM, so usually there should be only one catch block on the top level and it should be visible.

1 Like

This depends on the developer’s needs I guess, it would still look like a nice option to have lying around

Is the following lines valid?

val a = try evaluate() catch (e: IOException) someIOErrorHandling(e) catch (e: Exception) someErrorHandling(e)

val a = try try evaluate() catch (e: IOException) someIOErrorHandling(e) catch (e: Exception) someErrorHandling(e)

Your own example is a great illustration of why this is not a great idea. Since try is an expression in Kotlin, your example has two possible interpretations:

   (try { reader() } catch (e: Exception) { e.message }) ?: "error" 

or

    try { reader() } catch (e: Exception)  { e.message ?: "error" }

Making code harder to understand for the sake of saving a couple of characters in a construct which isn’t commonly used as a one-line statement is hardly a worthwhile tradeoff.

4 Likes

Never think the statement could be interpreted like this… And I could not see any kind of solution to it.
You just blast the idea. Ok then.

I would say default parameters (like in lambdas) would help a lot:
try { reader() } catch { it.message ?: “error” }
(or maybe at least catch (e) { e.message ?: “Error” }

Maybe not catch (e) { ... } but something like this :

try { evaluate() } 
catch (EvaluateException) { named -> evalutationErrorHandling(named) } // explicit name
catch (IOException) { ioErrorHandling(it) } // `it` is IOException
catch { defaultErrorHandling(it) } // `it` is Exception by default

This would be backwards incompatible so low chance of passing - my proposition is just omitting type optionally (as we do in many other cases) but doesn’t change the syntax for existing code nor introduces something completely not compatible with current way of handling exception

I like the OP idea. I think it should have the same behavior as if/else expression when it is a single statement.

Should be great too if this behavior is added to another functions like let.