3

Despite checked exceptions being generally bad practice and anti-pattern, I find one feature very useful: having list of checked exceptions part of function signature.

Checked exceptions are "business exceptions", something that requires from the source code or user to do something to recover and continue normal functioning. Having possible checked exceptions as a method signature gives me compile time type safety, and gives me list of possible outcomes after calling a function.

I struggle to find a proper alternative to this. Generally, the proposed alternative is using Either, or Try, or Result, or some similar class/structure that may keep either happy path result, or an Exception instance that marks a business exception that happened. But these solutions does not help ne knowing what are possible exceptions that I should expect, so that I can choose how to react in which situation.

There is an option to list possible exceptions in the javadoc/kdoc, but it may not be truth, only the code is truth, after all and I want my type system and compile time safety.

Since these exceptions are not really thrown, so instead of them we could use enums, each function call having it's own enum specify possible alternative scenario outcomes, but that seems little bit overwhelming, and I don't see such thing being proposed.

Is there any widely accepted solution to this problem, that is according to some of the accepted best practices?

4
  • 4
    Exceptions are, by definition, exceptions to the explicit expectations and flow of your code. If exception types are explicitly mentioned and to be expected from your strong typing, they cease to be exceptions and become result objects instead.
    – Flater
    May 15, 2022 at 16:48
  • @Flater All of that is understood, and my question is whether there is some "industry standard" of handling such situations. There is a general concensus about why checked exceptions are bad thing for handling business "exceptions" and alternative scenarios, but I don't see any widely accepted pattern or alternative to checked exceptions.
    – SadClown
    May 16, 2022 at 10:08
  • 1
    I agree with your core observation, but what I was trying to point out (but should have done more explicitly) is that your question depends on whether you count a result object as a valid alternative. Not so much that it's a valid approach in and of itself (which it is), but whether you still consider it as an implementation of a "checked exception", or something separate which fills a similar (but not precisely equal) niche.
    – Flater
    May 16, 2022 at 10:52
  • Yeah, I see them as valid alternative result. That was kinda whole point of checked exceptions - to get "alternative" or "unhappy scenarios" results
    – SadClown
    May 17, 2022 at 8:51

2 Answers 2

4

First, a lot of programmers don't realize that being forced to handle specific exceptions is not the bad part of checked exceptions. The main idea is a good one. The problem is that you have to either handle or declare that you rethrow at every step in the call stack. This can lead to situations, such as with higher-order functions, where you end up having to temporarily wrap a checked exception in an unchecked exception.

I am aware of two good solutions to this problem, although I don't know about "widely accepted."

The first is the experimental Scala CanThrow Capability. It does this by sort of reversing the dynamic. The CanThrow capability essentially grants "permission" down the stack for a function to throw a specific exception. That page is definitely worth reading to get the details, but in a nutshell, it allows a checked exception to skip a step in the call stack, but statically verify that it is indeed eventually handled.

The second solution is the monadic IO that you already mentioned.

But these solutions does not help me knowing what are possible exceptions that I should expect

They do if you are specific about the exceptions being returned. Sure, an Either[Exception, String] isn't very precise, but you generally would be more specific, like Either[FileNotFoundException, String]. With sum types, this is even more flexible, like Either[FileNotFoundException | JsonParseException, String]. Or you can create your own app-specific exception hierarchy. It's relatively common to see something like an Either[HttpError, Json] to make sure a response is encoded appropriately.

1
  • Using particular language or library constructs is pretty limiting factor. I was more asking about something that can be used straight forward using common language constructs, at least common ones in JVM languages. Moreover, I do have some ideas how to do it, and I am using them, but I wander if there is an industry standard, something widely accepted a s a solution for this. I am surprised that there is a general consensus about why checked exceptions are bad, but there is no generally accepted alternative to them.
    – SadClown
    May 16, 2022 at 10:12
1

I think you have to look again at what "exceptions are meant to be". If you think of exceptions as "exceptional things which cannot be handled" then the idea of returning them as possible results of a method or function becomes non-sensical. The whole idea of throwing exceptions is to give a way of returning results outside of the return value.

So in the "try again" example where we throw a checked exception so the calling code has to decide whether to reattempt the call or give up, the function itself could implement the "try again" logic and take a "number of retries" argument.

Throwing a "DoYouWantToTryAgain" exception and forcing the calling code to implement that logic doesn't make sense. It admits that retries are needed, but doesn't handle them

Neither does expanding your return type to allow the same thing.

Throwing a "ConnectionError" exception which forces no behaviour makes sense because its an unexpected circumstance which you don't want to waste time on writing code to remediate. Nor do you expect the calling code to have to remediate it.

The 'normal' way of dealing with "I need to return data that isn't in my return object" is to add code so you don't have to return that data. ie a retry handler or adjustable timeout vs alternate return types or extra meta data on return type.

Its just that its also normal programming, so not seen as a solution to any particular issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.