Live data from Hacker News

Using unwrap() in Rust is Okay (2022)

burntsushi.net

11–20 of 54 posts

Re: Using unwrap() in Rust is Okay (2022)

#11
post #3

> That section briefly described that, broadly speaking, using unwrap() is okay if it’s in test/example code or when panicking indicates a bug. I've come to the conclusion that even in tests unwraps look ugly. Especially in doc tests which serve as examples the code is better off using regular "?" that one would see in other parts of code. (that is: don't treat test code as a "worse" kind of code) In Signstar we're u…

> but the rendered example looks a lot better:

For doctests it makes total sense, but for regular test no so much.

Re: Using unwrap() in Rust is Okay (2022)

#13
post #9

Just don’t put unwrap in library code, please. Not if it can possibly happen, bearing in mind that you can make mistakes. I like my background threads to be infallible. If they panic, then chances are nothing will notice and the rest of the program will solely seize up. I might have agreed with more of this article if panics actually crashed the program, but in multithreaded Rust that’s rarely the case.

> I might have agreed with more of this article if panics actually crashed the program, but in multithreaded Rust that’s rarely the case. Why is that?

If you don't join the threads a panic get stopped at thread boundaries (unless you have taken a lock when the panic happens, in which case the lock is poisoned and attempting to lock it again will return an error. Error that will most likely trigger a further panic since you usually write something like

    let mutex_guard= mutex.lock().expect("poisoned lock");

Re: Using unwrap() in Rust is Okay (2022)

#14
post #8

The article pretty much says this as well, but a concise way I saw Andrew Kelley put it recently in the context of Zig (but it seems to apply well for any language that has errors-as-values + panics) is: "Assertions for programmer mistakes; errors for user mistakes."[0] One interesting difference between Zig and other languages with similar error stories (Rust, Go) is that panicking can be handled but not recovered .…

> Assertions for programmer mistakes; errors for user mistakes

That's been the general mantra for at least a decade or two. And I think it's right.

Re: Using unwrap() in Rust is Okay (2022)

#15
post #5
post #3

> That section briefly described that, broadly speaking, using unwrap() is okay if it’s in test/example code or when panicking indicates a bug. I've come to the conclusion that even in tests unwraps look ugly. Especially in doc tests which serve as examples the code is better off using regular "?" that one would see in other parts of code. (that is: don't treat test code as a "worse" kind of code) In Signstar we're u…

I always felt unwrap is preferable for diagnosing issues, which makes it useful in tests. A failed unwrap will point you directly to the line of code which panics, which is much simpler than trying to trace an issue through many layers of Results. If you use `assert` in tests, I don't understand why you wouldn't also prefer unwrap in this context. I think it's also perfectly reasonable to use in a context like binary…

I call unwrap a lot in unit tests where it feels obvious to me that this succeeds, so, if it doesn't that's a huge mistake and should definitely fail the test but I have no pre-existing description of what's wrong, it's just a big red flag that I'm wrong.

Fallible conversions that never fail in the tested scenario are an example - parsing "15/7" as a Rational is never going to fail, so unwrap(). Converting 0.125 into a Real is never going to fail, so unwrap(). In a doctest I would write at least the expect call, because in many contexts you should handle errors and this shows the reader what they ought to do, but in the unit test these errors should never happen, there's no value in extensive handling code for this case.

Re: Using unwrap() in Rust is Okay (2022)

#16
post #8

The article pretty much says this as well, but a concise way I saw Andrew Kelley put it recently in the context of Zig (but it seems to apply well for any language that has errors-as-values + panics) is: "Assertions for programmer mistakes; errors for user mistakes."[0] One interesting difference between Zig and other languages with similar error stories (Rust, Go) is that panicking can be handled but not recovered .…

> which removes any temptation to use them for user errors. It doesn't look to be too much of a temptation to use panics as regular errors in Rust though, so I don't think it gains you much. And it makes it more complicated when you want to catch panics for legitimate reasons (like when you want to show an error box to the user, instead of silently crashing, or when you want to send the crash log for later analysis).…

> It doesn't look to be too much of a temptation to use panics as regular errors in Rust though

Maybe not, but it was enough for the author to dedicate at least one whole section of the article to reasoning about this.

> like when you want to show an error box to the user, instead of silently crashing, or when you want to send the crash log for later analysis

As I mentioned, panics can be handled but not recovered. You can use the panic handler to do these things just fine. Just not recover.

Re: Using unwrap() in Rust is Okay (2022)

#17

While I don't fully understand rust (not that I've really attempted to program in it much), I do really like the Result convention. Before I knew about it, I used a similar construct in a couple of places in my C# code, but I think I'll make my own version of it and try to use it more often. I don't think C# has a builtin version anyway, I know it has a builtin that does the same as Option with its nullable types, li…

C# may add discriminate union so you won’t need your own types! Both Result and Option should be included too.

Re: Using unwrap() in Rust is Okay (2022)

#18
post #16

Earlier quoted context omitted.

> which removes any temptation to use them for user errors. It doesn't look to be too much of a temptation to use panics as regular errors in Rust though, so I don't think it gains you much. And it makes it more complicated when you want to catch panics for legitimate reasons (like when you want to show an error box to the user, instead of silently crashing, or when you want to send the crash log for later analysis).…

> It doesn't look to be too much of a temptation to use panics as regular errors in Rust though Maybe not, but it was enough for the author to dedicate at least one whole section of the article to reasoning about this. > like when you want to show an error box to the user, instead of silently crashing, or when you want to send the crash log for later analysis As I mentioned, panics can be handled but not recovered .…

I've never heard of anyone using panic for exception-style recovery. That's anathema to the whole idea of Result. But I suppose if it's possible, it will be normal for someone.

Re: Using unwrap() in Rust is Okay (2022)

#19
The general issue, as I see it:

One function is too general and handles all inputs. Some inputs are wrong and code returns error. Some languages forces you to handle that error.

Another code snippet uses that function with very specific inputs which must not cause errors, but was forced to handle error, because of language rules. This error handling is essentially useless.

I saw this issue with Java. There's constructor `new URI(String) throws URISyntaxException`. URISyntaxException is checked exception which must be handled at invocation site or propagated to the caller. But you might need to write code like `var uri = new URI("https://example.com/")` and any error handling code will only be to please the compiler, essentially wasted work. Java solved it using `public static URI create(String str)` which does not throw checked exceptions and you're supposed to choose either constructor or factory method, depending in the circumstances.

Using Rust analogy, may be it would be useful for Java to write something like `var uri = unchecked new URI("https://example.com/");`, so with minimal syntax overhead you would signal that checked exceptions are not supposed to occur here (and if they did occur, then some unchecked UnexpectedCheckedException would throw here). It's actually possible to implement method `static T unchecked(CheckedSupplier supplier)`, though syntax would be ugly: `var uri = unchecked(() -> new URI("https://example.com/"))`.

I think that this is general issue for programming languages. There's only one way to validate input parameters and report error. But whether those input parameters are trusted or not - only the caller knows. So nothing wrong about using `unwrap()` to signify the fact, that caller already made sure that error does not happen. The only important nuance is that error must not be swallowed if it happened.

Re: Using unwrap() in Rust is Okay (2022)

#20

The general issue, as I see it: One function is too general and handles all inputs. Some inputs are wrong and code returns error. Some languages forces you to handle that error. Another code snippet uses that function with very specific inputs which must not cause errors, but was forced to handle error, because of language rules. This error handling is essentially useless. I saw this issue with Java. There's construc…

It's a general issue with typed languages. Types are either too fine-grained or too coarse. Some more sophisticated languages can infer a whole lot but static type checking is still confusing and slows down builds. I tend to not worry much about them anymore -- about C language level types (maybe a bit more) is helpful and important for performance, but beyond that (e.g. types get dynamically instanciated from templates by the compiler) returns are diminishing quickly for many tasks.

The biggest robustness gains often come from making the right architectural decisions. That also applies to error handling as you described.

Post reply on HN