Live data from Hacker News

A guide to error handling in Rust

nrc.github.io

71–76 of 76 posts

Re: A guide to error handling in Rust

#71

Earlier quoted context omitted.

> Now, the error would be pushed to the `+` operator because there isn't an `Add` for `f32 | u32`. Why not? It makes total sense for one to exist. This is something the language needs to deal with, not the programmer. But the programmer always sprinkle annotations so that errors can only reach so far.

I think the ramifications of `Add` (and friends) for union types is interesting, but I think we can imagine alternatives that are clearly mistakes and so it seems like you're missing the point (... is my guess about the downvotes). Your last sentence makes an important point, though - relying on type inference always lets type errors propagate further than they would if everything was explicitly typed. Adding more an…

Yeah that's true.

But also, for every developer with a couple of month experience, this is not a new problem. It happens all the time, be it missing some parens or a dot or a return / semicolon (depending on the language of course).

Usually it's very easy to hunt it down - you see "a + 1" and you say "wait, a should be an integer - why is it not" and then you go back from there. But in general I agree that it adds some time in such cases that would be resolved quicker with annotations everywhere.

Re: A guide to error handling in Rust

#72

Earlier quoted context omitted.

Maybe this is just about terminology. But essentially, when it comes to union types, they behave like sets. The compiler merges them. (A | B) | (A | B) is the same as A | B. But for sum types (even anonymous ones such as tuples) the compiler can't merge them because that would lose information (if the result is from the first A | B or the second one). Instead, you end up with a nested structure. Which one is desired…

The problem is that if you have e.g. let x: u64|i32 = ... It's impossible for the compiler to do anything with x without adding some kind of runtime type tag. The representations of those types are different. But with something like OCaml's polymorphic variants, you could do e.g. let x: Big(u64)|Small(i32) = ... and then switch on the tag (Big or Small) to determine what to do with the values.

> It's impossible for the compiler to do anything with x without adding some kind of runtime type tag.

Yes, in this particular case that's true. If the developer tries to do anything except maybe printing it for debug then the compiler will tell the developer so and the developer will have to switch to sumtypes / wrap it just like it is done in OCaml by default.

Re: A guide to error handling in Rust

#73

Earlier quoted context omitted.

> unless you have static type definitions for these methods you start having a very bad time inferring what types are being passed around. It doesn't matter if the types are annotated explicitly or inferred. The amount of information is 100% the same. The IDE could just fill in the types _exactly_ in the same way as they would look like when annotated by hand - maybe just with a different color. IntelliJ does this qu…

> It doesn't matter if the types are annotated explicitly or inferred. The amount of information is 100% the same. Explicit offers the opportunity for narrowing, comments, and sometimes choice of names. Otherwise, yes.

Good points!

Re: A guide to error handling in Rust

#74

Earlier quoted context omitted.

While I don't strongly object to Rust's choice here, and I agree that production code should have a type signature on every function, I think this is more a place for lint/clippy/whatever. There's no need to gate the programmer trying something on them having produced a type signature that could be inferred.

You might be interested to know that rustc does have some limited ability to infer return types[1], but there are so many edge cases that the feature as it exists today isn't perfect (and won't let you produce a binary). I believe that 1) type alias = impl Trait; will make prototyping easier, and 2) we should allow -> _ in return types in private functions so that they become an allowed part of the language but criti…

Where do I sign up to fight you on that last one? :D

Allowing _ in return position only for private functions feels like something that ends up surprising 99% of people either that this works, or that it doesn't work for their public function and neither group of people are filled with joy as a result.

It's not a hill I'd die on, but it would go on my list of things I don't like in Rust, along with most as casts, impl AddAssign for String, is_ascii_predicates(/* taking */ &self)

Re: A guide to error handling in Rust

#75

Earlier quoted context omitted.

You might be interested to know that rustc does have some limited ability to infer return types[1], but there are so many edge cases that the feature as it exists today isn't perfect (and won't let you produce a binary). I believe that 1) type alias = impl Trait; will make prototyping easier, and 2) we should allow -> _ in return types in private functions so that they become an allowed part of the language but criti…

Where do I sign up to fight you on that last one? :D Allowing _ in return position only for private functions feels like something that ends up surprising 99% of people either that this works, or that it doesn't work for their public function and neither group of people are filled with joy as a result. It's not a hill I'd die on, but it would go on my list of things I don't like in Rust, along with most as casts, imp…

The likelihood of it actually landing is quite low, because I suspect quite a few people would agree with you, and as long as rustfix can deal with it I also don't care as strongly about it ^_^

Re: A guide to error handling in Rust

#76

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 think that taking options and results usually is an anti pattern. You want to handle the errors at creation-site and not propagate it to another function.

Of course this is just a minimal example... Others have talked about the real point of this comment, and it's just a minor nit. I wanted to point this out for new rust programmers reading this.

Post reply on HN