Skip to content

Tracking issue for Cell::update #50186

Description

This issue tracks the cell_update feature.

The feature adds Cell::update, which allows one to more easily modify the inner value.
For example, instead of c.set(c.get() + 1) now you can just do c.update(|x| x + 1):

let c = Cell::new(5);
let new = c.update(|x| x + 1);

assert_eq!(new, 6);
assert_eq!(c.get(), 6);

Activity

  1. added
    T-libs-api[DEPRECATED; DO NOT USE]
    B-unstableBlocker: Implemented in the nightly compiler and unstable.
    on Apr 24, 2018
  2. oli-obk commented on Apr 24, 2018

    @oli-obk
    Contributor

    Not a blocking issue for merging this as an unstable feature, so I'm registering my concern here:

    The update function returning its new value feels very ++i-ish. Similar to += returning the result of the operation (which rust luckily does not!). I don't think we should be doing this. Options I see:

    • return () (that was the suggestion in the PR)
    • make the closure argument a &mut T, and allow the closure to return any value.
      • if users want the "return new/old value" behaviour, they can now encode it themselves via |x| {*x += 1; *y }

    Maybe there are other options?

    Data point: the volatile crate's update method returns () (https://github.com/embed-rs/volatile/blob/master/src/lib.rs#L134)

  3. SimonSapin commented on May 14, 2018

    @SimonSapin
    Contributor

    The T: Default flavor feels kinda awkward but I don’t know how to put that in more concrete terms, sorry :/

    It looks like there is a number of slightly different possible APIs for this. I don’t have a strong opinion on which is (or are) preferable.

  4. added a commit that references this issue on Jul 23, 2018
  5. CodeSandwich commented on Aug 6, 2018

    @CodeSandwich
    Contributor

    Taking &mut in this method would be awesome, I would love to use it.

    Unfortunately it seems that it would have to be unsafe, because AFAIK there is no way in Rust to restrict usage like this:

    let c = Cell::new(vec![123]);
    c.update(|vec| {
        let x = &mut vec[0];            // x references 123
        c.update(|vec| vec.clear());    // x references uninitialised memory
        *x = 456;                       // BOOM! undefined behavior
    })
    

    I hope, I'm wrong.

  6. SimonSapin commented on Aug 7, 2018

    @SimonSapin
    Contributor

    @CodeSandwich it is a fundamental restriction of Cell<T> that a reference &T or &mut T (or anything else inside of T) must not be given to the value inside the cell. It’s what makes it sound. (This is the difference with RefCell.)

    We could make an API that takes a closure that takes &mut T, but that reference would not be to the inside of the cell. It would be to value that has been copied (with T: Copy) or moved (and temporarily replaced with some other value, with T: Default) onto the stack and will be copied/moved back when the closure returns. So code like your example would be arguably buggy but still sound: the inner update() would operate on a temporary value that would be overwritten at the end of the outer one.

  7. CodeSandwich commented on Aug 13, 2018

    @CodeSandwich
    Contributor

    I think, that a modifier method might be safe if we just forbid usage of reference to Cell's self inside. Rust does not have mechanism for forbidding usage of a SPECIFIC reference, but it does have mechanism for forbidding usage of ALL references: 'static closures.

    I've created a simple implementation of such method and I couldn't find any hole in it. It's a limited solution, but it's enough for many use cases including simple number and collections modifications.

  8. SimonSapin commented on Aug 13, 2018

    @SimonSapin
    Contributor

    A 'static closure could still reach the Cell, for example by owning a Rc.

  9. CodeSandwich commented on Aug 13, 2018

    @CodeSandwich
    Contributor

    That's absolutely right :(

  10. added
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    on Oct 2, 2018
  11. earthengine commented on Oct 3, 2018

    @earthengine

    It seems like, the semantic are a bit different between Default and Copy: the later is more light weighted, as it does not have to fill the hole behind with some temporary rubbish.

    What shall we name those variants? update_move for the Default case?

    Also there is another variation: update_unsafe which will be unsafe and does not require a trait bound: it only moves the value and leave uninitialized value behind, before the method returns. This will make any nested calls UB and so have to be marked as unsafe.

    pub unsafe fn update_unsafe<F>(&self, f: F) -> T where F: FnOnce(T) -> T;
  12. SimonSapin commented on Oct 3, 2018

    @SimonSapin
    Contributor

    if you’re gonna use unsafe anyway you can use .get() and manipulate the raw pointer. I don’t think we should facilitate it more than that.

  13. 74 remaining items

  14. tgross35 commented on Apr 2, 2025

    @tgross35
    Member

    I can't update the top post because it was created by a deleted user, but the API will be:

    impl<T: Copy> Cell<T> {
        pub fn update(&self, f: impl FnOnce(T) -> T);
    }
  15. added a commit that references this issue on Apr 3, 2025
  16. added a commit that references this issue on Apr 3, 2025
  17. added a commit that references this issue on Apr 3, 2025
  18. added a commit that references this issue on Apr 3, 2025
  19. tgross35 commented on Apr 7, 2025

    @tgross35
    Member

    Crosslinking, FCP for the changed API is currently ongoing at #134446 (comment)

  20. added 2 commits that reference this issue on Apr 8, 2025
  21. added a commit that references this issue on Apr 24, 2025
  22. added a commit that references this issue on Apr 24, 2025
  23. added 2 commits that reference this issue on May 9, 2025
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

    B-unstableBlocker: Implemented in the nightly compiler and unstable.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCI-libs-radarLibs issues that are tracked on the team's radar.Libs-SmallLibs issues that are considered "small" or self-containedT-libs-api[DEPRECATED; DO NOT USE]disposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.finished-final-comment-periodThe final comment period is finished for this PR / Issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions