For example, if your errors are:
enum RispError {
/// Syntax error returning line number and char
SyntaxErr(u32, u32),
/// Parens not balanced; contains number of parens needed
UnbalancedParens(usize),
}
You can impl ToString straight away: impl ToString for RispErr {
fn to_string(&self) -> String {
match self {
RispErr::SyntaxErr(l,c) => format!("syntax error at line {}, col {}", l, c),
RispErr::UnbalancedParens(n) => format!("use your % key more! add {} more paren", n),
}
}
}
Then, when handling the error, you can match do_thing() {
Ok(v) => { ... },
Err(e) => { // TODO handle error
println!(e)
}
}
where do_thing's signature looks like fn do_thing(...) -> Result<T, RispErr>;
It takes the same amount of code, but all your error messages are in the same place, you haven't lost information about them, and refactoring to handle them becomes super easy.(n.b. I dashed this comment off without actually compiling the above, so please forgive any dumb errors =] )
[1] https://doc.rust-lang.org/std/string/trait.ToString.html
http://www.lispworks.com/documentation/HyperSpec/Body/f_cerr...
http://www.lispworks.com/documentation/HyperSpec/Body/m_rst_...
I gotta get to sleep, but will either update the post or add a note in the morning.
And of course, will do this in all future rust projects :D
See here: https://github.com/omarabid/rust-starter/blob/master/src/mai...
In the cases where I do want to distinguish between error cases, I'd still rather wait until I have the code consuming those error enums to help guide what errors are meaningfully different - evidenced by needing different error handling paths - instead of making every caller decide which of the dozens or hundreds of edge cases they want to be handled which way(s).
There are cases where your approach of distinguishing cases up front would be better - as an example, if you're limited in your ability to refactor due to the interface being part of a public API with semver restrictions to your refactoring - but there's plenty of cases where the author's approach is the correct one, where you should be cringing if you don't see things kept as simple as RispErr.
(Or maybe it's just a generic irony ... I can't tell yet.)
This sounds quite cool -- if you have the time, would you mind giving me a quick example? Want to make sure I have a full understanding of what you mean.
To be helpful to readers of this comment and not just critical of the author, I recommend you don't overthink your error types when you're first starting to write your program. Think of the contents of the enum like a "scratchpad" where you list every failure mode you've encountered so far. While you're still developing, you can greedily match on every variant in your match statements, and it's fine. As you do this, you'll begin to notice themes that will inform the eventual refactor. Best of all, once you do refactor, you won't have to re-understand your code to tease out the various kinds of failures - you'll already have a list of them!