Skip to content
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

Add unwrap_unchecked() methods for Option and Result #80876

Merged
merged 4 commits into from
Jan 26, 2021

Conversation

ojeda
Copy link
Contributor

@ojeda ojeda commented Jan 10, 2021

In particular:

  • unwrap_unchecked() for Option.
  • unwrap_unchecked() and unwrap_err_unchecked() for Result.

These complement other *_unchecked() methods in core etc.

Currently there are a couple of places it may be used inside rustc (LinkedList, BTree). It is also easy to find other repositories with similar functionality.

Fixes #48278.

In particular:
  - `unwrap_unchecked()` for `Option`.
  - `unwrap_unchecked()` and `unwrap_err_unchecked()` for `Result`.

These complement other `*_unchecked()` methods in `core` etc.

Currently there are a couple of places it may be used inside rustc
(`LinkedList`, `BTree`). It is also easy to find other repositories
with similar functionality.

Fixes rust-lang#48278.

Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
@rust-highfive
Copy link
Collaborator

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.

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jan 10, 2021
@ojeda
Copy link
Contributor Author

ojeda commented Jan 10, 2021

A few extra bits:

  • I was not sure if this was considered a hole in the API (given we have other *_unchecked() methods, including one equivalent function for Option in btree) or perhaps an RFC is required.
  • I will add the tracking issue number if people want to see this in.
  • The Option one could be const, but it would require const_refs_to_cell for the assert. Since anyway it is not a high-priority use case, I left it non-const.
  • I assumed changing the couple of potential users in core etc. would be done later, so I didn't touch them here. Please let me know if it is the other way around.

@rust-log-analyzer
Copy link
Collaborator

The job mingw-check failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)
configure: rust.channel         := nightly
configure: rust.debug-assertions := True
configure: llvm.assertions      := True
configure: dist.missing-tools   := True
configure: build.configure-args := ['--enable-sccache', '--disable-manage-submodu ...
configure: writing `config.toml` in current directory
configure: 
configure: run `python /checkout/x.py --help`
configure: 

Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
@oli-obk oli-obk added the T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. label Jan 13, 2021
@scottmcm
Copy link
Member

perhaps an RFC is required

An RFC is generally not required for individual inherent method additions, unless they'd be setting a new pattern. Usually a method going in unstable like this just needs a code review and a "seems plausible" from a libs member. (Only stabilization requires the whole-team & FCP.)

I can't predict whether this is desired. It seems plausible, but one could also argue that .unwrap_or_else(hint::unreachable_unchecked) is fine.

@ojeda
Copy link
Contributor Author

ojeda commented Jan 14, 2021

An RFC is generally not required for individual inherent method additions, unless they'd be setting a new pattern. Usually a method going in unstable like this just needs a code review and a "seems plausible" from a libs member. (Only stabilization requires the whole-team & FCP.)

Yeah, I wasn't sure -- thanks for confirming & the explanation!

I can't predict whether this is desired. It seems plausible, but one could also argue that .unwrap_or_else(hint::unreachable_unchecked) is fine.

Indeed, I can see both angles. I think the major argument in favor is that even ourselves are writing things like:

pub unsafe fn unwrap_unchecked<T>(val: Option<T>) -> T {
val.unwrap_or_else(|| {
if cfg!(debug_assertions) {
panic!("'unchecked' unwrap on None in BTreeMap");
} else {
unsafe {
core::intrinsics::unreachable();
}
}
})
}

@scottmcm
Copy link
Member

scottmcm commented Jan 15, 2021

Yeah, I don't doubt that its semantics are handy.

Unfortunately a big downside is that debug_assert!s in core only actually run in the bors test suite -- a user calling this method would never see the debug assert fire, since core is always shipped in release. So if this is an extension method in a crate instead, it could be more helpful. (Maybe https://docs.rs/new_debug_unreachable/ could be interested?)

Hopefully one day that'll no longer be the case and these will be more useful again...

@Mark-Simulacrum
Copy link
Member

I feel that we should not add these, as they would encourage what is almost always an antipattern. The cases in which the UB actually improves performance in a manner that meaningfully affect the program overall are few, and it is not difficult to write this manually if necessary.

r? @m-ou-se for libs team member review

@ojeda
Copy link
Contributor Author

ojeda commented Jan 15, 2021

Unfortunately a big downside is that debug_assert!s in core only actually run in the bors test suite -- a user calling this method would never see the debug assert fire, since core is always shipped in release.

There are a few counter-points to that I can think of:

  • The method (as documented, at least) should not do the assert for users even if it could -- i.e. if a project wants to assert a particular condition on debug for their own testing, they can do so explicitly. That way, they can control the behavior in debug. Otherwise, it would be forced on them. I guess one could argue to also provide a macro that does the assert, though; that seems useful too.
  • Projects building their own core, e.g. kernels/embedded/freestanding, can still take advantage of them. This can be useful not just to avoid writing an assert on their side (they should still write it if they rely on it being there for some reason), but rather to validate that core is working as expected when compiling for their particular target etc. When working with such projects, every bit counts towards ensuring things are sane.
  • It is the same for other *_unchecked() methods we have.

I feel that we should not add these, as they would encourage what is almost always an antipattern. The cases in which the UB actually improves performance in a manner that meaningfully affect the program overall are few, and it is not difficult to write this manually if necessary.

I understand it is not a very common use case and the desire to steer newcomers to the most commonly used methods, but not providing useful methods just for that reason is not tackling the right problem. If one wants to avoid newcomers using certain methods, one should add a feature to put them in an "expert" section in the documentation, or something like that (e.g. in the same spirit of spotlight/notable_trait; we could have an expert label too); rather than making life difficult for other developers.

Furthermore, this is an unsafe method, which means it is already being flagged as "you should know what you are doing". That is to say: it is not like adding a particularly unsuited (e.g. slow), but ultimately safe operation to a data structure that users should avoid unless they know what they are doing.

In any case, like everything else (specially unsafe bits), it should be used judiciously. Having the method or not will not stop anyone determined enough to "improve" performance. In the end, Rust is a systems programming language, which means people is more likely to need this kind of functionality compared to other languages.

@m-ou-se
Copy link
Member

m-ou-se commented Jan 24, 2021

I think it makes sense to have these. Of course we'd want to steer people away from using the unchecked functions, but that's what unsafe is for. We also have get_unchecked on slices, even though a.get(i).unwrap_or_else(|| unsafe { unreachable_unchecked() }) would result in the exact same code.

Let's try out the unstable version to get some experience with this function. Then we can have a more informed discussion about whether we want to stabilize this later.

@ojeda Can you open a tracking issue for this?

Copy link
Member

@m-ou-se m-ou-se left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's link the reference about undefined behaviour:

library/core/src/option.rs Outdated Show resolved Hide resolved
library/core/src/result.rs Outdated Show resolved Hide resolved
library/core/src/result.rs Outdated Show resolved Hide resolved
@m-ou-se m-ou-se added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 24, 2021
Suggested-by: Mara Bos <m-ou.se@m-ou.se>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
@ojeda
Copy link
Contributor Author

ojeda commented Jan 25, 2021

Thanks @m-ou-se, done!

@m-ou-se m-ou-se added the A-result-option Area: Result and Option combinators label Jan 25, 2021
@m-ou-se
Copy link
Member

m-ou-se commented Jan 25, 2021

Thanks!

@bors r+ rollup

@bors
Copy link
Contributor

bors commented Jan 25, 2021

📌 Commit 01250fc has been approved by m-ou-se

@bors
Copy link
Contributor

bors commented Jan 25, 2021

🌲 The tree is currently closed for pull requests below priority 1000. This pull request will be tested once the tree is reopened.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 25, 2021
JohnTitor added a commit to JohnTitor/rust that referenced this pull request Jan 26, 2021
…d, r=m-ou-se

Add `unwrap_unchecked()` methods for `Option` and `Result`

In particular:
  - `unwrap_unchecked()` for `Option`.
  - `unwrap_unchecked()` and `unwrap_err_unchecked()` for `Result`.

These complement other `*_unchecked()` methods in `core` etc.

Currently there are a couple of places it may be used inside rustc (`LinkedList`, `BTree`). It is also easy to find other repositories with similar functionality.

Fixes rust-lang#48278.
bors added a commit to rust-lang-ci/rust that referenced this pull request Jan 26, 2021
Rollup of 14 pull requests

Successful merges:

 - rust-lang#80812 (Update RELEASES.md for 1.50.0)
 - rust-lang#80876 (Add `unwrap_unchecked()` methods for `Option` and `Result`)
 - rust-lang#80900 (Fix ICE with `ReadPointerAsBytes` validation error)
 - rust-lang#81191 (BTreeMap: test all borrowing interfaces and test more chaotic order behavior)
 - rust-lang#81195 (Account for generics when suggesting bound)
 - rust-lang#81299 (Fix some bugs reported by eslint)
 - rust-lang#81325 (typeck: Don't suggest converting LHS exprs)
 - rust-lang#81353 (Fix spelling in documentation for error E0207)
 - rust-lang#81369 (rustc_codegen_ssa: use wall time for codegen_to_LLVM_IR time-passes entry)
 - rust-lang#81389 (rustdoc: Document CommonMark extensions.)
 - rust-lang#81399 (Update books)
 - rust-lang#81401 (tidy: Some code cleanup.)
 - rust-lang#81407 (Refine "remove semicolon" suggestion in trait selection)
 - rust-lang#81412 (Fix assertion in `MaybeUninit::array_assume_init()` for zero-length arrays)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit fe6b3a9 into rust-lang:master Jan 26, 2021
@rustbot rustbot added this to the 1.51.0 milestone Jan 26, 2021
@ojeda ojeda deleted the option-result-unwrap_unchecked branch January 27, 2021 00:42
yvt added a commit to r3-os/r3 that referenced this pull request Jan 31, 2021
The `unwrap_unchecked` methods were recently added to the standard
library [1] and are yet to be stabilized.

[1]: rust-lang/rust#80876
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-result-option Area: Result and Option combinators S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Option::unwrap_unchecked
9 participants