Hacker News new | ask | show | jobs
by simias 1747 days ago
Rust solves this issue by having a ? operator to bubble up Errors. Before that there was the try! macro with the same semantics. That cuts the boilerplate to a minimum while having a well defined and explicit control flow.

I agree that if you had to write the ifs by hand it would be a pita. Looking at you, Go.

2 comments

In the end that is equivalent to bubble up exceptions when thy are of the unchecked type.
I don't think that's true because if I understand it correctly, the return type of functions which can possibly throw unchecked exceptions would not indicate that they can throw or what they can throw. On the other hand, with the "errors as values" approach (including "bubbling up" operators like `?`), you can tell exactly from the function's return type if an error can be returned and if so what the set of possible errors is.

Did you maybe mean "the checked type"? In that case I still think it's not equivalent because at least in Rust you can automatically transform the error while it bubbles up, while I don't know of a language with checked exceptions that lets you transform the exception while unwinding (short of manually catching, transforming, and re-throwing).

> the return type of functions which can possibly throw unchecked exceptions would not indicate that they can throw or what they can throw

As far as I know, that's how Java's "throws" method signature works, which has been widely regarded as a mistake.

Throws is for checked exceptions. Unchecked are not listed in the throws list.
It's actually even worse: you can include both checked and unchecked exceptions in the `throws` clause. The compiler will only enforce handling of the checked exceptions included. Unchecked exceptions listed in the `throws` clause serve as an optional hint to others. Note that you can erroneously include any exceptions you like in the `throws` clause, even ones that are never thrown from the method. These quirks are often covered by static analysis.
The key difference for me is that you have to explicitly handle Results somehow, you can't just pretend that the function is infallible and hope that something up-stack is going to deal with all the failure modes. Also while you can have generic Error types it's generally frowned upon for libraries which are encouraged to provide meaningful error types that can be used to decide how a problem should be dealt with. Coupled with Rust's pattern matching it makes for concise and expressive error handling in my experience.
One could solve the problem further and more conveniently by doing the bubble up implicitly at every call and just re-invent exceptions.