If ... throws

After reading a lot on Exceptions, I see that the “try-catch” syntax is considered a pain by a lot of people, and that Exceptions are not as used as they could be.

To solve this, I think there is a better way to do it:
Let’s assume I have a method request.execute() which might throw ExampleException. It would be nice to be able to write:

if (request.execute() throws ExampleException)
  doSomething()

Compared to the traditionnal try-catch:

try {
  request.execute()
} catch (e: ExampleException){
  doSomething()
}

I thinik my solution is better because it is 1) more concise, 2) more readable, 3) more intuitive because it uses the same syntax as other conditionnals do.

This could also shine in when expressions:

when (str.charAt(i)) {
    'a'..'z' -> ...
    'A'..'Z' -> ...
    throws ArrayIndexOutOfBoundsException -> ...
    else ->
}

This is a lot cleaner than the same code with a try-catch, and is definitely easy to understand. From my understanding it doesn’t seem like a major modification to the language, but I’m no expert so I could be wrong.

Maybe this would even be possible with a simple extension function, but it would be nice that this was included in the standard lib.

That’s ingenious, but I see issues:

  • No access to the thrown exception (without adding further special syntax). In practice, you very often want this, whether to check its details, log it, and/or rethrow it.
  • No way to add further actions to take if the operation succeeds.
  • No way to catch multiple exception types.
  • Hard to read if the operation isn’t very short.

And if you addressed all of those, you’d basically end up with the existing trycatch anyway. So special syntax doesn’t seem justified for this.

1 Like

Here are possible solutions:

  • That’s a good point, maybe a variable with a special name? (alike ‘it’ in lambdas with no parameters)

  • What do you mean ? There’s still the ‘else’ clause for that: if(a() throws Exception) {...} else {...}

  • You can with the when expression

    when (...){ throws E1 -> ... throws E2 -> ... }

  • “The operation is not very short” do you mean “the operation that throws the exception” ? If so, this is a case where the try-catch can still be used. I’m not really saying that it’s bad, I just mean that making it compatible with if and when would be a great improvement for the language overrall. Now that might not be the best way to do it, but I feel like it should be discussed. Maybe someone will find something even better.

In pt.2 I meant cases where you want to take the same action if any of several adjacent statements throw an exception. You know, the equivalent of:

try {
    doSomething()
    doSomethingElse()
    doSomethingSlightlyDifferent()
} catch (x: SomeSortOfException) {
    // ...
}

The equivalent using the proposed syntax isn’t any clearer:

if (run { doSomething();  doSomethingElse(); doSomethingSlightlyDifferent() } throws SomeSortOfException) {
    // ...
}

And in pt.4 I meant e.g.

if (myCollectionOfStuff[someParameter.toLowerCase()] == someObject.someProperty.split(" ").firstOrNull() } throws SomeParticularTypeOfException) {
    // ...
}

Again, not very clear! And I suspect these longer examples are more representative of real-world programs in general.

Another thing the proposed syntax wouldn’t be able to do is return the value of the protected expression. (Again, without yet more special syntax.)

The base case doesn’t even gain that much over the existing syntax, if you wrap lines. Compare your:

if (request.execute() throws ExampleException)
    doSomething()

with:

try { request.execute() } catch (x: ExampleException) {
    doSomething()
}

The only case which has clear benefits is the when example. That seems significantly simpler than the existing alternatives, and doesn’t suffer from some of the problems in the if examples.

One of the reasons I like Kotlin so much is that its designers knew what to leave out, just as much as what to add in. I’ve seen kitchen-sink languages which included every pet feature their designers liked; they can do really cool stuff, but are much harder to learn, have buggier implementations, are much harder to use well (i.e. without causing unexpected behaviour), complicate further development of the language, and make it much harder to understand or maintain anyone else’s code.

So every feature must pull its weight. And for me, the proposed syntax for the if case really doesn’t seem to do that. That for the when case seems more worthwhile. (Though it would still need extra syntax to give access to the exception that was thrown.) That would be up to the language designers to judge, of course.

Okay I see all of this.

I really the think the when example is worth it, so maybe just add the possibility the catch in when expression ?

when (...) {
    1 -> ...
    catch IOException ->
}

This might make more sense than a ‘throws’ keyword (and, limiting the number of keywords is a nice thing).

Maybe use the same syntax as in try-catch?

when (...) {
    1 -> ...
    catch(e: IOException) ->
}
1 Like

Note that you can do this with an inline library function with equivalent performance (possibly equivalent bytecode):

inline fun <reified E : Throwable> catching(fn: () -> Unit) {
    try {
        fn()
        return false
    } catch(e: E)
        return true
    }
}

Then you can call this with:

if (catching<ExampleException> { request.execute() })
  doSomething()

You may consider to use Result

2 Likes