Live data from Hacker News

A guide to error handling in Rust

nrc.github.io

11–20 of 76 posts

Re: A guide to error handling in Rust

#11

Too bad Rust doesn't have union types (aka adhoc / anonymous unions) yet. Without them, using typed errors is very clumsy. Optimally, you would write the following code: fn foo(r1: Result , r: Result ) { let i1 = r1?; let i2 = r2?; // ... } and Rust would infer the return type to be Result without having to do any extra definitions or conversions.

Anonymous sum types are something I want for error handling as well. In practice though I'm not sure it would really make my life that much better.

Not sum types. Those are union types. The difference is important, since if you work with two results (or two functions that return results) that use the same error-type you most often don't want to end up with a tuple of two times the same error but simply A.

Of course, if you care about which error is from which function, you can always easily do that by wrapping them into a sumtype, but in practice this is a rather rare use-case in application code at least.

Re: A guide to error handling in Rust

#12

Too bad Rust doesn't have union types (aka adhoc / anonymous unions) yet. Without them, using typed errors is very clumsy. Optimally, you would write the following code: fn foo(r1: Result , r: Result ) { let i1 = r1?; let i2 = r2?; // ... } and Rust would infer the return type to be Result without having to do any extra definitions or conversions.

The library ecosystem does fill that gap somewhat with crates like anyhow [1] which also allow you to add context to the errors you return.

1. https://docs.rs/anyhow/latest/anyhow/

Re: A guide to error handling in Rust

#13

Too bad Rust doesn't have union types (aka adhoc / anonymous unions) yet. Without them, using typed errors is very clumsy. Optimally, you would write the following code: fn foo(r1: Result , r: Result ) { let i1 = r1?; let i2 = r2?; // ... } and Rust would infer the return type to be Result without having to do any extra definitions or conversions.

The library ecosystem does fill that gap somewhat with crates like anyhow [1] which also allow you to add context to the errors you return. 1. https://docs.rs/anyhow/latest/anyhow/

Unfortunately this does not solve the problem. If you use this, you lose typesafety and the documentation you get through the (inferred) types. I.e. with union types you can see at a glance in your IDE which types of errors a function can return - this is too valuable to give it up.

Re: A guide to error handling in Rust

#15
post #14

It is perhaps too verbose by default, as indicated by popularity of thiserror and anyhow crates.

Many of the features of such crates are making their way to the standard library, so things will definitely improve. Figuring out what is best has taken some time and Rust has not wanted to prematurely commit.

Re: A guide to error handling in Rust

#16

Too bad Rust doesn't have union types (aka adhoc / anonymous unions) yet. Without them, using typed errors is very clumsy. Optimally, you would write the following code: fn foo(r1: Result , r: Result ) { let i1 = r1?; let i2 = r2?; // ... } and Rust would infer the return type to be Result without having to do any extra definitions or conversions.

For anyone interested in what this would look like in Rust now, there's two ways. For libraries, people tend to recommend the thiserror crate. Code sample[0]:

    #[derive(thiserror::Error, Debug)]
    enum Error {
        #[error("One")]
        One(#[from] Error1),
        #[error("Two")]
        Two(#[from] Error2),
    }

    fn foo(r1: Result, r2: Result) -> Result {
        let i1 = r1?;
        let i2 = r2?;
        // ...
    }
Whereas for binaries, people usually recommend anyhow. Code sample[1]:

    fn foo(r1: Result, r2: Result) -> anyhow::Result {
        let i1 = r1?;
        let i2 = r2?;
        // ...
    }
[0]: https://play.rust-lang.org/?version=stable&mode=debug&editio... [1]: https://play.rust-lang.org/?version=stable&mode=debug&editio...

Re: A guide to error handling in Rust

#17

Too bad Rust doesn't have union types (aka adhoc / anonymous unions) yet. Without them, using typed errors is very clumsy. Optimally, you would write the following code: fn foo(r1: Result , r: Result ) { let i1 = r1?; let i2 = r2?; // ... } and Rust would infer the return type to be Result without having to do any extra definitions or conversions.

Even if the "Ad hoc union" becomes a thing in Rust, you are not likely to get inference of return types.

The return type is part of the function signature and Rust deliberately doesn't infer signatures, in languages with "too much" inference it's impractical for the human programmer to keep track of types because it's all inferred, this has started to be a problem in C++ as more and more things are auto. Rust has some very sophisticated inference inside a function (including partial inference and inferring types from how they're later used), but none for the signature.

Re: A guide to error handling in Rust

#18

Earlier quoted context omitted.

The library ecosystem does fill that gap somewhat with crates like anyhow [1] which also allow you to add context to the errors you return. 1. https://docs.rs/anyhow/latest/anyhow/

Unfortunately this does not solve the problem. If you use this, you lose typesafety and the documentation you get through the (inferred) types. I.e. with union types you can see at a glance in your IDE which types of errors a function can return - this is too valuable to give it up.

You don't really loose type safety, rather it moves to runtime. Downcasting an anyhow error to the concrete internal type is certainly possible and won't panic in my experience.

Re: A guide to error handling in Rust

#19

Earlier quoted context omitted.

Anonymous sum types are something I want for error handling as well. In practice though I'm not sure it would really make my life that much better.

Not sum types. Those are union types. The difference is important, since if you work with two results (or two functions that return results) that use the same error-type you most often don't want to end up with a tuple of two times the same error but simply A . Of course, if you care about which error is from which function, you can always easily do that by wrapping them into a sumtype, but in practice this is a rath…

Unions don't have a discriminant. Anonymous Sum types have a discriminant, you just can't name it. Unions in Rust are unsafe because you can't tell what the underlying value will be.

Re: A guide to error handling in Rust

#20

Too bad Rust doesn't have union types (aka adhoc / anonymous unions) yet. Without them, using typed errors is very clumsy. Optimally, you would write the following code: fn foo(r1: Result , r: Result ) { let i1 = r1?; let i2 = r2?; // ... } and Rust would infer the return type to be Result without having to do any extra definitions or conversions.

„Yet”? Are there any plans to add them?
Post reply on HN