Description
Feature tracking issue: rust-lang/rust#53667
Should we introduce a new guideline for wrapping let-chains?
The rationale is that let-chains allow let
bindings to be anywhere in a line of code. let
is no longer consitently at the left side. It is good for let
bindings to stand out and be easy to discover since they introduce new variables for the following scope. Oftentimes when reading code, I look backwards with the question "where did this variable come from?"
Possible answers
-
No change. Wrap
let
expressions the same as any other expression. -
Always wrap
let
expressions.let
is only ever preceded by one token in the same line:if
,while
,&&
,||
, etc. -
Wrap
let
expressions if they begin N characters or more past the current indentation.For example, a
let
-expression may be on the same line if it is 15 characters from the left margin. If it is 16 characters from the left margin, it must break to the next line. -
Wrap
let
expressions if there are 2 (?) or morelet
expressions in the condition -
Allow
single_identifier && let
on one line (if it fits line length limits), but require a line break before the&&
for any other expression. Always wrap after a let expression.
Potential concerns for each answer
- The introduction of
x
may be hard to find in this case:if my_long_condition(foo, bar, baz) && some_more && let Some(x) = foo() { // lots of code... use_x(x);
- Wrapping for this case seems a little unnecessary since it only shifts
let
leftward by one character:if a && let Some(b) = foo() {
- Added complexity to formatting logic. Difficult to follow/verify the guideline without automated tooling. The subtlety of the logic may be surprising to users.
- This case is suboptimal (similar to 1):
if my_function(Some(get_thing()), variable, and_another) && let Some(x) = foo() {
Other considerations
The rules for if
and while
will be the same.
If a let
expression wraps, it will cause all of the &&
or ||
-separated expressions to be on separate lines.
if something
&& let Some(x) = foo() && something_else { // bad - `&& something_else` should be on its own line
If there is just one let
binding at the beginning, the condition may be on one line:
if let Some(foo) = do_something() && another_condition {