-
Notifications
You must be signed in to change notification settings - Fork 898
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
Flag for enforcing explicit 'return' keyword #4359
Comments
Thank you for the question @UebelAndre. No, there is no flag nor config option that will have rustfmt convert the last item to a return expression. Needless return expressions are generally considered to be bad style and non-idiomatic in Rust (there's even a Clippy lint that will warn on them). If you prefer to use utilize explicit return expressions within your code then you can certainly do so, and rustfmt will still happily format them. However, IMHO rustfmt should not be in the business of trying to change these expression types as part of style formatting, particularly to one that will cause clippy to emit warnings. |
@calebcartwright Thank you so much for your reply! 😃 I would agree that rustfmt should not start adding ways to fight clippy, however, I don't at all understand the known issue or the justification for why this is bad in the link you sent. Could you elaborate on those to help me understand this better? |
My understanding is that elision of the This convention comes from more functional languages where The rust book has some more insight on statements vs expressions: https://doc.rust-lang.org/reference/statements-and-expressions.html. |
I guess there's a question of whether rustfmt should do the reverse, ie convert terminating explicit returns into expressions. |
Yeah the lint description there isn't exactly detailed is it 😆 As @ayazhafiz noted, it really is more about convention, and like with any convention, there's not always explicit origin story or obvious explanation, but conventions arise nevertheless. The explanation @ayazhafiz shared is similar to what I've heard before elsewhere, and I've also found the avoidance of return expressions to be helpful in other places, like closures. |
TBH I wouldn't be too keen on trying to take that on for the same reason as the requested inverse in the OP, and I'd rather defer this to the developer. Obviously different story if our hand gets forced by the style guide or it becomes a popular ask from the community, but for now it just feels like it'd be another vector for bugs. |
I feel like the intention of the implicit return is great but the execution could be improved. There should be a way to write code that doesn't require the use of the
The mix of a |
Perhaps I am misunderstanding you here, but I feel like this is quickly getting off topic and really outside the scope of rustfmt anyway. Requests/suggestions for changes to the language itself need to be made elsewhere. rustfmt is just the code formatting tool.
fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
if rhs == 0 {
return false;
}
lhs % rhs == 0;
} Please take note that your snippet here is not the same as the book reference (you've added a semicolon to the last line making it a statement), and it actually will not compile because that path doesn't return a boolean value.
Again, not really sure what to make of this considering your snippet is invalid 😄 That trivial example from the book is simply illustrative, showing both usage of an early return as well as last-line expressions for implicit returns. There's a lot of alternative ways you could choose to write this example from the book, for example: fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
if rhs == 0 {
false
} else {
lhs % rhs == 0
}
} or fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
if rhs == 0 {
return false;
}
return lhs % rhs == 0;
} You're welcome to use any approach you prefer, but as discussed above, rustfmt isn't going to convert your code from one of those approaches to another; rustfmt will ensure that, whichever approach you prefer and use, it follows the formatting/style established by the Style Guide. |
My apologies, this is a typo, I copied the wrong snippet above and forgot to remove that but it looks like you understood what I was getting at with that.
This has shifted toward a discussion about the language and I can happily move the conversation. Before opening this ticket, it was unclear to me that the implicit return was "enforced" by |
A clippy warning does not qualify as enforcement. As noted above, it's convention and considered to be idiomatic to use an expression over an explicit return expression statement.
I understand your ask, but I just disagree. rustfmt's job is to ensure that any two programs parsed to the same AST are formatted the same way, in accordance with the style guide. It's not a design goal of rustfmt to support changing the AST structure while maintaining program logic. IMHO, rustfmt should not support allowing the conversion of last-line-in-block expressions to an explicit return expression statement because it is out of scope, the cons of effort/code/etc. outweigh any user preference, and the output from rustfmt would be flagged by clippy. I'm inclined to close this as |
This is for lack of a better word. It does appear that
It does seem you understand my ask but I think I fail to communicate that I also understand your responses. I completely agree with your stance on the responsibility of |
I really want to stress that there's not anywhere to go if you're looking for something that will rewrite your code from: fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
if rhs == 0 {
return false;
}
lhs % rhs == 0
} To a functionally equivalent alternative like: fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
if rhs == 0 {
false
} else {
lhs % rhs == 0
}
}
// Or
fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
if rhs == 0 {
return false;
}
return lhs % rhs == 0;
}
// Or
fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
match rhs {
0 => false,
_ => lhs % rhs == 0,
}
}
// Or... because which features of the language to use to implement logic is really left to the discretion of the programmer. Conventions/best practices/official approaches/etc. often stem from collective experience and wisdom around what the experts and community at large have found to be optimal, and how to best take advantage of the features provided by the language. It's stylistic in nature, but explicit return expression statements are similar here because they're redundant and don't take advantage of the expression oriented nature of the language (you may find https://users.rust-lang.org/t/explicit-and-implicit-return-in-functions/17089/5 helpful as well). There's other common/preferred stylistic conventions such as fn greet(user: Option<&str>) {
if user.is_some() {
let name = user.unwrap();
println!("Greetings {}", name);
} else {
println!("Hello world!");
}
} It's more conventional to leverage fn greet(user: Option<&str>) {
if let Some(name) = user {
println!("Greetings {}", name);
} else {
println!("Hello world!");
}
} Similarly to how you seem to prefer the explicit return expression statements, there's probably someone out there who stylistically would prefer the Conventions are just that, and folks can (and do) go against the conventions sometimes. However, you probably shouldn't be surprised that the official tools won't help you enforce anti-convention nor convert convention-following code to non-convention-following code. All that being said, if you'd like more info (or to challenge) clippy's needless return lint then the clippy repo (https://github.com/rust-lang/rust-clippy) would indeed be the place to do so. Lastly, if you'd like to suggest changes to Rust keywords/syntax/constructs/etc., then you'd need to follow the RFC process https://github.com/rust-lang/rfcs.
No, that's not what I said. What I said is that you're welcome to write in whichever style you prefer and rustfmt will format either, but that I view this type of conversion of the input code as out of scope. Additionally, as noted above, I don't think official tools should invest in support for converting from convention to anti-conventions, but your ask here is for rustfmt to do just that. The fact that clippy (the linting tool) warns about this is just another point of evidence that your ask is for something that goes against convention; clippy doesn't have any decision making authority over rustfmt and vice versa. Lastly, even in the absence of all the above issues, although rustfmt could probably implement the ask from a technical perspective, IMO it would add undo overhead to the rustfmt source and I suspect would likely be a source of bugs and idempotency issues in "real" code scenarios. |
Yeah, this is not the feature I was requesting.
But the alternatives you give here are awesome and satisfy my desire for the
So thank you so much for all the info and taking the time to explain everything to me 😄 |
Sure! Sounds like we've come to a logical resolution on this, so going to go ahead and close this issue. |
Is there a flag that would cause
rustfmt
to appropriately add an explicitreturn
keyword at the end of functions?Before:
After:
Diff:
The text was updated successfully, but these errors were encountered: