rust icon indicating copy to clipboard operation
rust copied to clipboard

Tracking Issue for `Option::get_or_insert_default`

Open camsteffen opened this issue 3 years ago • 12 comments

Feature gate: #![feature(option_get_or_insert_default)]

This is a tracking issue for adding Option::get_or_insert_default.

Basically, it is a shorthand for option.get_or_insert_with(Default::default). It differs with unwrap_or_default since it does not consume the Option. This is useful, for example, when you have an Option as a struct field or inside a data structure like Vec<Option<T>>.

Public API

impl<T> Option<T> {
    pub fn get_or_insert_default(&mut self) -> &mut T where T: Default;
}

Steps / History

  • Original issue: #55042
  • [x] Implementation: #82849
  • [x] Renamed from get_or_default to get_or_insert_default: #82977
  • [ ] Final commenting period (FCP)
  • [ ] Stabilization PR

Unresolved Questions

  • None yet.

camsteffen avatar Mar 08 '21 14:03 camsteffen

It's not obvious to me at all from the name that this modifies the Option. It sounds like it'd be the same as unwrap_or_default. Something like get_or_insert_default would be more consistent with the other method names.

m-ou-se avatar Mar 09 '21 08:03 m-ou-se

Hmm I hadn't considered that.

camsteffen avatar Mar 09 '21 14:03 camsteffen

+1 on the name get_or_insert_default

I wanted to use this today, but it's still experimental. :laughing:

sffc avatar Dec 31 '21 01:12 sffc

+1 -- was looking for this exact method today

insou22 avatar Apr 07 '22 09:04 insou22

@rustbot ping libs

Let's see if this works now? Would be nice to have this FCP'ed.

cc @joshtriplett

djc avatar Jul 07 '22 20:07 djc

Error: Only Rust team members can ping teams.

Please file an issue on GitHub at triagebot if there's a problem with this bot, or reach out on #t-infra on Zulip.

rustbot avatar Jul 07 '22 20:07 rustbot

LGTM

@rfcbot merge

joshtriplett avatar Jul 08 '22 03:07 joshtriplett

Team member @joshtriplett has proposed to merge this. The next step is review by the rest of the tagged team members:

  • [x] @Amanieu
  • [ ] @BurntSushi
  • [x] @dtolnay
  • [x] @joshtriplett
  • [x] @m-ou-se
  • [ ] @yaahc

Concerns:

  • is this in the same category as resize_default (https://github.com/rust-lang/rust/issues/82901#issuecomment-1244996427)

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

rfcbot avatar Jul 08 '22 03:07 rfcbot

:bell: This is now entering its final comment period, as per the review above. :bell:

rfcbot avatar Sep 13 '22 06:09 rfcbot

@rfcbot concern is this in the same category as resize_default

Many years ago we deleted vec.resize_default(n) because it just wasn't worth having when vec.resize_with(n, T::default) is equally suitable.

  • https://github.com/rust-lang/rust/issues/41758
  • https://github.com/rust-lang/rust/pull/57656
  • https://github.com/rust-lang/rust/pull/77850

It seems like it came down to just not being worth dedicating a whole new method given how rarely resize_with is used in the first place. This is in contrast to option.unwrap_or_default() as shorthand for option.unwrap_or_else(T::default), which is the only existing precedent for T::default getting a dedicated convenience that I know of, and is justified by being used literally over 100× more than resize_with.

I suppose option.get_or_insert_default() is much closer to the resize_with end of this spectrum than the unwrap_or_default end, and option.get_or_insert_with(T::default) would be good enough.

dtolnay avatar Sep 13 '22 07:09 dtolnay

My own experience (which may or may not be representative) tells that in every single case I wanted option.get_or_insert_-like functionality I actually wanted option.get_or_insert_default(). So in my books it is much closer to unwrap_or_default than to resize_with. Just my 2 shekels.

imp avatar Oct 17 '22 10:10 imp

Be aware that whether or not you want the default value is not the only consideration here. You also require a situation in which T is completely inferrable. The combination of those 2 is less common in my experience (especially if I also take into account experience from similar situations in the Entry API). Extrapolating "every single case I wanted the default" to "therefore I would have found get_or_insert_default valuable if available" is not correct.

use std::collections::BTreeSet;
use std::iter;

fn main() {
    let mut junks = None;
    for (id, value) in iter::repeat(("junk", 99)).take(10) {
        if id == "junk" {
            junks.get_or_insert_with(BTreeSet::default).insert(value);
        }
    }
    println!("{:?}", junks);
}

With get_or_insert_default:

error[E0282]: type annotations needed for `Option<T>`
 --> src/main.rs:5:9
  |
5 |     let mut junks = None;
  |         ^^^^^^^^^
...
8 |             junks.get_or_insert_default().insert(value);
  |                                           ------ type must be known at this point

dtolnay avatar Oct 17 '22 14:10 dtolnay

Very good example. However, in my opinion it doesn't lower the value of get_or_insert_default. Just my opinion - I realize others can feel differently.

imp avatar Oct 17 '22 19:10 imp

Is there anything blocking stabilisation of this?

Rua avatar Nov 05 '22 08:11 Rua