Replies: 5 comments 8 replies
-
‘Don’t particularly care what it is’ doesn’t necessarily mean ‘ok with any arbitrary value’. If I have configuration object with a timeout field, I don’t particularly care what the timeout is so long as it’s a sensible value that authors of the library considered a good default. |
Beta Was this translation helpful? Give feedback.
-
@Jarcho in the specific case that triggered this post I'll post a repro in a separate issue if necessary. Chose to make this post a "discussion" because it's really more about the semantics of Edit: posted #11631 |
Beta Was this translation helpful? Give feedback.
-
In general I feel like this argument would be a lot stronger if you had specific examples where you think clippy's suggestion is wrong/misguided, which IMO is usually the standard "false positives" get judged against.
In particular, how do you see this being applied? |
Beta Was this translation helpful? Give feedback.
-
It would be good to have specific failure cases to discuss. Are there types that really have |
Beta Was this translation helpful? Give feedback.
-
Every single time I see this warning, I have to disable it or rewrite code to avoid the suggestion because it makes the code worse. |
Beta Was this translation helpful? Give feedback.
-
Lint
unwrap_or_default
suggests replacing instances ofunwrap_or
and similar methods withunwrap_or_default
.This is a great change when the value or function (in the case of
_or_else
) being replaced isDefault::default
. However the lint appears to suggest replacing even constructors that have nothing to do withDefault
and merely happen to return the same value.I believe this is not only not a useful suggestion but a misleading one. It propagates the expectation of the "default" value being somehow special, even though there is no specification for what exactly that specialness might mean.
From
std::default::Default
:The purpose of the
Default
trait is to provide an arbitrary valid value. Almost every'static
type has at least one value that is valid regardless of context, so this is a very easy condition to satisfy, even when there is no particular reason to choose one value over others.By design, the trait says nothing at all about the value. It would be unusual, but not incorrect to return a randomly chosen value or even choose a different value on every call.
Contrast this with various
Zero
traits that return an algebraic zero, such thatx + 0 = x
. It is quite reasonable forDefault::default
to return this zero value, but the number of types that can implementZero
is much lower. (Besides, sometimes a type cannot implementZero
because there are two different relevant operations with two different zero values, yet either value would work perfectly well as the output ofDefault::default
.)The motivating example described by the
Default
trait is various configuration types. It is common for configuration to include options that only become relevant in rare, even exceptional circumstances.Default
allows explicitly deciding that those extra options don't matter.#[derive(Default)]
supports this design: in most cases it makes perfect sense to construct an arbitrary record by constructing arbitrary values for every field. On the other hand, it would have rarely been useful ifDefault::default
carried some special but not standardized and, more importantly, not composable semantics.Rust API Guidelines also support this design. They recommend implementing
Default
eagerly, among other default traits.Despite all this, the misunderstanding of
Default
as being required to produce some undefined blessed value is common and causes friction across the ecosystem. Numerous crates were published to circumvent the issue of upstream types not implementingDefault
.The most high-profile instance of this that I know of is
chrono
types not implementingDefault
, with the motivation of having no way to choose between multiple reasonable defaults, despite it being extremely common for aforementioned configuration types to include dates.I hope I made a convincing case for not expecting
impl Default
to mean more that it is supposed to. It should now be obvious that replacingT::new
withT::default
is incorrect in the general case, even if returned value is the same.Beta Was this translation helpful? Give feedback.
All reactions