I still think it's kind of mad that the standard library doesn't have better options built in. We've had long enough to explore the approaches. It's time to design something that can go into std and be used by everybody. As it is any moderately large Rust project ends up including several different error handling crates.
Rust errors without dependencies
11–20 of 91 posts
Re: Rust errors without dependencies
#12I've been using rust for 8+ years, I remember the experiments around `failure` crate, a precursor to anyhow if I remember right... and then eyre, and then thiserror...
It just felt like too much churn and each one offered barely any distinction to the previous.
Additionally, the `std::error::Error` trait was very poorly designed when it was initially created. It was `std` only and linked to a concept of backtraces, which made it a non-starter for embedded. It just seemed to me that it was a bad idea ever to use it in a library and that it would harm embedded users.
And the upside for non-embedded users was minimal. Indeed most of it's interface since then has been deprecated and removed, and it to this day has no built-in idea of "error accumulation". I really can't understand this. That's one of the main things that I would have wanted an generic error interface to solve in order to be actually useful.
It was also extremely painful 5 years ago when cargo didn't properly do feature unification separately for build dependencies vs. target dependencies. This meant that if you used anything in your build.rs that depended on `failure` with default features, and turned on `std` feature, then you cannot use `failure` anywhere in your actual target or you will get `std` feature and then your build will break. So I rapidly learned that these kinds of crates can cause much bigger problems than they actually solve.
I think the whole "rust error handling research" area has frankly been an enormous disappointment. Nowadays I try to avoid all of these libraries (failure, anyhow, thiserror, etc.) because they all get abandoned sooner or later, and they brought very little to the table other than being declared "idiomatic" by the illuminati. Why waste my time rewriting it in a year or two for the new cool flavor of suck.
Usually what I actually do in rust for errors now is, the error is an enum, and I use `displaydoc` to make it implement `Display`, because that is actually very simple and well-scoped, and doesn’t involve std dependencies. I don't bother with implementing `std::error::Error`, because it's pointless. Display is the only thing errors need to implement, for me.
If I'm writing an application and I come to a point where I need to "box" or "type erase" the error, then it becomes `String` or perhaps `Box` if I care about a few bytes. It may feel crude, but it is simple and it works. That doesn't let you downcast errors later, but the situations where you actually have to do that are very rare and I'm willing to do something ad hoc in those cases. You can also often refactor so that you don't actually have to do that. I'm kind of in the downcasting-is-a-code-smell camp anyways.
I'm a little bit excited about `rootcause` because it seems better thought out than it's progenitors. But I have yet to try to make systematic use of it in a bigger project.
Re: Rust errors without dependencies
#13> 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…
External C++ code never has CVEs? Or I guess since you are manually managing it, you are just ignorant of any CVEs?
Re: Rust errors without dependencies
#14That's quite a good amount of boilerplate to create a custom, project-specific handling of errors, which itself can have bugs. During reading I thought " anyhow , at this point you are half way to reinvent the wheel and write your own "anyhow'". I agree with avoiding an explosion of dependencies; but not at any cost. In any case if custom error handling works, then why not. It's just that it feels like a deviation to…
Re: Rust errors without dependencies
#15Re: Rust errors without dependencies
#16`anyhow` has exactly one optional dependency (backtrace). `thiserror` has three (proc-macro2, quote, syn) which are at the base of practically the entire Rust ecosystem.
Unless the author has zero dependencies in general, I'll bet they have all of the above dependencies already.
¯\_(°ペ)_/¯
Re: Rust errors without dependencies
#17I find it hard to believe. Since a huge class of errors are caught by compile time static analysis, you don't really need an exception system, and errors are basically just return values that you check.
It's much more productive just to use return values and check them, wrap return values in an optional, do whatever. Just move on, do not recreate the features of your previous language on a new language.
Re: Rust errors without dependencies
#18OP is spot on, no deps is the way. I've been using rust for 8+ years, I remember the experiments around `failure` crate, a precursor to anyhow if I remember right... and then eyre, and then thiserror... It just felt like too much churn and each one offered barely any distinction to the previous. Additionally, the `std::error::Error` trait was very poorly designed when it was initially created. It was `std` only and l…
It was never linked to backtraces. And if you used `std::error::Error` in a library that you also wanted to support in no-std mode, then you just didn't implement the `std::error::Error` trait when the `std` feature for that library isn't enabled. Nowadays, you can just implement the `core::error::Error` trait unconditionally.
As for backtrace functionality, that is on the cusp of being stabilized via a generic interface that allows `core::error::Error` to be defined in `core`: https://github.com/rust-lang/rust/issues/99301
> and it to this day has no built-in idea of "error accumulation".
The `Error` trait has always had this. It started with `Error::cause`. That was deprecated long ago because of an API bug and replaced with `Error::source`.
> It just felt like too much churn and each one offered barely any distinction to the previous.
I wrote about how to do error handling without libraries literally the day Rust 1.0 was published: https://burntsushi.net/rust-error-handling/
That blog did include a recommendation for `failure` at one point, and now `anyhow`, but it's more of a footnote. The blog shows how to do error handling without any dependencies at all. You didn't have to jump on the error library treadmill. (Although I will say that `anyhow` and `thiserror` have been around for a number of years now and shows no signs of going away.)
> I don't bother with implementing `std::error::Error`, because it's pointless.
It's not. `std::error::Error` is what lets you provide an error chain. And soon it will be what you can extract a backtrace from.
> I'm kind of in the downcasting-is-a-code-smell camp anyways.
I happily downcast in ripgrep: https://github.com/BurntSushi/ripgrep/blob/0a88cccd5188074de...
That also shows the utility of an error chain.
Re: Rust errors without dependencies
#19My controversial take on Rust errors is to use anyhow everywhere until you have an immediate demand for explicit Enums. YANGNI The pros for using anyhow are big: Easily stack errors together - eg file.open().context(path) -, errors are easily kept up to date, and easy to find where they occur. An enum error is pleasing when you're finished, but cumbersome in practice. It's niche situation that you need to write a fun…
anyhow seems useful in the very top layers where you basically just want bubble the useful errors modeled elsewhere to a top layer that can appropriately handle them. I don't think a crate should abdicate from modeling the error domain any more than they should abdicate from modeling the other types.
Re: Rust errors without dependencies
#20Earlier quoted context omitted.
you could just do that with Rust, right? you’re just saying cargo makes it too easy not to I’m very tempted to go this direction myself with Rust, vendoring in and “maintaining” (using Claude Code to maintain) dependencies. or writing subsets of the crates I need myself and using those. the sprawl with Rust dependencies is concerning
Yes of course you could do this in Rust. It's just that every resource out there promotes the usage of Cargo, and sells this as an "improvement" over the old school way of managing dependencies manually.
I think you’re conflating the tool, with how people manage deps.