Live data from Hacker News

Rust errors without dependencies

vincents.dev

81–90 of 91 posts

Re: Rust errors without dependencies

#81
post #6

Earlier quoted context omitted.

And it was treated as potentially malformed and hence the panic. That's what panic is for! When invariants are not upheld at runtime, in Cloudflare's case an abnormal amount of entries IIRC. I mean, if the error was handled what would you have done if not crashing the service with an error message? I think the post's point is that you don't panic if someone submits a malformed PDF (you just reject their request) but…

Continue with the previous config. If the config-loading function was fallible, and that bubbled up somewhere, someone might say, "Oh this can fail, we should do blue-green for configs the same as we do for exes." With it being infallible and a panic, that gets hidden. If I was designing a language to surpass Rust, I'd make panics opt-in. I think Rust has a team looking into no-panic but it's a funny loophole for a l…

I think "eliminate crashes" isn't the way to describe what Rust aims for. Eliminate memory corruption, yes. But one mechanism for achieving that was safely crashing.

Re: Rust errors without dependencies

#82
post #79

Earlier quoted context omitted.

>I don't think a crate should abdicate from modeling the error domain any more than they should abdicate from modeling the other types. Yes, it's just harder. We usually have a pretty good idea what callers want from the happy path, but the range of things that callers may or may not want to do in case of an error is very broad.

This is an interesting perspective. I usually don't try to imagine how someone should handle the error. Instead I try to indicate the different types of errors that could occur and what type of information needs to be included to be useful to the caller. I can leave the question of what to do with that information to the caller since it's highly situational and the context necessary to make that decision lives outsid…

That can be tricky because there may be a trade-off between error message quality and something else. Like, perhaps, the size of an error, code size or even runtime performance. Another trade-off with too-detailed errors---especially when those details are part of the library API---is that they become an extensibility hazard. Unless you're extremely certain about the line that divides a specific implementation from the logical domain of errors for a particular operation, you might get that wrong. And changing the implementation in the future might want a change in the error details.

This is very hand-wavy, but I think we're talking at a very high level of abstraction here. My main point is to suggest that there is more of a balancing act here than perhaps your words suggest.

Re: Rust errors without dependencies

#83
post #56

Earlier quoted context omitted.

I doubt epage is suggesting that. And note that in that case, the thing distinguishing the cause is not `std::io::Error`, but `std::io::ErrorKind`. The latter is not the error type, but something that forms a part of the I/O error type. It's very rare that `pub enum Error { ... }` is something I'd put into the public API of a library. epage is absolutely correct that it is an extensibility hazard. But having a sub-or…

It's not uncommon to have it on the error itself, rather than a details/kind auxiliary type. AWS SDK does it, nested even [0][1], diesel[2], password_hash[3]. [0] https://docs.rs/aws-smithy-runtime-api/1.9.3/aws_smithy_runt... [1] https://docs.rs/aws-sdk-s3/1.119.0/aws_sdk_s3/operation/get_... [2] https://docs.rs/diesel/2.3.5/diesel/result/enum.Error.html [3] https://docs.rs/password-hash/0.5.0/password_hash/errors/e…

Sure, I've done it too: https://docs.rs/ignore/latest/ignore/enum.Error.html

It's not necessarily about frequency, but about extensibility. There's lot of grey area there. If you're very certain of your error domain and what kinds of details you want to offer, then the downside of a less extensible error type may never actualize. Similarly, if you're more open to more frequent semver incompatible releases, then the downside also may never actualize.

Re: Rust errors without dependencies

#84

Earlier quoted context omitted.

> I do think that `std::error::Error` is mostly pointless. That's a value judgment, and reasonable people can disagree. I took it as a statement of fact. It is a factual matter of whether `std::error::Error` has a point to it or not. And it definitively does. I use the error chain in just about every CLI application I've built. It's not even mostly pointless. It's incredibly useful and it provides an interoperable po…

> I took it as a statement of fact. It is a factual matter of whether `std::error::Error` has a point to it or not. And it definitively does. I use the error chain in just about every CLI application I've built. It's not even mostly pointless. It's incredibly useful and it provides an interoperable point for libraries to agree upon a single error interface. Okay, I'm willing to give you this one. I haven't encountere…

> It may just be a matter of perspective -- if you don't count rust pre 1.0, then yeah it "never" involved backtrace.

Yes. I'm only counting what has been part of the stable API since Rust 1.0.

I agree that following the stabilization path and future direction of a feature can be difficult.

> Because if the only purpose was error chains, it could have been in core on the day of rust 1.0, as it is today. I think what actually happened is `fn backtrace(&self) -> Option` was removed shortly before 1.0, but there were some misgivings about that and some on the core team wanted to bring that back eventually. And that was the main reason that it could not move to core, because that would make it a breaking change to bring `fn backtrace` back. At least that's what I remember from PRs I followed at the time. (There may have been other reasons besides this though?)

The only purpose is not chaining. Backtraces were definitely a desirable part of it! But we wanted to move `Error` to `core` and having backtraces be tightly coupled to `Error` would not allow that. As far as I remember, that was always the tension. To my memory, it wasn't until Jane wrote down the "generic member access" direction[1] for the `Error` trait that this tension was finally broken.

[1]: https://github.com/rust-lang/rfcs/pull/2895

Re: Rust errors without dependencies

#85
post #49

The fact that you either need a third party dependency or a large amount of boilerplate just to get decent error reporting, points to an issue in the language or std library design. I've started also dropping `thiserror` when building libraries, as I don't want upstream users of my libraries to incur this additional dependency, but it's a pain.

Why are people disagreeing with this? This is absolutely a problem that most other languages don't have. If you want to claim that Rust's error system is "better" than anything else (as the author did), you should have a good argument about why this exact problem the parent commenter described, which to me is a major problem, does not (maybe) cancel out all the other purported benefits of Rust's error system!

This isn't a problem in other languages because most other languages don't have strong, statically typed errors that need to compose across libraries. And those that do have the same problem.

The general argument against adding something to `std` is that once the API is stabilized, it's stabilized forever (or at least for an edition, but practically I don't think many APIs have been changed or broken across editions in std).

The aversion to dependencies is just something you have to get over in Rust imo. std is purposefully kept small and that's a good thing (although it's still bigger and better than C++, which is the chief language to compare against).

Re: Rust errors without dependencies

#86
post #4

> I want less code. I want to limit the amount of 3rd party code I pull in. This is mostly due to supply chain disasters over on NPM scaring me and the amount of code dependencies bringing in see rust dependencies scare me. And this is basically why I like the C/C++ model of not having a centralized repo better. If I need some external piece of software, I simply download the headers and/or sources directly and place…

This is called "vendoring" and any package manager that doesn't totally suck supports it, including cargo.

Re: Rust errors without dependencies

#87
post #79

Earlier quoted context omitted.

>I don't think a crate should abdicate from modeling the error domain any more than they should abdicate from modeling the other types. Yes, it's just harder. We usually have a pretty good idea what callers want from the happy path, but the range of things that callers may or may not want to do in case of an error is very broad.

This is an interesting perspective. I usually don't try to imagine how someone should handle the error. Instead I try to indicate the different types of errors that could occur and what type of information needs to be included to be useful to the caller. I can leave the question of what to do with that information to the caller since it's highly situational and the context necessary to make that decision lives outsid…

>I usually don't try to imagine how someone should handle the error.

But that's exactly what you do when you...

>... try to indicate the different types of errors that could occur and what type of information needs to be included to be useful to the caller.

Modelling the error domain means to decide which possible distinctions matter and which don't. This is not self evident. It's you imagining what users may want to do with your errors.

Is it enough for the caller to know that some string you're parsing is invalid or do they need to know what it is exactly that makes it invalid?

If you decide to just pass on everything you happen to know based on your current implementation then you are putting restrictions on future changes to that implementation, potentially including the use of third party libraries.

What if you find a shortcut or a library that makes your parser 10 times faster but doesn't provide this detailed information?

What I see a lot in Rust is that massive amounts of implementation details are leaked via errors. thiserror actually encourages this sort of implementation leak:

  #[derive(Error, Debug)]
  pub enum MyError {
      Io(#[from] io::Error),
      Glob(#[from] globset::Error),
  }
https://docs.rs/thiserror/latest/thiserror/

Re: Rust errors without dependencies

#88
post #79

Earlier quoted context omitted.

This is an interesting perspective. I usually don't try to imagine how someone should handle the error. Instead I try to indicate the different types of errors that could occur and what type of information needs to be included to be useful to the caller. I can leave the question of what to do with that information to the caller since it's highly situational and the context necessary to make that decision lives outsid…

That can be tricky because there may be a trade-off between error message quality and something else. Like, perhaps, the size of an error, code size or even runtime performance. Another trade-off with too-detailed errors---especially when those details are part of the library API---is that they become an extensibility hazard. Unless you're extremely certain about the line that divides a specific implementation from t…

I agree that it's a balancing act. I just don't think you get to abdicate from doing that balancing act and getting the balance wrong has consequences just like getting the balancing act wrong in your non error data model.

Re: Rust errors without dependencies

#89
post #79

Earlier quoted context omitted.

This is an interesting perspective. I usually don't try to imagine how someone should handle the error. Instead I try to indicate the different types of errors that could occur and what type of information needs to be included to be useful to the caller. I can leave the question of what to do with that information to the caller since it's highly situational and the context necessary to make that decision lives outsid…

>I usually don't try to imagine how someone should handle the error. But that's exactly what you do when you... >... try to indicate the different types of errors that could occur and what type of information needs to be included to be useful to the caller. Modelling the error domain means to decide which possible distinctions matter and which don't. This is not self evident. It's you imagining what users may want to…

Sure, if you don't model the error domain correctly you will leak stuff that maybe you shouldn't leak. But I'm not sure that this is worse than just not exposing the types of errors that you are handling.

Your example is interesting actually because there are real differences in those types of errors. IO errors are different from the globset errors. It is reasonable to assume that you would want to handle them differently. If your function can actually have both errors as a consumer I would want to know that so I can make the correct decisions in context. If you don't have a way to signal to my code that both happen you've deprived me of the tools to do my own proper error modeling and handling.

Re: Rust errors without dependencies

#90
post #89

Earlier quoted context omitted.

>I usually don't try to imagine how someone should handle the error. But that's exactly what you do when you... >... try to indicate the different types of errors that could occur and what type of information needs to be included to be useful to the caller. Modelling the error domain means to decide which possible distinctions matter and which don't. This is not self evident. It's you imagining what users may want to…

Sure, if you don't model the error domain correctly you will leak stuff that maybe you shouldn't leak. But I'm not sure that this is worse than just not exposing the types of errors that you are handling. Your example is interesting actually because there are real differences in those types of errors. IO errors are different from the globset errors. It is reasonable to assume that you would want to handle them differ…

>Sure, if you don't model the error domain correctly you will leak stuff that maybe you shouldn't leak

You are implying that there is one correct and self evident set of distinctions. I disagree with that. In library design, you're always making assumptions about what users may want. In my opinion, this is even harder when modelling errors, because there are so many possible ways in which callers might want to respond.

>Your example is interesting actually because there are real differences in those types of errors. IO errors are different from the globset errors.

Of course. I'm not complaining about the distinction between io errors and globbing errors here but about the fact that the globset library and its specific error type is leaked.

What if someone (say fastburningsushi) comes along and creates a glob library that absolutely smokes this one? :P

Post reply on HN