Skip to content

A lint for diverging expressions in else-case to encourage early retuns (and similar) #13674

Open
@porky11

Description

@porky11

What it does

If you have a return/continue/break/panic or similar in an else case, it's often cleaner to use an early return/continue/break.

This also applies to turning if-let-else into let-else, if the else case always returns/continues/breaks.

I think it might even be one which can be enabled by default. I don't see any cases where it would be difficult to discover this, nor do I see any real drawbacks.

Advantage

  • less indentation/nesting
  • decreased complexity since else cases are closed
  • often considered better style

Drawbacks

Not everybody might prefer early returns.
At least a completely functional style might be preferable.
(but probably almost never a "return" in an else case only)

Maybe the if_not_else lint might be confusing when not handled in a good way.

Example

fn sum_smaller_than(numbers: &[usize], max: usize) -> Option<usize> {
    let mut sum = 0;

    for &num in numbers {
        if sum < max {
            sum += num;
        } else {
            return None;
        }
    }

    Some(sum)
}

Here's a diverging expression (return) in an else case.

The suggestion would usually be to negate the expression and switch the branches like this:

fn sum_smaller_than(numbers: &[usize], max: usize) -> Option<usize> {
    let mut sum = 0;

    for &num in numbers {
        if !(sum < max) {
            return None;
        } else {
            sum += num;
        }
    }

    Some(sum)
}

Then when following the other lints nonminimal_bool and redundant_else lints, we get this:

fn sum_smaller_than(numbers: &[usize], max: usize) -> Option<usize> {
    let mut sum = 0;

    for &num in numbers {
        if sum >= max {
            return None;
        }

        sum += num;
    }

    Some(sum)
}

Following the if_not_else lint would just revert it back, so it should be disabled if a redundant_else lint is discovered for the same lint (probably a separate issue, which is useful by itself).

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lintArea: New lints

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions