In future, could Kotlin have checked exceptions?

First, I love the fact that checked exceptions are missing.
I do use the functional way, though: the Try-class.

The Try-class with getValueUnsafe is the same as unchecked exceptions.
If you don’t have that function, you do need to check the type -> checked exception.

Try-classes with all their callbacks are harder to chain.
But I believe something like that can be solved the same way suspend already solves multithreading.

try fun foo() : String = ""
fun outside() = when(val v = foo()){
    is Success -> println(v.value)
    is Failure -> println(v.failure.message)
}

try fun inside(){
     val value = try { foo() } catch(e : Exception) { it.message }
     println(value)
}

or if you want to simple rethrow on exception:

try fun inside() = println(foo())

Here you tell people clearly that you expect some exception to be thrown.
The drawback:

  • Silencing can easily be done by adding tthe getValue or adding try before the function.
    This way, either lots of functions would become try-functions, or a lot of functions are silenced.
  • Also, it doesn’t tell which exceptions can be thrown.

If a (way better) function like this would be implemented, it would be done in arrow-kt, combined with arrow-meta.

Yes, your idea using “try” functions could/will solve the compatibility to Java, something like I mentioned here.

Maybe ask in the arrow-group on slack if they have ideas how you can implement it using arrow-meta?

Still missing checked eceptions, none of this solutions worked out for me i always have to write boilerplate code see to my last posts why… i still think giving developers the option to use them is always good

1 Like

Is there a Kotlin fork having checked exceptions already?

1 Like

Just had a thought a compromise between Java’s pedantic enforcement of checked exceptions and the wild west of no enforcement would have been to treat it like lint warnings:

  • have the distinction between exceptions that are unexpected and those that are expected, In Java terms Exception vs. RuntimeException
  • If a function throws or calls a piece of code that is declared to throw a “checked” exception there should be a lint check to see if the function either catches the exception or declares that the function throws that exception
  • like normal lint style checks provide a way to suppress for the line, function, class, or file
  • provide a way to specify if that lint check globally is ignored, produces a warning, or produces an error

That would let the programmer be as pedantic as they want to be.

3 Likes

Isn’t this just equivalent to a checked exception? Your function either returns Success or FailureDueToX, FailureDueToY, etc. That’s the same as either returning a T or throwing a checked exceptions X and Y. I thought about doing this myself but if you use this everywhere then you essentially have reimplemented checked exceptions, with all the downsides we’re trying to avoid.

For example, the low level APIs often don’t have the context to handle failures thrown by functions they call, so they often just “rethrow” it, except in your solution rethrowing involves creating a new sealed result class which includes FailureDueToX, FailureDueToY and new ones thrown by other functions they call such as FailureDueToZ. This is worse than with checked exceptions, where documenting the exceptions that you rethrow was already annoying enough.

Just as with checked exceptions, every method between your low level exception generator and your high level exception handler needs to specify the exception in their API.

(Disclaimer: I’m still trying to work out what the best practise is here, so I can be convinced. I’m just relaying the criticisms of checked exceptions that I’ve learned about.)

I think there needs to be a very prominent piece of documentation telling developers the best practice here, covering all sorts of cases such as Java interop, implementing interfaces, passing exceptions up the chain, how to test exceptions, etc. A developer like me shouldn’t need to read pages and pages of philosophical discussion threads and blogs to be able to write good code. There should be one source of idiomatic Kotlin that says “if you are trying to do X, here’s how the exceptions should look”. This probably doesn’t exist yet precisely because this is a contentious issue, but I think the lack of official opinion is causing developers to diverge on their approach, which sounds pretty bad.

1 Like

There is some truth in what you are saying, but I think your thoughts are not complete. At least you did not consider syntax.

Working with return values in Kotlin generally yields more concise syntax than catching exceptions.

One could argue that Kotlin should get nicer and more fluent exception handing syntax. I would understand that, and even would like it. However I would understand also when the answer is that it is not worth improving something that can already be done in another way very nicely.

1 Like

The time has shown that checked exceptions in Java were a failed exercise in language design. No other modern language has them. Even in Java itself you’ll only find checked exceptions extensively used by legacy APIs. Newer APIs are overwhelmingly designed without checked exceptions. Java is working on adding support for algebraic data types which will make checked-exception-less alternatives more appealing even for Java developers.

To give a definite answer to the topic starter’s question on “could Kotlin have checked exceptions” the answer is no. Kotlin will not have checked exceptions in Java sense. They don’t work in a functionally-oriented language. However, Kotlin lives in the JVM ecosystem where people still have to regularly use legacy JVM APIs that rely on checked exceptions, so we are looking at various approaches that would simplify Kotlin interoperability with checked exceptions. It does not mean we are looking to add Java-style checked exceptions to Kotlin proper. We are mostly looking at it from the standpoint of improving Java interop.

P.S. The full idea behind the concept of exception in Kotlin is explained in this story that I wrote a while ago: Kotlin and Exceptions. What are Kotlin Exceptions and how… | by Roman Elizarov | Medium

5 Likes

Beyond the fact that checked exceptions don’t work with functional code there is another serious drawback to exceptions in general. That is the problem of writing exception-safe code. This is certainly possible, but not in the least straightforward. The problem is that a function call that throws an exception should not change the state of the object it was called upon (even though that was the purpose of the function). This is generally possible, but hard.

it seems like checked exceptions are cool again:

looks like complete craziness to me
but still, pretty interesting

Java lives over 20 years with this exception concept.
We will see how long modern computer languages will survive.

The subtle implication that checked exceptions contributed to Java living over 20 years is a bold statement to make.

3 Likes

You are perfectly right. I find it is a bold statement that “modern languages” are improved while not having the checked exception handling. My answer referres to the bold statement of elizarov:

elizarov
The time has shown that checked exceptions in Java were a failed exercise in language design. No other modern language has them.

But keep calm, we can talk some years later about the future of java an kotlin.

FWIW, my experience is that checked exceptions work very well for general coding in Java.⠀They don’t work so well around lambdas, nor the boundaries between modules or layers of abstraction; but they’re really good for forcing you to think about what’s likely to go wrong, and handle it one way or another.

Conversely, I’ve had Kotlin code fail in production because it wasn’t clear enough what exceptions could be thrown, and I missed one…

In some ways it’s strange that Kotlin, which in many other ways is stricter than Java and prevents many classes of error (e.g. around nulls, promotions, and variance) is looser with exceptions and provides neither errors nor warnings about bugs that Java would catch.

As I’ve mentioned upthread, I think a useful compromise would be exception inference: having the compiler automatically infer a throws clause for each function.⠀That would require no changes to existing code, and be no more verbose, but would let you easily see what exceptions were possible at any point (and interoperate better with Java).⠀After all, Kotlin infers many other things to save you typing them; why not exceptions?

I had production app fail, because Google removed the checked sql-exceptions in their Java-API. Even if my code was perfectly valid. It took a lot of time to figure out that some android versions are closing open database connections sometimes.

After wrapping each sql-call with checked exceptions, the failure was exactly reproducable in the next production release (some tiny percent of the users).

Tossing my two cents in here: getting rid of checked exceptions in my opinion was one of the best design decisions made for Kotlin. I’m working in the industry for 20 years, the majority of those years was spend on large-scale, multi-tier enterprise Java applications. And since day one I remember the “exception argument” being a thing. Having been a fan of checked exceptions once, here is how I personally see things as of today:

Pro Checked Exceptions:

  • Exceptional cases are an explicit, publicly documented part of your interfaces: clients know what error situations are to be expected, and are forced to either handle those situations or pass the errors up the call stack. This (in theory) is nice from an API design perspective: after all, errors are part of every API.

Contra Checked Exceptions:

  • I can count the situations I had to explicitly handle a given exception in a very specific way (that was different from how I handled all other exceptions) in all my years of work on one, maybe two hands. In those very, very few situations checked exceptions can be helpful, yes. Most of the times though it was either “log this error and continue” or “pass this error on, can’t recover from it anyways”.
  • In my first company we used checked exceptions extensively, both “system” exceptions provided by the JDK (IOException, SQLException etc.) and custom checked exceptions that denoted specific application error situations. In every non-trivial application this makes your application code look like this: List<MyBean> doSomething() throws IOException, SQLException, MyException1, MyException2, ... Or, after you’ve added the tenth exception to your throws clause, either this: List<MyBean> doSomething() throws Exception (aka “something can go wrong here, and I want you to know about it”) or this: List<MyBean> doSomething() throws RuntimeException (aka “something can go wrong here”). The latter is kind of what Kotlin does.
  • Going back to the initial example in my previous point (the long throws clause): if used like this you also introduce API bleed to your application. Suddenly the business logic and/or the client is aware you are using SQL for persistence on your backend (SQLException and its descendants). Of course this can be prevented by being cautious and wrapping exceptions at the appropriate service boundaries, which brings me to my final point:
  • In large scale applications there usually are network boundaries between application/service layers (e.g. micro-services, SOA etc.). This is especially true if the application architecture consists of heterogeneous parts, e.g. a C++ Client accessing a Java web-service. What do we do in such situations? Well, we return proper error responses, preferably with an established error code system (HTTP codes, custom application error codes etc.). The same logic can apply to what happens inside a single service/layer, but in most of our use cases errors are not recoverable anyways, so we throw our custom runtime exception and be done with it. A global exception handler (probably installed at the service boundary) takes care of the exception and renders it as an error response.

To summarize, there are arguments for checked exceptions, but I think there are even more against them. Even the Java and many framework designers seem to agree, as of today important system libraries (JPA, streams API) and projects like Spring or Hibernate do not use checked exceptions any longer. Ultimately it seems to be a matter of personal taste and choice, for those of us that really do need them Java is probably the language to stay with.

2 Likes

Interesting here is that for newer versions of C++ they have deprecated checked exceptions with one exception, you can still specify noexcept to specify that something does not throw. Looking at what the C++ people are saying about solving the “error handling” issue, it seems that the most promising solution is basically some sort of monad approach (like kotlin’s Result type (only for coroutines for now)). It makes it easy to both write code that “ignores” exceptions, as well as allows you to actually handle exceptions where you need to, without having: incredible amounts of boilerplate, writing exception-safe code.

I would also want to add an important point here, writing exception-safe code is really really hard because you don’t get to control your control flow (not that monads make it entirely easy to do).

1 Like