3
votes

I've run into a problem with piston2d-graphics crate. When I try to use expect() method on Result that I get from graphics::character::CharacterCache::character method, it turns out I can't — because it requires the Error type of the Result to implement std::fmt::Debug trait:

error[E0599]: no method named `expect` found for type `std::result::Result<graphics::character::Character<'_, <G as graphics::Graphics>::Texture>, <C as graphics::character::CharacterCache>::Error>` in the current scope
  --> src/some_file.rs:44:53
   |
44 |             let ch_glyph = glyphs.character(34, ch).expect("Couldn't load character");
   |                                                     ^^^^^^
   |
   = note: the method `expect` exists but the following trait bounds were not satisfied:
           `<C as graphics::character::CharacterCache>::Error : std::fmt::Debug`

Error here is an associated (nested) type in CharacterCache trait. I can easily submit a PR that adds the requirement and then add it's implementation with a simple derive macro to all other crates. It seems reasonable, because expect() and other related methods are used in Rust all the time, but I'm not sure. Is it the Rust way, or are there reasons not to do it?


I describe the question using example of it's occurrence, but it has nothing specific to do with Piston, my question is about general pattern in Rust. So tag rust-piston is unrelated, please don't add it to the question.

1
Adding where <C as graphics::character::CharacterCache>::Error : std::fmt::Debug on the function that calls expect (and possibly other functions that call the first one) should solve the problem too. - Francis Gagné
@FrancisGagné but then this function wouldn't be usable unless I actually fix the libraries I'm using, and this question is exactly about whether I should do it - Max Yankov
Oh, I assumed the error types in question already implemented Debug. Nevermind then! - Francis Gagné

1 Answers

4
votes

Is it good practice to require associated Error types implement Debug trait?

Yes, when possible. Maybe they forget it.

A way to solve this problem is to use map_err(), here a MCVE of the problem:

struct Error;

fn foo() -> Result<(), Error> {
    Ok(())
}

fn main() {
    foo().expect("no error");
}
error[E0599]: no method named `expect` found for type `std::result::Result<(), Error>` in the current scope
 --> src/main.rs:8:11
  |
8 |     foo().expect("no error");
  |           ^^^^^^
  |
  = note: the method `expect` exists but the following trait bounds were not satisfied:
          `Error : std::fmt::Debug`

Use map_err() to produce an error that implement Debug, that could be your own custom Error, In the following exemple, I just return () as Error:

struct Error;

fn foo() -> Result<(), Error> {
    Ok(())
}

fn main() {
    foo().map_err(|_| ()).expect("no error");
}