4 ms·
I agree, it's tough to know when the right time to toss information away is, to simplify things for the caller. When in doubt, I tend to prefer "wrapper style"
by fwip 1y ago
I agree, it's tough to know when the right time to toss information away is, to simplify things for the caller.
When in doubt, I tend to prefer "wrapper style" errors for libraries, so the caller can match at whatever level of specificity they care about. As a toy example:
match read_config() {
Err(ConfigError(FileNotFound) => println!("No configuration file found. Supported config directories are: {}", get_config_dirs()),
Err(ConfigError(IOError(filename, msg))) => println!("Access error for config file {}: {}", filename, msg),
Err(ConfigError(ParseError(e))) => println!("Parse error: {:?}", e),
Err(ConfigError(e)) => println!("configuration error: {:?}", e),
Ok(config) => {...},
}
The calling application could start with just the generic error message at the end, and over time decide to add more useful behavior for some specific cases.
Of course, then the problem becomes "what are the useful or natural groupings" for the error messages.
- dwattttt 1y agoI did this with a moderate sized cli tool; it was really good to be able to see effectively every error state you could have at the top level of the program. Something I didn't find an ergonomic solution to though was pulling out common errors; I wanted to say, pull out any std::io errors that occurred at the top level, but all I found was to match and expand every error case to pull them out. I considered maybe a derive/trait based approach would work, but it was too big a hammer for that project.