Comment by drivebyhooting
18 hours ago
I think my opinion will be even more maligned: I like Java-style checked exceptions. It forces awareness of the error and a clean way to propagate it.
18 hours ago
I think my opinion will be even more maligned: I like Java-style checked exceptions. It forces awareness of the error and a clean way to propagate it.
People advocate for Go's error handling because it forces you to deal with errors.
But in the cases I do want to catch a specific error, the signature only tells me that a function returns an error, not which type. So I do feel that returning (int, error) is strictly worse than Java's checked exceptions if you care about errors.
This is elegantly solved with sum types. (And arguably needs sub typing.)
If instead of just returning (int, error) the function would return (int, parseError | outOfBoundsError) you would know that the parser function can fail on reading a number at all and on the number being to big/small to fit the type and handle then accordingly.
Saliently, Java in a sense has supported sum types in the throws declaration and the subsequent catch statements forever. Unfortunately it has not landed in other places where you can use types so you cannot use it for returning errors. Scala 3 supports this but has tiny adoption it seems.
That's helped by errors.Unwrap() and errors.Is(), though you do need to build and structure your errors appropriately.
It's helped, but that's runtime behaviour. The compiler can't help you with questions like "you didn't handle certain errors" or "the error you're trying to check can never occur".
Nor does that help with documentation, I'm guessing if I read a file then it might raise the error that the file does not exist. But what exactly is the technical type of that error? You have to search through the function's implementation, and functions that function calls, etc., to find out.
And it doesn't help with refactoring. If you create new.FileNotFoundError and change your function to return it, existing code which checks for old.FileNotFoundError will start to silently fail.
I agree; in practice, probably only the public error types, though. If it can return fmt.Errorf("…%w…") I probably only need the type of the wrapped error, not whatever type the implementation uses.
I liked Nim’s take on checked exceptions personally, was quite lovely
The thing that most annoys me in Java in that area is when a dependency throws an unchecked error that wasn’t even documented.
Thanks so much for that! Now I have no choice but to be reactive when something fails…