I'm defining a customized error type using the crate thiserror. Below is an example.
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ParseRankError {
#[error("{0} is not a valid symbol for card rank!")]
InvalidSymbol(char),
#[error("{0} is not a valid integer for card rank!")]
InvalidInteger(u8),
}
My question is should I include the error type in the error messages? That is, should I do it the following way?
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ParseRankError {
#[error("ParseRankError::InvalidSymbol: {0} is not a valid symbol for card rank!")]
InvalidSymbol(char),
#[error("ParseRankError::InvalidInteger: {0} is not a valid integer for card rank!")]
InvalidInteger(u8),
}
No, it shouldn't. Display (which is what [error()] macro implements) is supposed to be for end users, and unless your application is for Rust programmers, the type shouldn't matter.
The Debug output is meant for programmers, and the default implementation already includes the type.
What if I want to print out the error message by myself? I have an interactive command-line application which handles user input. When an user enters invalid input, the Error is handled (as I don't want to terminate the interactive application). Basically, I print out the error message using eprintln! and allows the user to reenter information. I found that eprintln! does not include error type name by default. Is there a way to include the error type name when I want to print out the error message by myself?
Rather than trying to meticulously craft detailed error messages, I found it way more useful for debugging to include a stack trace in the error and print it when displayed. (Maybe only in the alternate representation, using the # flag.)
Another option is to use a library like log or tracing to dump your highly detailed error messages, and let stderr stick with the more user-friendly output.
It depends whether you use Debug ({:?}) to print the error or Display ({}). As mentioned by @kornel the default Debug implementation shows the concrete type while the Display implementation is meant for end users, therefore, usually does not include the type.
BTW Rust has no type reflection, i.e. type names are removed in the code, which means you can't request a type's name at runtime unless you coded it somewhere, e.g. in the default derive for the Debug trait.