Skip to content

Add give method to Option<T> #1416

Closed
Closed

Description

Currently, Option<T> has the method take, which is implemented as replace(&mut self, None). To complement this method, I propose adding a give as well:

pub fn give(&mut self, val: T) -> Option<T> {
    ::std::mem::replace(self, Some(val))
}

#[test]
fn it_works() {
    let mut opt = None;
    assert_eq!(opt.give(5), None);
    assert_eq!(opt, Some(5));
    assert_eq!(opt.give(6), Some(5));
    assert_eq!(opt, Some(6));
}

This follows the same standard that HashMap, BTreeMap, and other collections use. Inserts a value into the option and returns the old value.

I feel like this is a common enough pattern to warrant a method from the standard library.

Activity

  1. ghost changed the title [-]Add `insert` method to `Option<T>`[/-] [+]Add `give` method to `Option<T>`[/+] on Dec 18, 2015
  2. steveklabnik commented on Dec 18, 2015

    @steveklabnik
    Contributor

    I haven't had a need for this, but I do like the symmetry 👍

  3. Stebalien commented on Dec 20, 2015

    @Stebalien
    Contributor

    nit: personally, I'd call it offer.

  4. jonas-schievink commented on Dec 20, 2015

    @jonas-schievink
    Contributor

    Rust giveth and Rust taketh away

  5. withoutboats commented on Dec 20, 2015

    @withoutboats
    Contributor

    This seems to provide the same functionality as the methods requested in #1405 and #1278. While this proposal is symmetrical with take, I find the return value here really confusing (like difficult to reason about even with the code in front of me, which is not true of take) and don't know when it would be useful.

  6. oli-obk commented on Dec 21, 2015

    @oli-obk
    Contributor

    I find this very confusing. HashMap and BtreeMap return the value that previously was in the slot. This api returns the value you just tried to put in. I find both solutions to be more readable in the following ways:

    let x = val.take();
    *val = Some(y);
    if val.is_none() {
        *val = Some(x);
    } else {
        // process val
    }
  7. abonander commented on Dec 21, 2015

    @abonander

    I think put() makes more sense coupled with returning the previous value.

  8. withoutboats commented on Dec 21, 2015

    @withoutboats
    Contributor

    So put would be something like this, right?

    fn put(&mut self, val: T) -> &T {
        match *self {
            Some(ref item) => item,
            None => {
                self = Some(val);
                self.as_ref().unwrap()
            }
        }
    }
  9. abonander commented on Dec 21, 2015

    @abonander

    @withoutboats More like

    fn put(&mut self, val: T) -> Option<T> {
        mem::replace(self, Some(val))
    }

    For your suggestion, a more descriptive name like put_and_ref would probably be better.

  10. withoutboats commented on Dec 22, 2015

    @withoutboats
    Contributor

    That would replace the value even if the value is Some; I think most of these requests have wanted the function to only insert in the None case.

  11. burdges commented on Dec 22, 2015

    @burdges

    There is no reason to have a put that overwrites because you can always just overwrite it yourself by writing x = Some(y) or whatever.

    Yes, give is meant to act like insert does on collections. I imagine the reasoning behind give is : If I've an Option<T> that I want to put into a struct but the location is occupied, then I want to handle it some other way, like by merging the T. It's maybe helpful if T is a Box or something.

    I suppose a replace or swap function that always replaced the value and returns the contents sounds more intuitive, but maybe that's expensive if T is big. In principle, one could argue that if T were a Box, Arc<Mutex<S>>, etc. then T is small and replace is fast, and that big Ts should be handled another way.

  12. withoutboats commented on Dec 22, 2015

    @withoutboats
    Contributor

    The behavior @cybergeek94 suggested is the same as insert: it always replaces the value and returns the prior value.

  13. leoyvens commented on Dec 25, 2015

    @leoyvens

    I recently proposed something similar however I came to the conclusion that this would be a bad API because after being called it guarantees that the option will be Some, this encourages unwrapping and dosen't seem like a good use of Option after all.

  14. BlacklightShining commented on Dec 27, 2015

    @BlacklightShining

    A give() that returns the value you pass if self.is_some() already would confuse me. I agree with calling that offer() and making give() unconditionally replace self. I dunno whether this is good API, though; I've never used take() or wanted give(), myself.

  15. jaroslaw-weber commented on Jul 12, 2017

    @jaroslaw-weber

    unwraping option with result is nice but setting the value may be confusing when u dont know what is underneath the api. also writing Some(3) is not that inefficient

  16. Centril commented on Oct 7, 2018

    @Centril
    Contributor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-libs-api[DEPRECATED; DO NOT USE]

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions