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 unsafe Option::unwrap_unchecked() #1095

Closed
wants to merge 1 commit into from

Conversation

dschatzberg
Copy link

No description provided.

bike-shedding). It is implemented quite simply by using the
`unreachable` intrinsic to indicate that the `Option` cannot be `None`
and then calling `unwrap()`. I expect that the compiler can them
optimize out the conditional. A prototype implement can be found
Copy link
Contributor

Choose a reason for hiding this comment

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

Have you verified that the compiler does in fact optimize it away?

Copy link
Author

Choose a reason for hiding this comment

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

This is dependent on a lot of different cases. If I build a library as follows:

#![feature(core)]

use std::intrinsics;

pub fn my_unwrap(o: Option<i32>) -> i32 {
    match o {
        Some(v) => v,
        None => panic!("panic")
    }
}

pub unsafe fn my_unwrap_unsafe(o: Option<i32>) -> i32 {
    match o {
        Some(v) => v,
        None => intrinsics::unreachable()
    }
}


$ rustc -O --crate-type=lib unwrap.rs
$ objdump -d libunwrap.rlib
0000000000000000 <_ZN16my_unwrap_unsafe20h8f4545557bc4e296MaaE>:
   0:   48 c1 ef 20             shr    $0x20,%rdi
   4:   89 f8                   mov    %edi,%eax
   6:   c3                      retq   

You can see no conditionals in the unwrap_unsafe asm. Further testing on the actual standard library implementation would be needed to confirm, but at least one method of implementing it seems to work as I expect.

@seanmonstar
Copy link
Contributor

Other possible alternative: If we added branch weights, such as llvm.expect, we could expect the Some case, which would help the compiler to make it the fast case.

@reem
Copy link

reem commented Apr 30, 2015

One benefit of adding this is that it would allow stable users to (unsafely) express unreachability without needing the unstable intrinsics API.

@Gankra
Copy link
Contributor

Gankra commented Apr 30, 2015

I've definitely wanted this before for expressing the invariants in data structures (stuff like "if I'm at this point in the program the root/parent must not be null"). Not for any particularly profiled reason, though. Just a vague sense of "I don't like having the code think it can panic here".

However if the intrinsic was properly exposed I believe this could just be written as foo.unwrap_or_else(intrinsics::unreachable). This is easy for someone to make a function/extension trait for if they want better semantics. As such it seems like a very minor ergonomic benefit to expose a dedicated method for.

@brson
Copy link
Contributor

brson commented May 5, 2015

I'm interested to see specific code in std where this optimization helps.

@dschatzberg
Copy link
Author

@brson How is what you're asking different from what is already in the RFC? The example I provided is from std.

@tbu-
Copy link
Contributor

tbu- commented May 6, 2015

You can also use .unwrap_or_else(|| intrinsics::unreachable())

@alexcrichton alexcrichton added the T-libs-api Relevant to the library API team, which will review and decide on the RFC. label May 14, 2015
@SimonSapin
Copy link
Contributor

As far as I can tell this can be done in a library outside of std, with the only downside that you’d have to use a trait where you use it.

@tbu-
Copy link
Contributor

tbu- commented May 28, 2015

@SimonSapin That can be said for all things in the standard library. :)

@bluss
Copy link
Member

bluss commented May 28, 2015

I actually think the explicit match is desireable. It would be much better if we suggested this pattern:

let inner_value = match opt {
    Some(x) => x,
    None => debug_assert_unreachable("This is a bug"),
};

I.e. we encourage the user to check their assumptions in the code with debug assertions, this particular macro or function after reem's model would behave like debug_assert!() in debug builds and be the unreachable intrinsic in release builds.

@tbu-
Copy link
Contributor

tbu- commented May 29, 2015

@bluss One could make a functions which does exactly this to encourage the pattern. :)

@Gankra Gankra self-assigned this Jun 5, 2015
@alexcrichton alexcrichton added the final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. label Jun 10, 2015
@alexcrichton
Copy link
Member

This RFC is now entering the final-comment-period for one week.

@alexcrichton
Copy link
Member

I personally see this as a minor convenience that doesn't necessarily pull its weight as a method, I'd prefer either @tbu-'s or @bluss's suggestion which would involve stabilizing this form of "unsafe unreachable" in a different manner.

@SimonSapin
Copy link
Contributor

I'd prefer either @tbu-'s or @bluss's suggestion which would involve stabilizing this form of "unsafe unreachable" in a different manner.

Isn’t that std::intrinsics::unreachable?

@alexcrichton
Copy link
Member

@SimonSapin yeah, I was just thinking that we'd want to pursue stabilizing that intrinsic (in a different location) instead of stabilizing a one-off method on Option.

@hanna-kruppe
Copy link

I am unconvinced that I'd even want to do this optimization at all. It's such a tiny gain (avoids a single, trivially predictable branch), and the consequences for getting it wrong (i.e., the value being None) are pretty dire, up to and including interpreting arbitrary bits as as pointer. That's a pretty terribly ratio of potential danger to potential benefit.

I am even less convinced that this optimization needs to be codified in a method in std, especially when it's trivial to express otherwise on nightly. I don't think there is any pressing need to get the possibility of this optimization into stable: There are already many unstable optimizations (e.g., various collection APIs, other intrinsics) that are far more widely applicable, and unreachable will be stabilized in some form or another at some point in the future. If anyone wants this optimization on stable, working to stabilize std::intrinsics::unreachable would probably be more effective as @alexcrichton already said.

I'd appreciate hard data (i.e., well-done benchmarks) showing a measurable performance gain in any non-pathological code --- ideally, a real library or application. But even with that I'd be inclined to say "well that's nice but you can do the same thing yourself, so why bake it into std for all eternity?"

Overall, 👎

@reem
Copy link

reem commented Jun 10, 2015

Also of note: you can now have an unreachable optimization hint in stable code through the unreachable crates.io crate, which provides the same interface as std::intrinsincs::unreachable but doesn't need any unstable code.

@SimonSapin
Copy link
Contributor

the unreachable crates.io crate

Uh, that looks crazy magic to me. Does the complier really eliminate branches that cause transmuting to Void? Reliably?

@reem
Copy link

reem commented Jun 10, 2015

@SimonSapin it works because rustc emits an unreachable hint after all calls to diverging functions.

@bluss
Copy link
Member

bluss commented Jun 10, 2015

@SimonSapin rustc's part of the magic is this, it simply emits unreachable when matching an empty enum:

fn unreachable(v: Void) -> ! {
    match v { /* empty */ }
}

@SimonSapin
Copy link
Contributor

I see, thanks for the explanation!

@alexcrichton
Copy link
Member

Thanks again for the RFC @dschatzberg! The consensus of the library subteam is to not merge this RFC at this time due to the worries about composability and how stabilizing an unreachable-like function in the standard library (or using @reem's crate) may be the best way to go here.

@dschatzberg
Copy link
Author

Thanks for the response, @alexcrichton. Could you clarify what the worries about
composability are?

@alexcrichton
Copy link
Member

Ah it's what I meant in a previous comment about how an unreachable function of some form would be more composable instead of only having this method on Option itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. T-libs-api Relevant to the library API team, which will review and decide on the RFC.
Projects
None yet
Development

Successfully merging this pull request may close these issues.