rust-lang / rust-clippy

A bunch of lints to catch common mistakes and improve your Rust code. Book: https://doc.rust-lang.org/clippy/
https://rust-lang.github.io/rust-clippy/
Other
11.43k stars 1.54k forks source link

Suggest to use turbofish syntax instead of type hints #7081

Open thomaseizinger opened 3 years ago

thomaseizinger commented 3 years ago

What it does

Suggest to use turbofish syntax instead of type hints.

Categories (optional)

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

Type hints can get stale if the expression is modified / refactored and ends up returning a different type than what was originally returned.

Using turbofish syntax instead allows the compiler to continue with its type-inference and hence not require a type hint. Contrary to the type hint on the variable, the turbofish syntax is applied "locally" to where it is needed and therefore is more likely to stay relevant as the code around it changes.

Overall, I think this makes it easier to maintain Rust code.

Drawbacks

Some people may prefer to write type hints instead of turbo-fish syntax.

Examples

let numbers: Vec<_> = (0..10).collect();
let lucky_number: u64 = "42".parse().unwrap();

Could be written as:

let numbers = (0..10).collect::<Vec<_>>();
let lucky_number = "42".parse::<u64>().unwrap();
camsteffen commented 3 years ago

Some people

I am one of those people. I like to be able to glance at let lucky_number and see the type of the variable without compiling the code after it in my head. I also like to write code saying "This is the type I ultimately want, Rust will figure out the details for me." I also like how writing an expression that is returned by a function works in a consistent way - the type is just annotated by the function signature rather than the let.

But, my opinion aside, this could possibly be done as a restriction lint. But it would be very hard (impossible?) to implement since we would have to reverse engineer the rustc type checking process.

thomaseizinger commented 3 years ago

I like to be able to glance at let lucky_number and see the type of the variable without compiling the code after it in my head.

At least in IntelliJ Rust and rust-analyzer, inlay type hints solve this problem.

I also like to write code saying "This is the type I ultimately want, Rust will figure out the details for me." I also like how writing an expression that is returned by a function works in a consistent way - the type is just annotated by the function signature rather than the let.

I do see this argument although it is not my workflow at all. I almost never type let bindings myself but always start with the expression and use IDE assists like "Extract variable" or postfix completions like .let to end with Rust code that compiles.

From that perspective, I find it an annoyance if I have to modify the code that was created because it interrupts my flow, esp. if I am modifying the code and I end up with non-compiling code due to now stale let bindings.

But, my opinion aside, this could possibly be done as a restriction lint. But it would be very hard (impossible?) to implement since we would have to reverse engineer the rustc type checking process.

I am not too familiar with writing clippy lints. Could we start with a hard-coded list of types? Maybe only supporting simple expressions like .parse() could be a feature because they are easy enough to understand quickly.

camsteffen commented 3 years ago

It should be possible for simple cases at least where the generic function output is assigned directly, or maybe with one added method like unwrap. It would just be hard to implement in a way that covers all cases.

thomaseizinger commented 3 years ago

Okay, thanks for the confirmation.

I'll leave this open and see if there is further interest in it. I may also attempt to write it myself now that I've discovered https://github.com/trailofbits/dylint.