Live data from Hacker News

A guide to error handling in Rust

nrc.github.io

21–30 of 76 posts

Re: A guide to error handling in Rust

#21

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…

How would that work in a memory safe language? Rust does have (named) untagged unions already (using the `union` keyword), but they are unsafe to use because there is no way to know statically which of the possible variants a given value contains.

Re: A guide to error handling in Rust

#22
post #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?

There are not. I don't believe they've ever been thoroughly proposed.

Re: A guide to error handling in Rust

#23
post #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.

I like what the error handling achieves, it is actually readable way to understand the divergent control flow paths (and probably majority of code is read more than written), but I do not enjoy writing the initial boilerplate, so that's good to hear.

Re: A guide to error handling in Rust

#24
post #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.

If anyone's interested in helping to shape the future of Rust's built-in error-handling story, there's an error handling project group that's been doing great work recently, e.g. the major effort to move the Error trait into libcore ( https://github.com/rust-lang/project-error-handling/issues/3 ) and stabilizing std::backtrace. You can follow along or get involved via the #project-error-handling channel on the Rust zulip: https://rust-lang.zulipchat.com/

Re: A guide to error handling in Rust

#25

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 som…

I think it's the job of the IDE to make that work, but I agree, without IDE this can quickly become a problem.

Re: A guide to error handling in Rust

#26
post #18

Earlier quoted context omitted.

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.

"moves to runtime" exactly means to lose typesafety though.

Re: A guide to error handling in Rust

#27

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.

I know that this is a common wish, but anonymous sum types have pretty catastrophic impacts on type checking and lead to all sorts of bizarre corner cases like the following:

  let a = if cond {
    1 
  } else {
    1.0
  };
  
  a + 3
Now, the error would be pushed to the `+` operator because there isn't an `Add` for `f32 | u32`. Granted, this is a trivial example, and a programmer can easily see through it, but in general this can get very overwhelming and cause errors to leave their 'root cause'.

Re: A guide to error handling in Rust

#28

I feel like this document makes the Try operator (?) and its associated trait more mysterious than necessary. Most people probably won't need to implement Try, especially before it is stabilised, but it's not that much more complicated than say, AddAssign the trait which you implement to make the Add Assignment (+=) operator work on your type. The key trick of Try is that it converts something (by default an Option o…

TIL what ControlFlow is. This is super interesting and solves some problems I thought were impossible.

Error handling has gone from uber painful in 2018 to pretty decent in the latest editions.

Re: A guide to error handling in Rust

#29

Earlier quoted context omitted.

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…

How would that work in a memory safe language? Rust does have (named) untagged unions already (using the `union` keyword), but they are unsafe to use because there is no way to know statically which of the possible variants a given value contains.

You can obviously only call common methods or have to pattern match later and have a way to tell them apart. If you can't tell them apart, the compiler will tell you and you need to tag them somehow.

Re: A guide to error handling in Rust

#30
This glaring omission from this is the "enum idiom":

https://doc.rust-lang.org/std/convert/trait.From.html#exampl...

they talk about it here:

https://nrc.github.io/error-docs/error-design/error-type-des...

but including more than a snippet would go a long way to that "aha" moment I think. This was frustrating for me browsing this site. The author wrote 10 pages of docs, but nearly all the examples are like 5 line snippets of code. I think examples are equally important as the discussion itself. Rust itself suffers from the same problem:

https://github.com/rust-lang/book/issues/3348

Post reply on HN