Live data from Hacker News

Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

msirringhaus.github.io

71–80 of 204 posts

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#71
post #44
post #40

Earlier quoted context omitted.

Why not `thiserror` for executables as well? It happened to me a few times that I started to write an executable program, but then realized I want to embed its functionality in a library. Converting from `anyhow` to `thiserror` at that stage would be extra work that can be avoided.

I guess this depends somewhat on the situation. If the design is pretty clear upfront with a part that can be implemented as a core library, I'd make the library use `thiserror` from the beginning. However, if it's not really clear and I have to start with exploratory coding, then keeping track of error types that may come and go feels like unnecessary overhead, when I can just use `anyhow`. But! To each their own!

I've used `thiserror` with great success in small side web projects since you can create a new enum of Errors that can be converted from a class of underling library errors. Then, inside of my regular application code, I sprinkle in `anyhow` to make my life easier.

For example, if I wanted to say, return a 500 status code for all diesel database errors, I can convert the diesel error into my custom error type, then throw it back up the stack using `anyhow`. This works _really_ well in conjunction with Rocket's Responder impl.

EDIT: This is pretty close to what TFA is saying as well, I should have read more in the article, heh

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#72
post #68

Earlier quoted context omitted.

> I am designing my program for a particular use, by definition. No; this is bad engineering. You write a program to conform to a specification. In the specification, it says what must happen when a file does not exist, what must happen when there's not enough memory, etc. Then you write the specified behavior into code.

The specification and boundary conditions directly comes from an analysis of the expected usage. Except for some all-purpose libraries you don't develop in a vacuum (assuming you don't work for Roomba).

But design and coding are different steps, best kept separate. When you are designing, I agree with you, the expected usage is very important. But in the design step the particular language mechanism for dealing with conditions does not matter. Once you get a specification to program to, all input conditions can be treated as equal. That is, unless you need to optimize heavily by biasing your execution path for a certain percentage of input cases (which should be clearly described in the specification).

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#73

Error handling has been wrong since the beginning, and has continued to be wrong ever since. First, we had error codes. Except these were wrong because people forget all the time to check them. Then we had exceptions, which solved the problem of people forgetting to check by crashing the app. Then the Java team got the bright idea to have checked exceptions, which at first helped to mitigate crashes from uncaught exc…

Would you put the Erlang/Elixir error handling in the "catch Throwable" camp?

Because in this case, the error handling is done in a different process altogether (supervisor).

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#74
post #67

Earlier quoted context omitted.

> Languages need to offer control flow mechanisms that allow you to separate common cases in the code from the uncommon cases. Strong disagree with this sentence. It represents the exact opposite of what I deem a good programming language. The difference between "common" and "uncommon" execution paths must be of no bearing. Moreover, this "likeliness" depends on the (unknown to the programmer) usage that the program…

Strongly disagree with your disagreement. Programming features help you organize your code. The fact that you actually have a robust software or not with what the language offers is another problem. When people say "errors are values", I say: yes, but they are a special kind of values. The same way floats are special (signaling NaNs), or that bools are special (short-circuit operators). It is great to have special su…

Thanks for explaining so clearly your view. I'm totally biased towards programming practices that make execution paths 100% explicit and local. Yet it is interesting to understand the other point of view (and somewhat liberating, to be honest).

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#75
post #70

Error handling has been wrong since the beginning, and has continued to be wrong ever since. First, we had error codes. Except these were wrong because people forget all the time to check them. Then we had exceptions, which solved the problem of people forgetting to check by crashing the app. Then the Java team got the bright idea to have checked exceptions, which at first helped to mitigate crashes from uncaught exc…

Are you familiar with Zig's error handling? Except for the fact that errors cannot contain payloads, it is, imo, perfect.

it has the same issues. You can always discard errors with `catch unreachable` for example.

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#76
post #68

Earlier quoted context omitted.

The specification and boundary conditions directly comes from an analysis of the expected usage. Except for some all-purpose libraries you don't develop in a vacuum (assuming you don't work for Roomba).

But design and coding are different steps, best kept separate. When you are designing, I agree with you, the expected usage is very important. But in the design step the particular language mechanism for dealing with conditions does not matter. Once you get a specification to program to, all input conditions can be treated as equal. That is, unless you need to optimize heavily by biasing your execution path for a cer…

> Once you get a specification to program to, all input conditions can be treated as equal.

And if the spec says "try downloading the file 3 times at 5 seconds interval; if that fails, give up the update", I am free to implement it however I want (?) unless I missing your point.

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#77
post #67

Earlier quoted context omitted.

Strongly disagree with your disagreement. Programming features help you organize your code. The fact that you actually have a robust software or not with what the language offers is another problem. When people say "errors are values", I say: yes, but they are a special kind of values. The same way floats are special (signaling NaNs), or that bools are special (short-circuit operators). It is great to have special su…

Thanks for explaining so clearly your view. I'm totally biased towards programming practices that make execution paths 100% explicit and local. Yet it is interesting to understand the other point of view (and somewhat liberating, to be honest).

Thanks for the kind remarks (we are all biased :))

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#78

Earlier quoted context omitted.

In terms of control flow, this: try { someCall(); } catch (ErrorICanHandle err) { //handle } perfectly equivalent to this: err = someCall(); if canHandle(err) { //do something } else { return err } I don't see why so many people think exceptions make code harder to analyze. In my opinion, it is errors themselves that make code hard to analyze, regardless of implementation strategy. The only difference between excepti…

I mean, Go's error handling is one of the worst implementations of the "error code" idea, so it is a bit unfair to disregard the idea just because one particular implementation is bad. You should try Rust or Swift, at least the error handling part, to fully appreciate what a good error code implementation could be.

I'd love to when I get a chance. I did see that Rust seems to favor a ? macro that seems to make error codes behave essentially like exceptions, so I am curious to try it out at some point and see if that ends up being any different from exceptions in practice.

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#79

For the mostpart, Rust error handling is okay. What really rustles my jimmies, however, is the often mandatory indentation because of a lack of an inverse "if let". I prefer to bail out of a block if a condition is NOT met, rather than execute another nested block if it IS met. Rust makes that harder than it should be. It's good code hygiene in every other language, and Rust makes it painful in places. I've even been…

Yeah, this is irritating... one workaround for this is to do:

(in the context of walking a tree...):

    fn get_depth(root_opt: &Option>) -> usize {
        let root = match root_opt {
            Some(root) => root,
            None => return 0;
        };

        1 + std::cmp::max(get_depth(root.borrow().left), get_depth(root.borrow().right))
    }

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#80
post #75
post #70

Earlier quoted context omitted.

Are you familiar with Zig's error handling? Except for the fact that errors cannot contain payloads, it is, imo, perfect.

it has the same issues. You can always discard errors with `catch unreachable` for example.

True, but it's very explicit, and easy to audit for.
Post reply on HN