-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Free default()
forwarding to Default::default()
#73001
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @Mark-Simulacrum (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
r? @dtolnay as this is an unstable addition to standard library surface so should get libs team attention. That said, speaking personally, I don't think this is a good move. I have usually found that uses of Default::default() are usually a poor choice in the long run -- I prefer |
When you need to be explicit about the type - I totally agree, you want For example, when changing a value of some of the fields in the struct:
I do not think it adds a lot of clarity if you repeat the type names twice:
|
I'd rather make (As for EDIT: There are existing issues for both of these features somewhere in this or the rfcs repo, but I can't find them right now. |
Yeah, I would prefer a language solution too I think :) I will also note that I think I've used the |
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 have high confidence that the language change will happen, as much as it would be better, so I am on board with landing this unstable.
We probably wouldn't stabilize until use Default::default;
is ruled out though.
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.
Thanks! I like this example code better.
Thanks for the review! Spent some time looking for existing proposals on extending the language to allow direct import of trait methods but did not find anything. Thought, language change would be a much, much larger time investment, also requiring more expertise. Not sure if I would be able to pull it off. |
229c95a
to
67f9a39
Compare
Since there is no RFC I will put in a couple of questions here. We have the following existing alternatives:
The existing syntaxes have the following benefit. Using an explicit type makes the code easy to read, when the explicit type is the "source" of the type, this becomes the best option. Even when the type would be redundant, it can, as a matter of taste, still be good code style. Instead of The The The drawback would be if you don't think this is good-looking or easy to understand code.
I wrote this so that we know the alternatives, so that they can be specifically addressed w.r.t stabilization of this. |
#[unstable(feature = "default_free_fn", issue = "73014")] | ||
#[inline] | ||
pub fn default<T: Default>() -> T { | ||
Default::default() |
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 is a nitpick I'd mention in any PR, but I guess it's extra strange now - here, why don't we prefer using the style T::default()
?
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 would like to stick with Default::default()
. The documentation of the function describes it as being equivalent to Default::default()
and this reinforces that, even if T::default()
would also be equivalent. It would be less clear for the documentation to describe the function as being equivalent to T::default()
because T::default()
has type T
while Default::default()
has a type that is filled in by inference.
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 guess I'm here because avoiding Default::default
is a pet peeve of mine, which in some way I must partly share with ilya-bobyr then. Since we say equivalent, any equivalent code would be fine, and I think we should prefer the style that we would like to see in Rust codebases around the ecosystem, hence T::default()
.
If the docs say Default::default
, maybe that could change now or in the future.
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.
Default::default()
was the first thing I thought about, as this is what I was trying to replace. If @dtolnay likes Default::default()
more here, I would just leave it.
@bluss In response to #73001 (comment): I don't disagree with anything in there but I don't see this as being a replacement for let zw = ZWriteData { key, ..default() }; When there are a lot (sometimes 100+) of these in a file it's reasonable to want to import Default::default, and the suggestions of |
When creating default values a trait method needs to be called with an explicit trait name. `Default::default()` seems redundant. A free function on the other hand, when imported directly, seems to be a better API, as it is just `default()`. When implementing the trait, a method is still required.
@bors r+ |
📌 Commit ebb8722 has been approved by |
Free `default()` forwarding to `Default::default()` It feels a bit redundant to have to say `Default::default()` every time I need a new value of a type that has a `Default` instance. Especially so, compared to Haskell, where the same functionality is called `def`. Providing a free `default()` function that forwards to `Default::default()` seems to improve the situation. The trait is still there, so if someone wants to be explicit and to say `Default::default()` - it still works, but if imported as `std::default::default;`, then the free function reduces typing and visual noise.
@bors rollup |
An usage example of default could be added to Vec::resize_with. |
Rollup of 10 pull requests Successful merges: - rust-lang#72026 (Update annotate-snippets-rs to 0.8.0) - rust-lang#72583 (impl AsRef<[T]> for vec::IntoIter<T>) - rust-lang#72615 (Fix documentation example for gcov profiling) - rust-lang#72761 (Added the documentation for the 'use' keyword) - rust-lang#72799 (Add `-Z span-debug` to allow for easier debugging of proc macros) - rust-lang#72811 (Liballoc impl) - rust-lang#72963 (Cstring `from_raw` and `into_raw` safety precisions) - rust-lang#73001 (Free `default()` forwarding to `Default::default()`) - rust-lang#73075 (Add comments to `Resolve::get_module`) - rust-lang#73092 (Clean up E0646) Failed merges: r? @ghost
Agreed. But maybe when the feature is stabilized? As David Tolnay (dtolnay) said: "I would prefer not to feature an unstable API so heavily in the doc of an extremely widely used trait." |
Yeah that should be a checklist item in the tracking issue. It can be done in the stabilization PR or a separate PR just beforehand. |
I've added an item to the tracking issue. |
|
ad 4. this user-defined alternative could be called #[derive(Default)]
struct Struct {
member1: u128,
member2: u128,
}
fn d<T:Default>() -> T {
T::default()
}
fn main() {
use Default as D;
Struct { ..Default::default() };
Struct { ..D::default() };
Struct { ..d() };
} |
It feels redundant to have to say
Default::default()
every time I need a new value of a type that has aDefault
instance.Especially so, compared to Haskell, where the same functionality is called
def
.Providing a free
default()
function that forwards toDefault::default()
could improve the situation.The trait is still there, so if someone wants to be explicit and to say
Default::default()
- it still works, but if imported asstd::default::default;
, then the free function reduces typing and visual noise.