-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Open
Labels
A-lintArea: New lintsArea: New lints
Description
What it does
Lints against uses of move
before a closure or async
block that captures nothing by reference.
Advantage
This is likely the result of a mistake from the implementer, which does not have the proper intuition about how closure borrow their contents. Sometimes it can be hard to reason about it.
For example the developer might not realise that a capture that is passed by value is always captured by value.
Drawbacks
No response
Example
let a = String::new();
let closure = move || {
drop(a);
};
Could be written as:
let a = String::new();
let closure = || {
drop(a);
};
Because the String is always captured by value, since it needs to be passed by value to drop
.
TennyZhuang, KisaragiEffective, farazdagi and Kinrany
Metadata
Metadata
Assignees
Labels
A-lintArea: New lintsArea: New lints
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
feat: needless_move lint
Span
of themove
keyword to the HIR. rust-lang/rust#117585needless_move
#11759Auto merge of rust-lang#117585 - dnbln:feat/move-kw-span, r=cjgillot
feat: needless_move lint
Auto merge of #117585 - dnbln:feat/move-kw-span, r=cjgillot
feat: needless_move lint
feat: needless_move lint
feat: needless_move lint
feat: needless_move lint
feat: needless_move lint
kpreid commentedon Nov 19, 2023
I think this is not a good principle to follow. A programmer should not be obligated to understand every nuance of the language's DWIM behaviors; they should be able to follow simpler principles which produce the right answer, where that does not harm readability, and
move
's behavior is simpler to describe (move/copy everything) than non-move
(borrow or move according to usage sites).Furthermore, this is at odds with reasonable consistency principles, like “always write
spawn(move || { ... })
, notspawn(|| { ... })
, because either it's necessary or it's moot”. I'd rather readthan
I understand that this is being implemented as a
pedantic
lint and therefore not enabled by default. Still, I think this goes beyond pedantic territory into “arguably the opposite of this is better” — it's putting a greater obligation on the programmer to comprehend every detail of their program and put it in a form that is only optimal in the direction of “fewer tokens”, not “clearer”. Readability and good style is not just about using fewer tokens.Please consider putting this in the
restriction
category (it even has an obvious possible opposite restriction lint, of "write all closures as move closures"), not adding it at all, or at least putting the lack of consistency as a documented caveat.feat: needless_move lint
feat: needless_move lint
feat: needless_move lint
dnbln commentedon Nov 20, 2023
When I initially added it, I wasn't sure of which category would fit it better, as it seems like a candidate for both
pedantic
as well asrestriction
, although I went withpedantic
because of the "lints which are rather strict" part in the description. I'd be happy with changing it torestriction
if it would be a better fit.sgued commentedon Nov 22, 2023
It definitely doesn't make sense as a warn by default lint.
Restriction seems fitting.
The use case that made me think of that was when trying to force a closure to not implement
Copy
to make sure it's not called twice (in addition to FnOnce).A case where this lint would trigger:
It compiles, but I initially expected it wouldn't.
If you replace
let _ =
withlet _a
it did what I expected it to do.Maybe this is more about
let _ =
and_ =
than about themove
keywordthinking about it. There could be a
suspiciouslint for closures that have reference something only through
let _ =or
_ = ` and therefore don't actually capture it.change category to `restriction`
feat: needless_move lint
change category to `restriction`
feat: needless_move lint
change category to `restriction`
feat: needless_move lint
change category to `restriction`