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

Suggest changing &mut Vec<_> parameters to &mut [_] when only slice methods are used. #6406

Closed
scottmcm opened this issue Nov 30, 2020 · 7 comments · Fixed by #8271
Closed
Labels
A-lint Area: New lints C-enhancement Category: Enhancement of lints, like adding more cases or adding help messages E-medium Call for participation: Medium difficulty level problem and requires some initial experience.

Comments

@scottmcm
Copy link
Member

scottmcm commented Nov 30, 2020

This mistake comes up fairly frequently on URLO, such as
https://users.rust-lang.org/t/iterators-vs-index-loops-performance/52131?u=scottmcm
https://users.rust-lang.org/t/we-all-know-iter-is-faster-than-loop-but-why/51486/3?u=scottmcm

What it does

  • For a free function or inherent method that takes &mut Vec<_> or &Vec<_> [ed: the &Vec<_> one already exists]
  • But only uses it via its deref to slice (len, iter_mut, etc)
  • Suggest changing the parameter to a slice instead

Categories (optional)

  • Kind: perf & style both seem appropriate

What is the advantage of the recommended code over the original code

  • More general in what it accepts, as one can pass sub-slices of Vecs instead of only being able to pass entire ones
  • Faster, because LLVM optimizes it better when it doesn't have to do the extra hop)
  • Clearer, because it makes it obvious that you're not changing the length of the passed Vec

For example:

  • Remove bounce checking inserted by ...
  • Remove the need to duplicating/storing/typo ...

Drawbacks

None.

Example

fn use_for(vec: &mut Vec<usize>) {
    for i in 0..vec.len() {
        vec[i] = i;
    }
}

Could be written as:

fn use_for(vec: &mut [usize]) {
    for i in 0..vec.len() {
        vec[i] = i;
    }
}
@scottmcm scottmcm added the A-lint Area: New lints label Nov 30, 2020
@Volker-Weissmann
Copy link

I think its better if clipyy suggests using an iterator over the Vector. Changing a vec to an array might involve more code change than chaning a loop to an iterator.

@scottmcm
Copy link
Member Author

Note that I'm not suggesting an array here, but a slice -- which is what code like .len() on a Vec is actually already using.

clippy will already suggest replacing the indexing with .iter_mut().enumerate(), but even with that change the parameter type should still change.

@Volker-Weissmann
Copy link

Ok. But I think that proposing .iter_mut().enumerate() is better than proposing taking a slice, because the latter is probably the bigger change.

@scottmcm
Copy link
Member Author

I see this as a both, not an either-or.

I totally agree that

fn use_for(vec: &mut Vec<usize>) {
    for i in 0..vec.len() {
        vec[i] = i;
    }
}

should change to

fn use_for(slice: &mut [usize]) {
    for (i, x) in slice.iter_mut().enumerate() {
        *x = i;
    }
}

But this issue is just about one part. They're separable.

@ebroto
Copy link
Member

ebroto commented Nov 30, 2020

@Volker-Weissmann it does not require a change other than the type of the function parameter:

fn use_for(vec: &mut [usize]) {
    for i in 0..vec.len() {
        vec[i] = i;
    }
}

fn main() {
    let mut v = vec![1, 2, 3, 4, 5];
    use_for(&mut v);
}

(playground)

You can see in the playground too that Clippy will already suggest .iter_mut().enumerate().

EDIT: @scottmcm beat me to it :)

@flip1995 flip1995 added C-enhancement Category: Enhancement of lints, like adding more cases or adding help messages E-medium Call for participation: Medium difficulty level problem and requires some initial experience. labels Dec 2, 2020
@flip1995
Copy link
Member

flip1995 commented Dec 2, 2020

Clippy already suggests changing &Vec<..> to &[..]: ptr_arg

But it intentionally doesn't lint &mut args. We could start linting those to with the check for only-slice-methods.

@scottmcm
Copy link
Member Author

scottmcm commented Dec 4, 2020

Thanks, @flip1995 -- I hadn't checked that one. I've edited the OP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: New lints C-enhancement Category: Enhancement of lints, like adding more cases or adding help messages E-medium Call for participation: Medium difficulty level problem and requires some initial experience.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants