Skip to content

Suggest using unwrap_or_default() instead of unwrap_or(<default>) #9436

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

Closed
wants to merge 2 commits into from

Conversation

xphoniex
Copy link
Contributor

@xphoniex xphoniex commented Sep 7, 2022

Closes #9435

changelog: [or_fun_call]: Suggest using unwrap_or_default() instead of unwrap_or(<default>)

@rust-highfive
Copy link

r? @giraffate

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Sep 7, 2022
@xphoniex xphoniex changed the title Use unwrap or default Suggest using unwrap_or_default() instead of unwrap_or(<default>) Sep 7, 2022
@xphoniex
Copy link
Contributor Author

xphoniex commented Sep 7, 2022

r? @flip1995

@rust-highfive rust-highfive assigned flip1995 and unassigned giraffate Sep 7, 2022
@xphoniex xphoniex changed the title Suggest using unwrap_or_default() instead of unwrap_or(<default>) Suggest using unwrap_or_default() instead of unwrap_or(<default>) Sep 7, 2022
@matthiaskrgr
Copy link
Member

matthiaskrgr commented Sep 7, 2022

I don't like this because it ads an unnecessary layer of abstraction to the code without benefit.

@bors
Copy link
Contributor

bors commented Sep 8, 2022

☔ The latest upstream changes (presumably #9447) made this pull request unmergeable. Please resolve the merge conflicts.

@fhartwig
Copy link
Contributor

I think using unwrap_or(specific_value) is generally better than unwrap_or_default() because it's clearer and doesn't require the reader of that line to know what the default value of the relevant type is.

@xphoniex
Copy link
Contributor Author

I don't like this because it ads an unnecessary layer of abstraction to the code without benefit.

By "layer of abstraction", do you mean syntax-wise or is there a performance penalty when using unwrap_or_default

@xphoniex
Copy link
Contributor Author

I think using unwrap_or(specific_value) is generally better than unwrap_or_default() because it's clearer and doesn't require the reader of that line to know what the default value of the relevant type is.

Makes sense. But then, why do we have a unwrap_or_default in the first place?

@xphoniex
Copy link
Contributor Author

Hey @erickt , I went through the history and it seems like you're the one who introduced unwrap_or_default syntax. (Correct me if I'm wrong)

Would you care to comment on this?

@afetisov
Copy link

afetisov commented Oct 6, 2022

unwrap_or_default can cause issues with type inference, because previously the type was determined by the inner expression.

For primitives, this also looks needlessly complex and obfuscated. The .unwrap_or(0) is shorter, specifies the type (so no inference errors) and is explicit about the value. While the default 0: uN is simple, it's one more thing to remember, and doesn't carry its weight for this simple expression.

It also seems that the lint performs constant evaluation (i.e. folds .unwrap_or(FOO) to .unwrap_or(0) and lints it). This is just wrong. The entire point of constants is to abstract away the specific value, so that it can easily be changed later, and to give that value a clear and meaningful name in the current context. This lint violates both of those goals.

Finally, I expect this to create a lot of churn, so if added, this lint must be restriction or pedantic.

@erickt
Copy link
Contributor

erickt commented Oct 6, 2022

I agree with @afetisov. If I remember correctly, I added unwrap_or_default a long time before 1.0, back when we were just feeling out how APIs would work with traits. Nowadays after reading a lot of rust code I’m not sure if it’s really saving reducing that much cognitive load, and I can’t remember ever actually using it.

@afetisov
Copy link

afetisov commented Oct 6, 2022

I don't have an issue with unwrap_or_default when it's used for complex types, and the type is clear for the context (foremost to preserve type inference). For example, I don't think the explicit type expression adds anything in this case:

let map: HashMap<u64, String> = make_map();
let s = map.get(idx).unwrap_or_else(String::new);

The expression is more complex, you need to remember to use unwrap_or_else instead of unwrap_or and to pass a function (otherwise Clippy will somewhat reasonably complain). If you change the type of values from String to Vec<Stuff>, then you need to change the default value expressions for no good reason, and if you use Default::default as that expression, then it just unwrap_or_default but longer and clunkier.

But the for primitive types an explicit initializer is much more clear.

@flip1995
Copy link
Member

flip1995 commented Oct 23, 2022

@xphoniex As we talked about this before (I think in DMs?), I agree with all the others here: unwrap_or_default doesn't really make sense with primitives. Just writing the primitive in unwrap_or(0) is shorter and contains more information. In addition to all the other arguments that were brought up here.

The reason this lint exists for more complex types is the exact reason @afetisov brought up in the above comment: #9436 (comment)

We can add an extra lint that just lints this for primitives. But then again, I don't see who would use a lint like that.

So I'm strongly leaning towards not merging this PR.

@xphoniex
Copy link
Contributor Author

Thanks everyone for the input, I'm closing this PR.

@xphoniex xphoniex closed this Oct 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Using unwrap_or_default() in place of unwrap_or(<default>)
9 participants