←back to thread

611 points LorenDB | 2 comments | | HN request time: 0.416s | source
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 #
jasonjmcghee ◴[] No.43908133[source]
unfortunately it's not so simple. that's the convention. depending on the library you're using it might be a special type of Error, or special type of Result, something needs to be transformed, `?` might not work in that case (unless you transform/map it), etc.

I like rust, but its not as clean in practice, as you describe

replies(5): >>43908198 #>>43908870 #>>43908919 #>>43908995 #>>43912581 #
1. ryandv ◴[] No.43908995[source]
There are patterns to address it such as creating your own Result type alias with the error type parameter (E) fixed to an error type you own:

    type Result<T> = result::Result<T, MyError>;

    #[derive(Debug)]
    enum MyError {
        IOError(String)
        // ...
    }
Your owned (i.e. not third-party) Error type is a sum type of error types that might be thrown by other libraries, with a newtype wrapper (`IOError`) on top.

Then implement the `From` trait to map errors from third-party libraries to your own custom Error space:

    impl From<io::Error> for MyError {
        fn from(e: io::Error) -> MyError {
            MyError::IOError(e.to_string())
        }
    }
Now you can convert any result into a single type that you control by transforming the errors:

    return sender
        .write_all(msg.as_bytes())
        .map_err(|e| e.into());
There is a little boilerplate and mapping between error spaces that is required but I don't find it that onerous.
replies(1): >>43910763 #
2. johnisgood ◴[] No.43910763[source]
I scratch my head when people try to justify Rust's implementation of X. It looks absolutely horrendous, IMO.

I would rather have what OCaml has: https://ocaml.org/docs/error-handling.