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

There's no clean way to move a value into an Option and get a reference to the value. #29203

Closed
canndrew opened this issue Oct 21, 2015 · 6 comments

Comments

@canndrew
Copy link
Contributor

I need to mutate an Option in place, setting it to Some(x), then get a reference to x. The only way to do this is:

*my_opt = Some(x);
let r = match *my_opt {
    Some(ref x) => x,
    None => unreachable!(),
}

I shouldn't need to pattern-match against my_opt if I already know that it's a Some. Having to use unreachable!() creates code-smell - it's often a red flag that code is wrong and if it isn't wrong it should ideally be possible to restructure it to get rid of the unreachable!().

This is actually a problem with enums generally but without a way to fix the more general problem I think it should at least be fixed for Option.

I propose that either one of the following methods should be added to Option<T>

// Insert a value into the `Option`, setting it to `Some(val)` and returning a reference to `val`
fn insert(&mut self, val: T) -> &mut T

// Insert a value into the `Option`, setting it to `Some(val)` and returning a reference to `val`
// along with the previous value in the `Option` (if there was one)
fn insert(&mut self, val: T) -> (&mut T, Option<T>)
@Gankra
Copy link
Contributor

Gankra commented Oct 21, 2015

The example code is just a way more verbose version of:

*my_opt = Some(x);
let r = my_opt.as_ref().unwrap();

Still not as clean as

let r = my_opt.insert(x);

But certainly much less dire. I've felt this pain, but I'm not totally sold if it's worth it.

Note also that the code you demonstrate cannot be expressed by insert. Insert takes &mut self, and so any references derived from that input will leave the Option mutably borrowed. Even if you downgrade the &mut output to an &, the Option will still be mutably borrowed.

@canndrew
Copy link
Contributor Author

The example code is just a way more verbose version of...

D'oh, I didn't think of that. I feel the same way about unwrap as I do about unreachable! though.

Note also that the code you demonstrate cannot be expressed by insert. Insert takes &mut self, and so any references derived from that input will leave the Option mutably borrowed. Even if you downgrade the &mut output to an &, the Option will still be mutably borrowed.

I'm not sure what your point is. Mutably borrowing the Option is the intention.

@Gankra
Copy link
Contributor

Gankra commented Oct 21, 2015

Mutably borrowing the Option is the intention.

This is not what your example code does, so this wasn't clear.

@nikomatsakis
Copy link
Contributor

The more general fix to this problem, fwiw, would probably be a combination of the extended enums proposal (so that variants have types) along with a refinement type system that allows us to give more precise, flow-dependent types to mutable references. It would be cool, but certainly not on the short term horizon.

@steveklabnik
Copy link
Member

Given #29204 (comment), I'm going to give this a close in favor of an RFC. Thanks!

@hniksic
Copy link
Contributor

hniksic commented Oct 4, 2021

To help people who come here via google, don't be misled by this issue being closed and seemingly abandoned - Option::insert() did make it to Rust 1.53. Thanks to people who everyone who contributed!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants