Skip to content
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

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

Open
porky11 opened this issue Nov 10, 2024 · 0 comments
Labels
A-lint Area: New lints

Comments

@porky11
Copy link

porky11 commented Nov 10, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: New lints
Projects
None yet
Development

No branches or pull requests

1 participant