←back to thread

611 points LorenDB | 10 comments | | HN request time: 0.001s | source | bottom
Show context
dvratil ◴[] No.43908097[source]
The one thing that sold me on Rust (going from C++) was that there is a single way errors are propagated: the Result type. No need to bother with exceptions, functions returning bool, functions returning 0 on success, functions returning 0 on error, functions returning -1 on error, functions returning negative errno on error, functions taking optional pointer to bool to indicate error (optionally), functions taking reference to std::error_code to set an error (and having an overload with the same name that throws an exception on error if you forget to pass the std::error_code)...I understand there's 30 years of history, but it still is annoying, that even the standard library is not consistent (or striving for consistency).

Then you top it on with `?` shortcut and the functional interface of Result and suddenly error handling becomes fun and easy to deal with, rather than just "return false" with a "TODO: figure out error handling".

replies(24): >>43908133 #>>43908158 #>>43908212 #>>43908219 #>>43908294 #>>43908381 #>>43908419 #>>43908540 #>>43908623 #>>43908682 #>>43908981 #>>43909007 #>>43909117 #>>43909521 #>>43910388 #>>43912855 #>>43912904 #>>43913484 #>>43913794 #>>43914062 #>>43914514 #>>43917029 #>>43922951 #>>43924618 #
dvt ◴[] No.43908158[source]
Maybe contrarian, but imo the `Result` type, while kind of nice, still suffers from plenty of annoyances, including sometimes not working with the (manpages-approved) `dyn Error`, sometimes having to `into()` weird library errors that don't propagate properly, or worse: `map_err()` them; I mean, at this point, the `anyhow` crate is basically mandatory from an ergonomics standpoint in every Rust project I start. Also, `?` doesn't work in closures, etc.

So, while this is an improvement over C++ (and that is not saying much at all), it's still implemented in a pretty clumsy way.

replies(4): >>43908206 #>>43908469 #>>43908676 #>>43909810 #
1. ackfoobar ◴[] No.43908469[source]
> the `anyhow` crate is basically mandatory from an ergonomics standpoint in every Rust project I start

If you use `anyhow`, then all you know is that the function may `Err`, but you do not know how - this is no better than calling a function that may `throw` any kind of `Throwable`. Not saying it's bad, it is just not that much different from the error handling in Kotlin or C#.

replies(4): >>43908675 #>>43909119 #>>43909718 #>>43912137 #
2. efnx ◴[] No.43908675[source]
Yes. I prefer ‘snafu’ but there are a few, and you could always roll your own.
replies(2): >>43908842 #>>43909226 #
3. shepmaster ◴[] No.43908842[source]
Yeah, with SNAFU I try to encourage people going all-in on very fine-grained error types. I love it (unsurprisingly).
4. jbritton ◴[] No.43909119[source]
I know a ‘C’ code base that treats all socket errors the same and just retries for a limited time. However there are errors that make no sense to retry, like invalid socket or socket not connected. It is necessary to know what socket error occurred. I like how the Posix API defines an errno and documents the values. Of course this depends on accurate documentation.
replies(1): >>43910468 #
5. smj-edison ◴[] No.43909226[source]
+1 for snafu. It lets you blend anyhow style errors for application code with precise errors for library code. .context/.with_context is also a lovely way to propagate errors between different Result types.
replies(1): >>43909310 #
6. bonzini ◴[] No.43909310{3}[source]
How does that compare to "this error for libraries and anyhow for applications"?
replies(1): >>43909367 #
7. smj-edison ◴[] No.43909367{4}[source]
You don't have to keep converting between error types :)
8. Yoric ◴[] No.43909718[source]
Yeah, `anyhow` is basically Go error handling.

Better than C, sufficient in most cases if you're writing an app, to be avoided if you're writing a lib. There are alternatives such as `snafu` or `thiserror` that are better if you need to actually catch the error.

9. XorNot ◴[] No.43910468[source]
This is an IDE/documentation problem in a lot of cases though. No one writes code badly intentionally, but we are time constrained - tracking down every type of error which can happen and what it means is time consuming and you're likely to get it wrong.

Whereas going with "I probably want to retry a few times" is guessing that most of your problems are the common case, but you're not entirely sure the platform you're on will emit non-commoncases with sane semantics.

10. dwattttt ◴[] No.43912137[source]
I find myself working through a hierarchy of error handling maturity as a project matures.

Initial proof of concepts just get panics (usually with a message).

Then functions start to be fallible, by adding anyhow & considering all errors to still be fatal, but at least nicely report backtraces (or other things! context doesn't have to just be a message)

Then if a project is around long enough, swap anyhow to thiserror to express what failure modes a function has.