-
Notifications
You must be signed in to change notification settings - Fork 378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Idiom: Prefer Guard Clause over Nested Conditionals #62
Comments
My preference is to use fn read_config4() -> Result<Config, Error> {
let file = File::open("program.cfg")?;
let mut buf_reader = BufReader::new(file);
let mut contents = String::new();
// Correct use of Guard Clause
buf_reader.read_to_string(&mut contents)?;
let mut data: Vec<u8> = vec![];
for item in contents.
split("\n").
map(|s| s.to_string()).
filter(|s| !s.is_empty()) {
let num = item.parse::<u8>();
data.push(num?);
}
Ok( Config { data: data } )
} This makes the code much easier to read. For cases where it's not possible to use fn read_config4() -> Result<Config, Error> {
let file = File::open("program.cfg");
// Correct use of Guard Clause
let f = match file {
Ok(f) => f,
Err(_) => { return Err(Error::ConfigLoadFail); }
};
// We don't always need guard clauses.
if buf_reader.read_to_string(&mut contents).is_err() {
return Err(Error::ConfigLoadFail);
}
...
} |
I'm not sure handling assignment during the guard condition qualifies as a guard clause. Typically a Guard is at the forefront and indicates the alternate path that is handled before the safe assignment occurs. That's one reason why I didn't include kennytm's great acceptable use of let f = file.map_err(|_| Error::ConfigLoadFail)?; I think this is beautiful and acceptable for being preferred over nested conditionals, but I don't consider this a Guard Clause anymore. Yes I would openly advise this kind of usage, but I still firmly believe a Guard Clause would be far more beneficial to the language for two reasons:
I believe the term Guard Clause would better be defined as “A pre-assignment condition check with an explicit return. The purpose of which provides first and foremost continued type/condition safe code execution in the same scope. And secondly for code clarity and readability.” These terms are more generic for any language including non-typed languages. I'm looking forward to Rust enabling Pattern Matching after Guard Clause where leanardo described it as enabling True Flow Typing.
|
if buf_reader.read_to_string(&mut contents).is_err() {
return Err(Error::ConfigLoadFail);
} I consider that a Guard Clause. |
I had written on RFC to add Flow Typing to allow guard clauses to handle one enum path within scope but that got rejected. I go into much more detail about Guard Clauses there: rust-lang/rfcs#2221 |
Without True Flow Typing this practice isn't as convenient. It still stands true that it's a much better pattern to help new developers write simpler and more composable code. So I'll close this issue as it will still be hear for educational purposes but fundamentally needs Rust to make a step towards simplifying the language so we can all simplify our code for better readability. |
Guard Clause
I'm taking my inspiration from Ruby for this one.
First I'll provide three examples of the wrong way to do it. These are overly nested and trying to follow the paths or guess with else belongs to what can be confusing at a glance. These examples are a simple file config parse
Wrong (A)
Wrong (B)
Wrong (C)
And here is the correct usage of a Guard Clause which allows us to avoid deeply nested logic.
Correct
If you'd like to test the examples above I have a working gist here: danielpclark/guard_clause_rfc.rs … you just need to create the config file with the contents of
"1\n2\n3\n"
.Having your code implemented with guard clauses adds a huge benefit for code clarity and avoids having your conditionals carry your code too far and deep to the right.
Improvements for Guard Clause is currently in Pre-RFC as I would like to avoid using
unwrap()
after a Guard Clause.The guard clause doesn't have to be strictly for an
Error
alternate return type. I believe it can apply for any time when there are two conditional paths and one of those paths is nothing but a return type.The text was updated successfully, but these errors were encountered: