-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
[wip] library: mark more functions that return String as #[must_use] #50462
Conversation
r? @shepmaster (rust_highfive has picked a reviewer for you, use r? to override) |
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
Could you provide some rationale for this change? I'm too lazy to look for it now, but I seem to recall there being discussions around why we shouldn't add |
Ah, I didn't not know about this discussion. The idea is, if a user uses code like let x = String::from("Hello world");
x.to_uppercase();
println!("{}", x); ,the These functions that return a new String should have their return value captured, otherwise the operation has no effect and might lead to confusion. |
src/liballoc/string.rs
Outdated
@@ -2142,6 +2150,7 @@ pub trait ToString { | |||
/// since `fmt::Write for String` never returns an error itself. | |||
#[stable(feature = "rust1", since = "1.0.0")] | |||
impl<T: fmt::Display + ?Sized> ToString for T { | |||
#[must_use] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The #[must_use]
attribute needs to be in the trait definition. It doesn't work when added to impls: #48486.
(Discussion issue for |
@shepmaster I have just recently seen an answer on Reddit which made this kind of mistake using |
I'd also prefer that the rationale go into the commit message. Commit messages that duplicate the diff are mostly useless because we can always look at the diff again; we can't look back at the author's rationale. I'd also recommend squashing the commits, once the review feedback is finished. |
sure, will do |
03b98d5
to
efe47ba
Compare
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
src/liballoc/string.rs
Outdated
@@ -11,7 +11,7 @@ | |||
//! A UTF-8 encoded, growable string. | |||
//! | |||
//! This module contains the [`String`] type, a trait for converting | |||
//! [`ToString`]s, and several error types that may result from working with | |||
//! [`ToString`]s, and several error types that may result from working withF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a typo snuck in.
@@ -689,6 +693,7 @@ impl String { | |||
/// assert_eq!(String::from("hello"), s); | |||
/// } | |||
/// ``` | |||
#[must_use] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd disagree with this one — this is used for FFI when passing back a decomposed String
to deallocate it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't the code be more readable if one is forced to use drop()
explicitly if the only intention is to deallocate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not in my opinion, no. Idiomatic Rust doesn't tend to use explicit calls to drop
frequently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am just a stranger here, but I have some experience with Python, which mantra is "explicit is better than implicit".
Idiomatic Rust doesn't tend to use unsafe blocks frequently, either. I would even say that explicitness is even more valuable in unsafe code.
src/liballoc/string.rs
Outdated
#[stable(feature = "string_to_string_specialization", since = "1.17.0")] | ||
impl ToString for String { | ||
#[inline] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not be changed.
@@ -1419,6 +1425,7 @@ impl String { | |||
/// assert_eq!(world, "World!"); | |||
/// # } | |||
/// ``` | |||
#[must_use] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function does have side effects (&mut self
) — why should the user need to care about the return value here? What should they use instead of ignoring the result?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I ignore the result of split_off
, it seems that I should better use truncate
, shouldn't I?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to customize the error message provided by #[must_use]
on a case-by-case basis to suggest that truncate
is more appropriate? Otherwise, should that go into the documentation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The attribute can take a string literal with an additional message: usage, output. (The output format may change soon.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one I like provided it has the message. It sets a nice "if it allows redirecting to a cheaper method" precedent (which, in retrospect, collect
is also following).
(Should probably be on Vec::split_off
too, though.)
@@ -418,6 +423,7 @@ impl str { | |||
/// | |||
/// assert_eq!(boxed_str.into_string(), string); | |||
/// ``` | |||
#[must_use] | |||
#[stable(feature = "box_str", since = "1.4.0")] | |||
#[inline] | |||
pub fn into_string(self: Box<str>) -> String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one feels insufficiently justified. It's not allocating. It consumes the input so if you didn't need it you'll probably know. It does almost nothing, so will probably disappear on its own if unused.
I agree that it could be must_use
, but as I understand it the goal isn't to put it everywhere possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why we should apply so hardly-defined rules to where must_use
should be used and where it shouldn't. I suggest the following reasoning: if the function call doesn't make sense without consuming the result, it should be marked with must_use
.
It does almost nothing, so will probably disappear on its own if unused.
Why does Rust warn about unused use
s then? They do nothing and just "disappear" completely if not used.
src/liballoc/string.rs
Outdated
@@ -378,6 +378,7 @@ impl String { | |||
/// ``` | |||
/// let s = String::new(); | |||
/// ``` | |||
#[must_use] | |||
#[inline] | |||
#[stable(feature = "rust1", since = "1.0.0")] | |||
pub fn new() -> String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one's another case of a trivial method where, sure, not using it isn't ideal stylistically, but it's just setting 3 pointers to constants, so overall I feel "meh".
Edit: Also, it's inconsistent for String::new to have it but not Vec::new.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, for now I removed #[must_use] from std::String::new()
|
I did this for a bunch of existing ones in #50511 |
efe47ba
to
42c4faf
Compare
If the return value (String) of the function is not used, the function call is technically in vain (unless there are side effects) and the entire function call could be ommitted. Warn about unused return values of -> String functions. Example code: let mut x = Sting::from("hello"); x.push_str(" world!"); x.to_uppercase(); println!("{}", x); will print "hello world!" instead of "HELLO WORLD!") because the result of .to_uppercase() is not caught in a variable. std::str::to_lowercase() std::str::to_uppercase() std::str::escape_debug() std::str::escape_default() std::str::escape_unicode() std::str::into_string() std::str::repeat() std::str::to_ascii_uppercase() std::str::to_ascii_lowercase() std::String::with_capacity() std::String::from_str() std::String::from_utf16_lossy() std::String::from_raw_parts() std::String::from_utf8_unchecked() std::String::split_off()
42c4faf
to
aa127d8
Compare
Ping from triage @shepmaster! The author pushed some new commits. |
This still WIP, I haven't had s lot of time in the recent days unfortunately. |
I made a separate pull request for Vec::new() and String::new() here: #50766 |
Marking as blocked on #48926. |
Ping from triage! Thanks for your PR, @matthiaskrgr. It looks like blocking issue / RFC will need some time before it is resolved, so we're closing this PR for now. Feel free to reopen it in the future. |
TODO: