Live data from Hacker News

The Trouble with Checked Exceptions (2003)

artima.com

21–30 of 35 posts

Re: The Trouble with Checked Exceptions (2003)

#21
> Adding a new exception to a throws clause in a new version breaks client code.

Altering the return-type of a new version also breaks client code. Both return-types and thrown-types are kinds of results from your code, and both should be treated with similar rigor.

The main difference is that programmers are forced to get one of them right early on (in order to get their demo working) while the other is often ignored until late in development when you start needing to handle errors.

Conversely, always using unchecked exceptions "because it's too much work" is the same tradeoff as writing like writing methods that promise to return Object. Sure, it frees you from needing to plan, but it also makes it much harder for you (or another developer) to plan the next thing, leading to a snowball effect.

Re: The Trouble with Checked Exceptions (2003)

#22
> You don't want a program where in 100 different places you handle exceptions and pop up error dialogs. What if you want to change the way you put up that dialog box? That's just terrible. The exception handling should be centralized, and you should just protect yourself as the exceptions propagate out to the handler.

That's assuming a definition of an exception as a generic error you can do nothing about except tell it to the user and maybe retry the operation or kill the program. But in practice exceptions are used for more than that, they're a sort of union type where a method can return a result or an error, but because Java didn't have union types exceptions were used to signal that. For example parseInt will throw a NumberFormatException if it can't parse the string you pass as argument (NumberFormatException is unchecked but it really should be checked).

I think it's the coexistence of these 2 different ways things can go wrong under the same term that is the root of the confusion around Exceptions. The first way is using an exception as a normal outcome of a method, like parseInt above. Using the word "exception" for that is wrong, it is not exceptional for parseInt to return an error if you pass to it some string that does not contain a number. It is expected and will happen every time. The type system should be able to represent that with an union type or Either or something of the sort instead.

The second way things can go wrong is when the program is put in contact with the outside world, and the outside world is messy so things will happen that are not what you expect. You try to open a file but it cannot be found any more, you try to allocate some memory but the operating system refuses to do so, some network call is taking too long and so on. Those will have to be dealt with case by case, sometimes you can do something about it, sometimes not. I know programmers don't like that very much but I don't know what can be done about it, it's just the nature of dealing with all the edge cases.

Re: The Trouble with Checked Exceptions (2003)

#23
post #15

Earlier quoted context omitted.

Yes, this is the basic benefit of typed languages. I would not want to refactor a 20 year old code base without type safety - I do want to know what's being returned. I also want my tools to know what's being returned, as well as my compiler.

But in languages supporting this you do know that it's either A or B and you can use match expressions to deal with both cases. Usually these are the languages with more focus on type safety, like OCaml, Haskell and Rust.

To be fair, in OCaml, Haskell or Rust the type "A | B" also had to be declared beforehand.

Re: The Trouble with Checked Exceptions (2003)

#24
post #23
post #15

Earlier quoted context omitted.

But in languages supporting this you do know that it's either A or B and you can use match expressions to deal with both cases. Usually these are the languages with more focus on type safety, like OCaml, Haskell and Rust.

To be fair, in OCaml, Haskell or Rust the type "A | B" also had to be declared beforehand.

[deleted]

Re: The Trouble with Checked Exceptions (2003)

#25

Earlier quoted context omitted.

> what programmers actually* do with checked exceptions* If the only trade-off considered is 'writing "gobbledy gunk" to handle exceptions poorly' vs 'not handling them at all' then, of course, checked exceptions will look bad. If the trade-off is whether the compiler will be able to tell me that I'm not handling an exception, well, I want the compiler to help me out. People writing low-consequence code can sprinkle…

The crucial difference with Rust's Result (I don't know Zig well enough) is that Result isn't about control flow. Exceptions unavoidably and deliberately change control flow. Suppose you're in a loop twiddling zarks. In Rust, twiddling a zark gives you a Result and if the Result isn't Ok then that's an error. But Rust doesn't care what - if anything - you do with the error, it just won't allow you to pretend the erro…

Which is the imo correct approach. Instead of unwrapping and rewrapping the exception at the closest level, I want to handle most exceptions in a common place. Eg, in case of a web server that place would give a proper error page to the user whenever an unhandled exception happened in his/her request.

Also, Java’s exceptions are pretty much the exact same sum type as in Rust, just with added syntactic sugar. A method with a throws SomeException signature will have a type of Result | Error, that gets autounwrapped for you, with the added benefit of giving you a stacktrace by default.

Re: The Trouble with Checked Exceptions (2003)

#26
post #22

> You don't want a program where in 100 different places you handle exceptions and pop up error dialogs. What if you want to change the way you put up that dialog box? That's just terrible. The exception handling should be centralized, and you should just protect yourself as the exceptions propagate out to the handler. That's assuming a definition of an exception as a generic error you can do nothing about except tel…

Exceptions are exactly the same thing as sum types, there really is no difference between them on a conceptual level. They just come with additional stack traces and good, no boilerplate syntactic sugar in Java.

Re: The Trouble with Checked Exceptions (2003)

#27
post #6

I like James Iry’s take on checked exceptions here[1] which basically boils down to this: > The throws clause is the only point in the entire Java language that allows union types. You can tack “throws A,B,C” onto a method signature meaning it might throw A or B or C, but outside of the throws clause you cannot say “type A or B or C” in Java. In languages with better support for ad hoc union types, I think both the n…

It is pretty expensive performance vise

Depends on how it is compiled. There’s no reason in principle the two can’t have the same performance, it’s just a difference in ergonomics.

Re: The Trouble with Checked Exceptions (2003)

#28
post #23
post #15

Earlier quoted context omitted.

But in languages supporting this you do know that it's either A or B and you can use match expressions to deal with both cases. Usually these are the languages with more focus on type safety, like OCaml, Haskell and Rust.

To be fair, in OCaml, Haskell or Rust the type "A | B" also had to be declared beforehand.

Yes, but it doesn't really change the way you could handle it, and what I wanted to point out is that it actually helps with type safety, enabling you to create total functions.

Re: The Trouble with Checked Exceptions (2003)

#29
post #25

Earlier quoted context omitted.

The crucial difference with Rust's Result (I don't know Zig well enough) is that Result isn't about control flow. Exceptions unavoidably and deliberately change control flow. Suppose you're in a loop twiddling zarks. In Rust, twiddling a zark gives you a Result and if the Result isn't Ok then that's an error. But Rust doesn't care what - if anything - you do with the error, it just won't allow you to pretend the erro…

Which is the imo correct approach. Instead of unwrapping and rewrapping the exception at the closest level, I want to handle most exceptions in a common place. Eg, in case of a web server that place would give a proper error page to the user whenever an unhandled exception happened in his/her request. Also, Java’s exceptions are pretty much the exact same sum type as in Rust, just with added syntactic sugar. A method…

> Java’s exceptions are pretty much the exact same sum type as in Rust, just with added syntactic sugar.

Except Java doesn’t actually return a result object that can be assigned to a variable by default.

Re: The Trouble with Checked Exceptions (2003)

#30
post #25

Earlier quoted context omitted.

Which is the imo correct approach. Instead of unwrapping and rewrapping the exception at the closest level, I want to handle most exceptions in a common place. Eg, in case of a web server that place would give a proper error page to the user whenever an unhandled exception happened in his/her request. Also, Java’s exceptions are pretty much the exact same sum type as in Rust, just with added syntactic sugar. A method…

> Java’s exceptions are pretty much the exact same sum type as in Rust, just with added syntactic sugar. Except Java doesn’t actually return a result object that can be assigned to a variable by default.

And in case of exceptions, why would that be useful?

(For other things, I agree that sum types are cool, and fortunately are supported in Java through sealed classes)

Post reply on HN