Can we move `std::error::Error` to `core`?

I was skimming through a Reddit thread asking about Rust's sharp edges and came across this comment.

  • write! uses duck-typing and works with anything that has a write_fmt method
  • Impls for arrays are limited to array with <= 32 elements due to missing const generics (which is being worked on)
  • Similarly, impls for tuples are limited to tuples with <= 12 elements due to missing variadic generics
  • std::error::Error and std::io::{Read, Write} do not exist in libcore, which can make writing #![no_std] libraries painful

Which raises the question, is it possible to move std::error::Error to core and re-export it to std?

Rust prides itself on excellent error handling and although things like Result and ? are usable in #[no_std] code, not having the Error type sticks out like a sore thumb.

More concretely, this also means crate authors who want to expose an error type often need to create a std feature and conditionally implement Error.

The only insurmountable problem I can foresee is problems with coherence. Where certain blanket impls will be written in std (most probably around Box<T>) that aren't possible if it is in core.

The coherence problem is explained in a comment in libstd/error.rs:

// A note about crates and the facade:
//
// Originally, the `Error` trait was defined in libcore, and the impls
// were scattered about. However, coherence objected to this
// arrangement, because to create the blanket impls for `Box` required
// knowing that `&str: !Error`, and we have no means to deal with that
// sort of conflict just now. Therefore, for the time being, we have
// moved the `Error` trait into libstd. As we evolve a sol'n to the
// coherence challenge (e.g., specialization, neg impls, etc) we can
// reconsider what crate these items belong in.

Maybe it could move to the alloc crate? It doesn't really fit in there, but I think technically it should work.

2 Likes

This move was done for rebalancing coherence (rfcs#1023) in https://github.com/rust-lang/rust/pull/23867. Does the recent re-rebalancing coherence (rfcs#2451) allow Error be moved back to libcore?

It is also possible to explicitly impl !Error for &str {} now, but AFAIK it doesn't change the coherence.

1 Like

In Rust, std::error::Error is just std::fmt::Display with an error chain (using source) and possibly a backtrace. In resource constrained environments I can't imagine that either of those things are practical (correct me if I'm wrong), so would it be easier to just use the Display trait rather than the Error trait for errors? That way you can still print the error.

3 Likes

It would be fantastic if std::error::Error were available in alloc.

Several years ago I went to a meeting with Aaron Turon and Brian Anderson and we discussed that possibility (in the scope of error-chain in the pre-failure days) and at that time there was at least rough consensus it was possible. Not sure if anything has changed since, but it would definitely be great to be able to use the Error trait in no_std + alloc environments.

1 Like

Hmm, I guess the unstable Error::backtrace might be difficult without std though.

I think if we generalized the backtrace fn to return generic types it would work on no-std, something like

backtrace is already no_std compatible (with a std feature):

fancy!

It was just noted in another thread that there was an issue about moving Error to alloc, and that was closed citing the need for an RFC to resolve questions around backtraces.

1 Like