Skip to content

Wrapping rules for let-chains? #169

Open
@camsteffen

Description

@camsteffen

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

  1. No change. Wrap let expressions the same as any other expression.

  2. Always wrap let expressions. let is only ever preceded by one token in the same line: if, while, &&, ||, etc.

  3. 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.

  4. Wrap let expressions if there are 2 (?) or more let expressions in the condition

  5. 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

  1. 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);
  2. Wrapping for this case seems a little unnecessary since it only shifts let leftward by one character:
    if a
        && let Some(b) = foo()
    {
  3. Added complexity to formatting logic. Difficult to follow/verify the guideline without automated tooling. The subtlety of the logic may be surprising to users.
  4. 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 {

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions