News for hackers. Stuff that matters.
Re:Rating 26 years of Java changes by rectang on Saturday October 11, 2025 @10:21PM (#45554589)
Idealized checked exceptions are isomorphic to Rust's `Result` type, which is great.

Java's implementation of checked exceptions has some issues, though.

* "Invisible control flow", where you can't tell from the call site whether or not a call might throw (you need to check the signature, which is off in some other file, or perhaps visible in an IDE if you hover).

* Java has both checked and unchecked exceptions, but they go through the same try-catch mechanism, failing to make a clean distinction between recoverable errors and unrecoverable bugs. (In e.g. Rust and Go, recoverable errors go through return values but unrecoverable errors go through panics.)

In the end, Java's exception design simultaneously requires a lot of effort to comply with, but makes it difficult to understand when you've successfully locked things down.

Re:Rating 26 years of Java changes by samus on Sunday October 12, 2025 @02:03AM (#45555666)
> * "Invisible control flow", where you can't tell from the call site whether or not a call might throw (you need to check the signature, which is off in some other file, or perhaps visible in an IDE if you hover).

Never found this this to be a problem. It is really common to all implementations of exceptions, not just checked ones. And when you write code the compiler will yell at you. In monadic code,

Re:Rating 26 years of Java changes by rectang on Sunday October 12, 2025 @11:47AM (#45559062)
Invisible control flow is common to all implementations of unchecked exceptions (Java, C#, C++, Python, Ruby, etc). It means that any code, anywhere, at any time, can throw an exception.

People are used to that, and one common strategy is to not worry too much about exceptions and then wrap a big `try` block around everything near the outer boundary of your code. It’s good enough for many purposes and yields a high initial development velocity, but is comparatively fragile.

With Languages like Rust, Go, and Swift, only unrecoverable errors trigger the panic mechanism. Every call site where a recoverable error may occur is identifiable — in Rust via Result, `unwrap()`, the `?` operator, etc, in Go via returned Err (though unlike Rust you can discard them silently), and in Swift via the `try` operator.

You can still develop quickly by just unwrapping every Result, but unlike languages with invisible control flow, you can easily audit the codebase and go back to harden every site where a recoverable error may occur — yielding a level of robustness which is difficult to achieve in languages with unchecked exceptions.

Re:Rating 26 years of Java changes by peterashford on Sunday October 12, 2025 @08:32PM (#45563480)
As someone who uses Go professionally now and Java previously, I disagree with your take on unchecked exceptions. I think that Panics and errors is worse than just using exceptions. I think the latter is just simpler to deal with. At the end of the day, when error handling is complex, its complex with either approach - you have to think carefully about what's happening in the problem domain and come up with a robust solution. What the code level adds is complexity: the Go approach is more complex and consequently worse. I love Go coding but its error handling sucks and I would gladly have the Java approach instead.
Re:Rating 26 years of Java changes by vips7L on Sunday October 12, 2025 @09:21AM (#45558064)
Do you not have to check the signature to see what a function can return when using Results? It’s off in another file too.

> failing to make a clean distinction between recoverable errors and unrecoverable bugs

Recoverability is context specific. One persons panic may just be another error case for someone else. I think this is one thing that programmers miss when talking about this topic. It is really up to the caller of your function if something should panic. You can’t make that decision for them.

Re:Rating 26 years of Java changes by rectang on Sunday October 12, 2025 @12:06PM (#45559225)
The point of avoiding invisible control flow is not to identify the type of the error, but to identify all locations in the code where recoverable errors may occur.

> One persons panic may just be another error case for someone else.

We can make a strong distinction between recoverable errors (e.g. this I/O operation may fail) versus unrecoverable errors that may leave the process in an unsound state, such as divide-by-zero or out-of-bounds array access[1].

There are some problem domains where even unrecoverable errors are not allowable, and programmers in those domains have to grapple with the panic mechanism.

But for the rest of us, it is useful to be able to distinguish between recoverable and unrecoverable errors — and to know how we have handled all possible sites which could result in recoverable errors.

[1] Joe Duffy explains it well: https://joeduffyblog.com/2016/02/07/the-error-model/#bugs-ar...