-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Description
What it does
Passing a reference to a value instead of the value itself to the format!
macro causes unneeded double referencing that is not compiled away, as described in my stackoverflow question, and demonstrated in the 1.69 assembly output. The issue seem to be that reference format dispatch is not inlined by llvm. While this might be some issue with the Rust compiler itself, or an issue that is hard/impossible to solve in a general case, I think we could introduce a lint in the mean time to suggest it to improve readability and performance.
Lint Name
unneeded_format_arg_ref
Category
No response
Advantage
- Improve runtime performance
- Remove unneeded value referencing
- Allow variable inlining, e.g.
format!("{}", &var)
-->format!("{var}")
Drawbacks
Uncertain if there could ever be an edge case where formatting &var
and var
would produce different result, e.g. if format wants to print the address of a variable?
Example
format("{}", &foo.bar)
Could be written as:
format("{}", foo.bar)
Activity
nyurik commentedon May 31, 2023
Performance update: I consistently see a ~5% performance difference in a small benchmark.
disco07 commentedon May 31, 2023
Hello for your problem, I wish to work on this subject. Is it possible? If yes, have you some suggestions to give me?
Alexendoo commentedon May 31, 2023
For a plain binding yeah you wouldn't be able to do
{:p}
if you remove the&
for many types. Technically it could be the case for the other formatting traits too thatT
has a different impl compared to&T
, or no impl at all onT
Another thing to watch out for would be
!Sized
types e.g.&v[..]
&*x
wherex
derefs to something likestr
nyurik commentedon May 31, 2023
@Alexendoo thanks, good points. I am unclear about the last one -- all of these seems to work identically:
The rest of it could be added as unit tests -- these should not trigger the lint:
nyurik commentedon May 31, 2023
@disco07 go for it! See https://doc.rust-lang.org/nightly/clippy/development/adding_lints.html as a good starting point
Alexendoo commentedon May 31, 2023
e.g. only the last
println
here will compile https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ad20abfd2b21dbd4b77845b28f029d9amaxammann commentedon May 31, 2023
Actually only the 3rd one will not compile. But same point :)
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=2b3c6557c6d6f24c93fae05110331a7f
Alexendoo commentedon May 31, 2023
If you change the code to something else... yes
The other two cases still change the behaviour though in that example and so shouldn't be suggested
maxammann commentedon May 31, 2023
Ah oke sorry, now I got your point :)
&v
instead ofv
arg informat!
does not inline, causing ~6% perf hit rust-lang/rust#112156nyurik commentedon Jul 19, 2024
Is there ever a case
format!("{var:p}")
has any meaning? Or it must always use&var
? If so, it may mean that there is no code out there that compiles it, and therefor the format! macro could be improved to auto-ref on:p
?Alexendoo commentedon Jul 19, 2024
It makes sense when
var
is already a reference or pointer, it would be the difference of printing the address stored invar
and printing the address ofvar
nyurik commentedon Jul 19, 2024
I somehow feel this is almost never the case... to the point of perhaps creating a lint that flags
format!("{var:p}")
as likely being incorrectAlexendoo commentedon Jul 19, 2024
When would you want to print the stack address of a pointer rather than the pointer itself?
nyurik commentedon Jul 19, 2024
I don't think you ever would... thus my point that
{var:p}
is almost always pointless... Maybe we should submit this as a 2024 edition change - to always treat"{var:p}"
as"{:p}", &var
, and if someone wants to print the address of the address of the var, they will just have to write it explicitly with&&var
?Alexendoo commentedon Jul 19, 2024
It's the other way around,
&var
would print the stack addressRollup merge of rust-lang#127980 - nyurik:compiler-refs, r=oli-obk
Rollup merge of rust-lang#127980 - nyurik:compiler-refs, r=oli-obk
Rollup merge of rust-lang#127984 - nyurik:src-refs, r=onur-ozkan
Auto merge of #17641 - nyurik:optimize-refs, r=Veykril
Unrolled build for rust-lang#127984
Unrolled build for rust-lang#127980
Auto merge of rust-lang#17641 - nyurik:optimize-refs, r=Veykril
Auto merge of rust-lang#17641 - nyurik:optimize-refs, r=Veykril